From xen-devel-bounces@lists.xensource.com Thu Nov 17 15:52:58 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2011 15:52:58 +0000
Received: from lists.colo.xensource.com ([70.42.241.110] helo=lists.xensource.com)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RR4Gn-00027u-Bo
	for archives@lists.xen.org; Thu, 17 Nov 2011 15:52:58 +0000
Received: from localhost ([127.0.0.1] helo=lists.colo.xensource.com)
	by lists.xensource.com with esmtp (Exim 4.43)
	id 1RR4GV-00071o-5A; Thu, 17 Nov 2011 07:52:39 -0800
Received: from mail182.messagelabs.com ([85.158.139.83])
	by lists.xensource.com with esmtp (Exim 4.43) id 1RR3jd-0005hy-D7
	for xen-devel@lists.xensource.com; Thu, 17 Nov 2011 07:18:44 -0800
X-Env-Sender: anthony.perard@citrix.com
X-Msg-Ref: server-12.tower-182.messagelabs.com!1321543105!3550834!3
X-Originating-IP: [66.165.176.89]
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 29687 invoked from network); 17 Nov 2011 15:18:36 -0000
Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89)
	by server-12.tower-182.messagelabs.com with RC4-SHA encrypted SMTP;
	17 Nov 2011 15:18:36 -0000
X-IronPort-AV: E=Sophos;i="4.69,527,1315195200"; d="scan'208";a="19190249"
Received: from ftlpmailmx02.citrite.net ([10.13.107.66])
	by FTLPIPO01.CITRIX.COM with ESMTP/TLS/RC4-MD5;
	17 Nov 2011 10:18:36 -0500
Received: from smtp01.ad.xensource.com (10.219.128.104) by
	smtprelay.citrix.com (10.13.107.66) with Microsoft SMTP Server id
	8.3.137.0; Thu, 17 Nov 2011 10:18:36 -0500
Received: from perard.uk.xensource.com (dhcp-3-28.uk.xensource.com
	[10.80.3.28] (may be forged))	by smtp01.ad.xensource.com
	(8.13.1/8.13.1) with
	ESMTP id pAHFHWaS026286;	Thu, 17 Nov 2011 07:18:34 -0800
From: Anthony PERARD <anthony.perard@citrix.com>
To: QEMU-devel <qemu-devel@nongnu.org>,
	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Date: Thu, 17 Nov 2011 15:17:11 +0000
Message-ID: <1321543033-22090-9-git-send-email-anthony.perard@citrix.com>
X-Mailer: git-send-email 1.7.2.5
In-Reply-To: <1321543033-22090-1-git-send-email-anthony.perard@citrix.com>
References: <1321543033-22090-1-git-send-email-anthony.perard@citrix.com>
MIME-Version: 1.0
Content-Type: text/plain
Cc: Anthony PERARD <anthony.perard@citrix.com>, Guy Zana <guy@neocleus.com>,
	Xen Devel <xen-devel@lists.xensource.com>,
	Allen Kay <allen.m.kay@intel.com>
Subject: [Xen-devel] [PATCH V4 08/10] Introduce Xen PCI Passthrough,
	PCI config space helpers (2/3)
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.5
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com

From: Allen Kay <allen.m.kay@intel.com>

A more complete history can be found here:
git://xenbits.xensource.com/qemu-xen-unstable.git

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Guy Zana <guy@neocleus.com>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
---
 hw/xen_pci_passthrough.c             |   15 +
 hw/xen_pci_passthrough_config_init.c | 2131 ++++++++++++++++++++++++++++++++++
 2 files changed, 2146 insertions(+), 0 deletions(-)

diff --git a/hw/xen_pci_passthrough.c b/hw/xen_pci_passthrough.c
index 998470b..c816ed5 100644
--- a/hw/xen_pci_passthrough.c
+++ b/hw/xen_pci_passthrough.c
@@ -360,6 +360,11 @@ out:
             PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
         }
     }
+
+    if (s->pm_state != NULL && s->pm_state->flags & PT_FLAG_TRANSITING) {
+        qemu_mod_timer(s->pm_state->pm_timer,
+                       qemu_get_clock_ms(rt_clock) + s->pm_state->pm_delay);
+    }
 }
 
 /* ioport/iomem space*/
@@ -706,6 +711,13 @@ static int pt_initfn(PCIDevice *pcidev)
     /* Handle real device's MMIO/PIO BARs */
     pt_register_regions(s);
 
+    /* reinitialize each config register to be emulated */
+    if (pt_config_init(s)) {
+        PT_ERR(pcidev, "PCI Config space initialisation failed.\n");
+        host_pci_device_put(s->real_device);
+        return -1;
+    }
+
     /* Bind interrupt */
     if (!s->dev.config[PCI_INTERRUPT_PIN]) {
         PT_LOG(pcidev, "no pin interrupt\n");
@@ -798,6 +810,9 @@ static int pt_unregister_device(PCIDevice *pcidev)
         }
     }
 
+    /* delete all emulated config registers */
+    pt_config_delete(s);
+
     /* unregister real device's MMIO/PIO BARs */
     pt_unregister_regions(s);
 
diff --git a/hw/xen_pci_passthrough_config_init.c b/hw/xen_pci_passthrough_config_init.c
index 1e9de64..ae64544 100644
--- a/hw/xen_pci_passthrough_config_init.c
+++ b/hw/xen_pci_passthrough_config_init.c
@@ -1,11 +1,2142 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Alex Novik <alex@neocleus.com>
+ * Allen Kay <allen.m.kay@intel.com>
+ * Guy Zana <guy@neocleus.com>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ */
+
+#include "qemu-timer.h"
+#include "xen_backend.h"
 #include "xen_pci_passthrough.h"
 
+#define PT_MERGE_VALUE(value, data, val_mask) \
+    (((value) & (val_mask)) | ((data) & ~(val_mask)))
+
+#define PT_INVALID_REG          0xFFFFFFFF      /* invalid register value */
+
+/* prototype */
+
+static int pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                           uint32_t real_offset, uint32_t *data);
+static int pt_init_pci_config(XenPCIPassthroughState *s);
+
+
+/* helper */
+
+/* A return value of 1 means the capability should NOT be exposed to guest. */
+static int pt_hide_dev_cap(const HostPCIDevice *d, uint8_t grp_id)
+{
+    switch (grp_id) {
+    case PCI_CAP_ID_EXP:
+        /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0. We should not try to expose it to guest.
+         *
+         * The datasheet is available at
+         * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
+         *
+         * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
+         * PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0, so the Capability Version is 0 and
+         * pt_pcie_size_init() would fail.
+         */
+        if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
+            d->device_id == PCI_DEVICE_ID_INTEL_82599_VF) {
+            return 1;
+        }
+        break;
+    }
+    return 0;
+}
+
+/*   find emulate register group entry */
 XenPTRegGroup *pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
 {
+    XenPTRegGroup *entry = NULL;
+
+    /* find register group entry */
+    QLIST_FOREACH(entry, &s->reg_grp_tbl, entries) {
+        /* check address */
+        if ((entry->base_offset <= address)
+            && ((entry->base_offset + entry->size) > address)) {
+            return entry;
+        }
+    }
+
+    /* group entry not found */
     return NULL;
 }
 
+/* find emulate register entry */
 XenPTReg *pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
 {
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    uint32_t real_offset = 0;
+
+    /* find register entry */
+    QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
+        reg = reg_entry->reg;
+        real_offset = reg_grp->base_offset + reg->offset;
+        /* check address */
+        if ((real_offset <= address)
+            && ((real_offset + reg->size) > address)) {
+            return reg_entry;
+        }
+    }
+
     return NULL;
 }
+
+/* parse BAR */
+static PTBarFlag pt_bar_reg_parse(XenPCIPassthroughState *s, XenPTRegInfo *reg)
+{
+    PCIDevice *d = &s->dev;
+    XenPTRegion *region = NULL;
+    PCIIORegion *r;
+    int index = 0;
+
+    /* check 64bit BAR */
+    index = pt_bar_offset_to_index(reg->offset);
+    if ((0 < index) && (index < PCI_ROM_SLOT)) {
+        int flags = s->real_device->io_regions[index - 1].flags;
+
+        if ((flags & IORESOURCE_MEM) && (flags & IORESOURCE_MEM_64)) {
+            region = &s->bases[index - 1];
+            if (region->bar_flag != PT_BAR_FLAG_UPPER) {
+                return PT_BAR_FLAG_UPPER;
+            }
+        }
+    }
+
+    /* check unused BAR */
+    r = &d->io_regions[index];
+    if (r->size == 0) {
+        return PT_BAR_FLAG_UNUSED;
+    }
+
+    /* for ExpROM BAR */
+    if (index == PCI_ROM_SLOT) {
+        return PT_BAR_FLAG_MEM;
+    }
+
+    /* check BAR I/O indicator */
+    if (s->real_device->io_regions[index].flags & IORESOURCE_IO) {
+        return PT_BAR_FLAG_IO;
+    } else {
+        return PT_BAR_FLAG_MEM;
+    }
+}
+
+
+/****************
+ * general register functions
+ */
+
+/* register initialization function */
+
+static int pt_common_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = reg->init_val;
+    return 0;
+}
+
+/* Read register functions */
+
+static int pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint8_t *value, uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t valid_emu_mask = 0;
+
+    /* emulate byte register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+
+    /* emulate word register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+
+    /* emulate long register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+   return 0;
+}
+
+/* Write register functions */
+
+static int pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint8_t *value, uint8_t dev_value,
+                             uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t writable_mask = 0;
+    uint8_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+static int pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint16_t *value, uint16_t dev_value,
+                             uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+static int pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint32_t *value, uint32_t dev_value,
+                             uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* common restore register fonctions */
+static int pt_byte_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint32_t real_offset, uint8_t dev_value,
+                               uint8_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_byte(d->config + real_offset);
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, reg->emu_mask);
+
+    return 0;
+}
+static int pt_word_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint32_t real_offset, uint16_t dev_value,
+                               uint16_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_word(d->config + real_offset);
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, reg->emu_mask);
+
+    return 0;
+}
+
+
+/* XenPTRegInfo declaration
+ * - only for emulated register (either a part or whole bit).
+ * - for passthrough register that need special behavior (like interacting with
+ *   other component), set emu_mask to all 0 and specify r/w func properly.
+ * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
+ */
+
+/********************
+ * Header Type0
+ */
+
+static int pt_vendor_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = s->real_device->vendor_id;
+    return 0;
+}
+static int pt_device_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = s->real_device->device_id;
+    return 0;
+}
+static int pt_status_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    uint32_t reg_field = 0;
+
+    /* find Header register group */
+    reg_grp_entry = pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
+    if (reg_grp_entry) {
+        /* find Capabilities Pointer register */
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
+        if (reg_entry) {
+            /* check Capabilities Pointer register */
+            if (reg_entry->data) {
+                reg_field |= PCI_STATUS_CAP_LIST;
+            } else {
+                reg_field &= ~PCI_STATUS_CAP_LIST;
+            }
+        } else {
+            xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
+                                     " for Capabilities Pointer register."
+                                     " (%s)\n", __func__);
+            return -1;
+        }
+    } else {
+        xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
+                                 " for Header. (%s)\n", __func__);
+        return -1;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int pt_header_type_reg_init(XenPCIPassthroughState *s,
+                                   XenPTRegInfo *reg, uint32_t real_offset,
+                                   uint32_t *data)
+{
+    /* read PCI_HEADER_TYPE */
+    *data = reg->init_val | 0x80;
+    return 0;
+}
+
+/* initialize Interrupt Pin register */
+static int pt_irqpin_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = pci_read_intx(s);
+    return 0;
+}
+
+/* Command register */
+static int pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                           uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* emulate word register */
+    valid_emu_mask = emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint16_t *value, uint16_t dev_value,
+                            uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t wr_value = *value;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* modify emulate register */
+    writable_mask = ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+
+    if (*value & PCI_COMMAND_INTX_DISABLE) {
+        throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+    } else {
+        if (s->machine_irq) {
+            throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+        }
+    }
+
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* mapping BAR */
+    pt_bar_mapping(s, wr_value & PCI_COMMAND_IO,
+                   wr_value & PCI_COMMAND_MEMORY);
+
+    return 0;
+}
+static int pt_cmd_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint32_t real_offset, uint16_t dev_value,
+                              uint16_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+    uint16_t restorable_mask = 0;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_word(d->config + real_offset);
+
+    /* create value for restoring to I/O device register
+     * but do not include Fast Back-to-Back Enable bit.
+     */
+    restorable_mask = reg->emu_mask & ~PCI_COMMAND_FAST_BACK;
+    *value = PT_MERGE_VALUE(*value, dev_value, restorable_mask);
+
+    if (!s->machine_irq) {
+        *value |= PCI_COMMAND_INTX_DISABLE;
+    } else {
+        *value &= ~PCI_COMMAND_INTX_DISABLE;
+    }
+
+    return 0;
+}
+
+/* BAR */
+#define PT_BAR_MEM_RO_MASK      0x0000000F      /* BAR ReadOnly mask(Memory) */
+#define PT_BAR_MEM_EMU_MASK     0xFFFFFFF0      /* BAR emul mask(Memory) */
+#define PT_BAR_IO_RO_MASK       0x00000003      /* BAR ReadOnly mask(I/O) */
+#define PT_BAR_IO_EMU_MASK      0xFFFFFFFC      /* BAR emul mask(I/O) */
+
+static inline uint32_t base_address_with_flags(HostPCIIORegion *hr)
+{
+    if ((hr->flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+        return hr->base_addr | (hr->flags & ~PCI_BASE_ADDRESS_IO_MASK);
+    } else {
+        return hr->base_addr | (hr->flags & ~PCI_BASE_ADDRESS_MEM_MASK);
+    }
+}
+
+static int pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                           uint32_t real_offset, uint32_t *data)
+{
+    uint32_t reg_field = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* set initial guest physical base address to -1 */
+    s->bases[index].e_physbase = -1;
+
+    /* set BAR flag */
+    s->bases[index].bar_flag = pt_bar_reg_parse(s, reg);
+    if (s->bases[index].bar_flag == PT_BAR_FLAG_UNUSED) {
+        reg_field = PT_INVALID_REG;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                           uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* use fixed-up value from kernel sysfs */
+    *value = base_address_with_flags(&s->real_device->io_regions[index]);
+
+    /* set emulate mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        break;
+    default:
+        break;
+    }
+
+    /* emulate BAR */
+    valid_emu_mask = bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+   return 0;
+}
+static int pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint32_t *value, uint32_t dev_value,
+                            uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = &s->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+    uint32_t new_addr, last_addr;
+    uint32_t prev_offset;
+    uint32_t r_size = 0;
+    int index = 0;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    r = &d->io_regions[index];
+    base = &s->bases[index];
+    r_size = pt_get_emul_size(base->bar_flag, r->size);
+
+    /* set emulate mask and read-only mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        bar_ro_mask = PT_BAR_MEM_RO_MASK | (r_size - 1);
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        bar_ro_mask = PT_BAR_IO_RO_MASK | (r_size - 1);
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        bar_ro_mask = 0;    /* all upper 32bit are R/W */
+        break;
+    default:
+        break;
+    }
+
+    /* modify emulate register */
+    writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* check whether we need to update the virtual region address or not */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        /* nothing to do */
+        break;
+    case PT_BAR_FLAG_IO:
+        new_addr = cfg_entry->data;
+        last_addr = new_addr + r_size - 1;
+        /* check invalid address */
+        if (last_addr <= new_addr || !new_addr || last_addr >= UINT16_MAX) {
+            /* check 64K range */
+            if ((last_addr >= UINT16_MAX) &&
+                (cfg_entry->data != (PT_BAR_ALLF & ~bar_ro_mask))) {
+                PT_WARN(d, "Guest attempt to set Base Address "
+                       "over the 64KB. (offset: 0x%02x,"
+                       " addr: 0x%08x, size: 0x%08x)\n",
+                       reg->offset, new_addr, r_size);
+            }
+            /* just remove mapping */
+            r->addr = PCI_BAR_UNMAPPED;
+            goto exit;
+        }
+        break;
+    case PT_BAR_FLAG_UPPER:
+        if (cfg_entry->data) {
+            if (cfg_entry->data != (PT_BAR_ALLF & ~bar_ro_mask)) {
+                PT_WARN(d, "Guest attempt to set high MMIO Base Address. "
+                        "Ignore mapping. "
+                        "(offset: 0x%02x, high address: 0x%08x)\n",
+                        reg->offset, cfg_entry->data);
+            }
+            /* clear lower address */
+            d->io_regions[index-1].addr = -1;
+        } else {
+            /* find lower 32bit BAR */
+            prev_offset = (reg->offset - 4);
+            reg_grp_entry = pt_find_reg_grp(s, prev_offset);
+            if (reg_grp_entry) {
+                reg_entry = pt_find_reg(reg_grp_entry, prev_offset);
+                if (reg_entry) {
+                    /* restore lower address */
+                    d->io_regions[index-1].addr = reg_entry->data;
+                } else {
+                    return -1;
+                }
+            } else {
+                return -1;
+            }
+        }
+
+        /* never mapping the 'empty' upper region,
+         * because we'll do it enough for the lower region.
+         */
+        r->addr = -1;
+        goto exit;
+    default:
+        break;
+    }
+
+    /* update the corresponding virtual region address */
+    /*
+     * When guest code tries to get block size of mmio, it will write all "1"s
+     * into pci bar register. In this case, cfg_entry->data == writable_mask.
+     * Especially for devices with large mmio, the value of writable_mask
+     * is likely to be a guest physical address that has been mapped to ram
+     * rather than mmio. Remapping this value to mmio should be prevented.
+     */
+
+    if (cfg_entry->data != writable_mask) {
+        r->addr = cfg_entry->data;
+    }
+
+exit:
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* After BAR reg update, we need to remap BAR */
+    reg_grp_entry = pt_find_reg_grp(s, PCI_COMMAND);
+    if (reg_grp_entry) {
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_COMMAND);
+        if (reg_entry) {
+            pt_bar_mapping_one(s, index, reg_entry->data & PCI_COMMAND_IO,
+                               reg_entry->data & PCI_COMMAND_MEMORY);
+        }
+    }
+
+    return 0;
+}
+static int pt_bar_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint32_t real_offset, uint32_t dev_value,
+                              uint32_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t bar_emu_mask = 0;
+    int index = 0;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* use value from kernel sysfs */
+    if (s->bases[index].bar_flag == PT_BAR_FLAG_UPPER) {
+        *value = s->real_device->io_regions[index - 1].base_addr >> 32;
+    } else {
+        *value = base_address_with_flags(&s->real_device->io_regions[index]);
+    }
+
+    /* set emulate mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        break;
+    default:
+        break;
+    }
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, bar_emu_mask);
+
+    return 0;
+}
+
+/* write Exp ROM BAR */
+static int pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
+                                    XenPTReg *cfg_entry, uint32_t *value,
+                                    uint32_t dev_value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = (PCIDevice *)&s->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    pcibus_t r_size = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+
+    r = &d->io_regions[PCI_ROM_SLOT];
+    r_size = r->size;
+    base = &s->bases[PCI_ROM_SLOT];
+    /* align memory type resource size */
+    pt_get_emul_size(base->bar_flag, r_size);
+
+    /* set emulate mask and read-only mask */
+    bar_emu_mask = reg->emu_mask;
+    bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
+
+    /* modify emulate register */
+    writable_mask = ~bar_ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* update the corresponding virtual region address */
+    /*
+     * When guest code tries to get block size of mmio, it will write all "1"s
+     * into pci bar register. In this case, cfg_entry->data == writable_mask.
+     * Especially for devices with large mmio, the value of writable_mask
+     * is likely to be a guest physical address that has been mapped to ram
+     * rather than mmio. Remapping this value to mmio should be prevented.
+     */
+
+    if (cfg_entry->data != writable_mask) {
+        r->addr = cfg_entry->data;
+    }
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* After BAR reg update, we need to remap BAR*/
+    reg_grp_entry = pt_find_reg_grp(s, PCI_COMMAND);
+    if (reg_grp_entry) {
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_COMMAND);
+        if (reg_entry) {
+            pt_bar_mapping_one(s, PCI_ROM_SLOT,
+                               reg_entry->data & PCI_COMMAND_IO,
+                               reg_entry->data & PCI_COMMAND_MEMORY);
+        }
+    }
+
+    return 0;
+}
+/* restore ROM BAR */
+static int pt_exp_rom_bar_reg_restore(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry,
+                                      uint32_t real_offset,
+                                      uint32_t dev_value, uint32_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t v;
+
+    if (host_pci_get_long(s->real_device, PCI_ROM_ADDRESS, &v)) {
+        return -1;
+    }
+    /* use value from kernel sysfs */
+    *value = PT_MERGE_VALUE(v, dev_value, reg->emu_mask);
+    return 0;
+}
+
+/* Header Type0 reg static infomation table */
+static XenPTRegInfo pt_emu_reg_header0_tbl[] = {
+    /* Vendor ID reg */
+    {
+        .offset     = PCI_VENDOR_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_vendor_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Device ID reg */
+    {
+        .offset     = PCI_DEVICE_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_device_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Command reg */
+    {
+        .offset     = PCI_COMMAND,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xF880,
+        .emu_mask   = 0x0740,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_cmd_reg_read,
+        .u.w.write  = pt_cmd_reg_write,
+        .u.w.restore  = pt_cmd_reg_restore,
+    },
+    /* Capabilities Pointer reg */
+    {
+        .offset     = PCI_CAPABILITY_LIST,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Status reg */
+    /* use emulated Cap Ptr value to initialize,
+     * so need to be declared after Cap Ptr reg
+     */
+    {
+        .offset     = PCI_STATUS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x06FF,
+        .emu_mask   = 0x0010,
+        .init       = pt_status_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Cache Line Size reg */
+    {
+        .offset     = PCI_CACHE_LINE_SIZE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = pt_byte_reg_restore,
+    },
+    /* Latency Timer reg */
+    {
+        .offset     = PCI_LATENCY_TIMER,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = pt_byte_reg_restore,
+    },
+    /* Header Type reg */
+    {
+        .offset     = PCI_HEADER_TYPE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0x00,
+        .init       = pt_header_type_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Interrupt Line reg */
+    {
+        .offset     = PCI_INTERRUPT_LINE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Interrupt Pin reg */
+    {
+        .offset     = PCI_INTERRUPT_PIN,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_irqpin_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* BAR 0 reg */
+    /* mask of BAR need to be decided later, depends on IO/MEM type */
+    {
+        .offset     = PCI_BASE_ADDRESS_0,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 1 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_1,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 2 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_2,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 3 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_3,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 4 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_4,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 5 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_5,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* Expansion ROM BAR reg */
+    {
+        .offset     = PCI_ROM_ADDRESS,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x000007FE,
+        .emu_mask   = 0xFFFFF800,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_exp_rom_bar_reg_write,
+        .u.dw.restore = pt_exp_rom_bar_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Vital Product Data Capability
+ */
+
+/* Vital Product Data Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_vpd_tbl[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/**************************************
+ * Vendor Specific Capability
+ */
+
+/* Vendor Specific Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_vendor_tbl[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*****************************
+ * PCI Express Capability
+ */
+
+/* initialize Link Control register */
+static int pt_linkctrl_reg_init(XenPCIPassthroughState *s,
+                                XenPTRegInfo *reg, uint32_t real_offset,
+                                uint32_t *data)
+{
+    uint8_t cap_ver = 0;
+    uint8_t dev_type = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+    dev_type = (pci_get_byte(s->dev.config + real_offset - reg->offset
+                             + PCI_EXP_FLAGS)
+                & PCI_EXP_FLAGS_TYPE) >> 4;
+
+    /* no need to initialize in case of Root Complex Integrated Endpoint
+     * with cap_ver 1.x
+     */
+    if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
+        *data = PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Device Control 2 register */
+static int pt_devctrl2_reg_init(XenPCIPassthroughState *s,
+                                XenPTRegInfo *reg, uint32_t real_offset,
+                                uint32_t *data)
+{
+    uint8_t cap_ver = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        *data = PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Link Control 2 register */
+static int pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
+                                 XenPTRegInfo *reg, uint32_t real_offset,
+                                 uint32_t *data)
+{
+    uint32_t reg_field = 0;
+    uint8_t cap_ver = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        reg_field = PT_INVALID_REG;
+    } else {
+        /* set Supported Link Speed */
+        uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset
+                                      + PCI_EXP_LNKCAP);
+        reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+
+/* PCI Express Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_pcie_tbl[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Device Capabilities reg */
+    {
+        .offset     = PCI_EXP_DEVCAP,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x1FFCFFFF,
+        .emu_mask   = 0x10000000,
+        .init       = pt_common_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_long_reg_write,
+        .u.dw.restore = NULL,
+    },
+    /* Device Control reg */
+    {
+        .offset     = PCI_EXP_DEVCTL,
+        .size       = 2,
+        .init_val   = 0x2810,
+        .ro_mask    = 0x8400,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Link Control reg */
+    {
+        .offset     = PCI_EXP_LNKCTL,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFC34,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_linkctrl_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Device Control 2 reg */
+    {
+        .offset     = 0x28,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFE0,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_devctrl2_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Link Control 2 reg */
+    {
+        .offset     = 0x30,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xE040,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_linkctrl2_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Power Management Capability
+ */
+
+/* initialize Power Management Capabilities register */
+static int pt_pmc_reg_init(XenPCIPassthroughState *s,
+                           XenPTRegInfo *reg, uint32_t real_offset,
+                           uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+
+    if (s->power_mgmt) {
+        /* set Power Management Capabilities register */
+        s->pm_state->pmc_field = pci_get_word(d->config + real_offset);
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize PCI Power Management Control/Status register */
+static int pt_pmcsr_reg_init(XenPCIPassthroughState *s,
+                             XenPTRegInfo *reg, uint32_t real_offset,
+                             uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t cap_ver  = 0;
+    uint16_t v = 0;
+
+    if (!s->power_mgmt) {
+        *data = reg->init_val;
+        return 0;
+    }
+
+    /* check PCI Power Management support version */
+    cap_ver = s->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
+
+    if (cap_ver > 2) {
+        /* set No Soft Reset */
+        s->pm_state->no_soft_reset =
+            pci_get_byte(d->config + real_offset) & PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    host_pci_get_word(s->real_device, real_offset, &v);
+    /* wake up real physical device */
+    switch (v & PCI_PM_CTRL_STATE_MASK) {
+    case 0:
+        break;
+    case 1:
+        PT_LOG(d, "Power state transition D1 -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        break;
+    case 2:
+        PT_LOG(d, "Power state transition D2 -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        usleep(200);
+        break;
+    case 3:
+        PT_LOG(d, "Power state transition D3hot -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        usleep(10 * 1000);
+        if (pt_init_pci_config(s)) {
+            return -1;
+        }
+        break;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* read Power Management Control/Status register */
+static int pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = reg->emu_mask;
+
+    if (!s->power_mgmt) {
+        valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    valid_emu_mask = valid_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+/* reset Interrupt and I/O resource  */
+static void pt_reset_interrupt_and_io_mapping(XenPCIPassthroughState *s)
+{
+    PCIDevice *d = &s->dev;
+    PCIIORegion *r;
+    int i = 0;
+    uint8_t e_device = 0;
+    uint8_t e_intx = 0;
+
+    /* unbind INTx */
+    e_device = PCI_SLOT(s->dev.devfn);
+    e_intx = pci_intx(s);
+
+    if (s->machine_irq) {
+        if (xc_domain_unbind_pt_irq(xen_xc, xen_domid, s->machine_irq,
+                                    PT_IRQ_TYPE_PCI, 0, e_device, e_intx, 0)) {
+            PT_ERR(d, "Unbinding of interrupt failed!\n");
+        }
+    }
+
+    /* clear all virtual region address */
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        r->addr = -1;
+    }
+
+    /* unmapping BAR */
+    pt_bar_mapping(s, 0, 0);
+}
+/* check power state transition */
+static int check_power_state(XenPCIPassthroughState *s)
+{
+    XenPTPM *pm_state = s->pm_state;
+    PCIDevice *d = &s->dev;
+    uint16_t read_val = 0;
+    uint16_t cur_state = 0;
+
+    /* get current power state */
+    if (host_pci_get_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                          &read_val)) {
+        return -1;
+    }
+    cur_state = read_val & PCI_PM_CTRL_STATE_MASK;
+
+    if (pm_state->req_state != cur_state) {
+        PT_ERR(d, "Failed to change power state. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, cur_state);
+        return -1;
+    }
+    return 0;
+}
+/* write Power Management Control/Status register */
+static void pt_from_d3hot_to_d0_with_reset(void *opaque)
+{
+    XenPCIPassthroughState *s = opaque;
+    XenPTPM *pm_state = s->pm_state;
+    int ret = 0;
+
+    /* check power state */
+    ret = check_power_state(s);
+
+    if (ret < 0) {
+        goto out;
+    }
+
+    pt_init_pci_config(s);
+
+out:
+    /* power state transition flags off */
+    pm_state->flags &= ~PT_FLAG_TRANSITING;
+
+    qemu_free_timer(pm_state->pm_timer);
+    pm_state->pm_timer = NULL;
+}
+static void pt_default_power_transition(void *opaque)
+{
+    XenPCIPassthroughState *ptdev = opaque;
+    XenPTPM *pm_state = ptdev->pm_state;
+
+    /* check power state */
+    check_power_state(ptdev);
+
+    /* power state transition flags off */
+    pm_state->flags &= ~PT_FLAG_TRANSITING;
+
+    qemu_free_timer(pm_state->pm_timer);
+    pm_state->pm_timer = NULL;
+}
+static int pt_pmcsr_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint16_t *value, uint16_t dev_value,
+                              uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+    uint16_t emu_mask = reg->emu_mask;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    XenPTPM *pm_state = s->pm_state;
+
+    if (!s->power_mgmt) {
+        emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    /* modify emulate register */
+    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    if (!s->power_mgmt) {
+        return 0;
+    }
+
+    /* set I/O device power state */
+    pm_state->cur_state = dev_value & PCI_PM_CTRL_STATE_MASK;
+
+    /* set Guest requested PowerState */
+    pm_state->req_state = *value & PCI_PM_CTRL_STATE_MASK;
+
+    /* check power state transition or not */
+    if (pm_state->cur_state == pm_state->req_state) {
+        /* not power state transition */
+        return 0;
+    }
+
+    /* check enable power state transition */
+    if ((pm_state->req_state != 0) &&
+        (pm_state->cur_state > pm_state->req_state)) {
+        PT_ERR(d, "Invalid power transition. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, pm_state->cur_state);
+
+        return 0;
+    }
+
+    /* check if this device supports the requested power state */
+    if (((pm_state->req_state == 1) && !(pm_state->pmc_field & PCI_PM_CAP_D1))
+        || ((pm_state->req_state == 2) &&
+            !(pm_state->pmc_field & PCI_PM_CAP_D2))) {
+        PT_ERR(d, "Invalid power transition. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, pm_state->cur_state);
+
+        return 0;
+    }
+
+    /* in case of transition related to D3hot, it's necessary to wait 10 ms.
+     * But because writing to register will be performed later on actually,
+     * don't start QEMUTimer right now, just alloc and init QEMUTimer here.
+     */
+    if ((pm_state->cur_state == 3) || (pm_state->req_state == 3)) {
+        if (pm_state->req_state == 0) {
+            /* alloc and init QEMUTimer */
+            if (!pm_state->no_soft_reset) {
+                pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                    pt_from_d3hot_to_d0_with_reset, s);
+
+                /* reset Interrupt and I/O resource mapping */
+                pt_reset_interrupt_and_io_mapping(s);
+            } else {
+                pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                                        pt_default_power_transition, s);
+            }
+        } else {
+            /* alloc and init QEMUTimer */
+            pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                pt_default_power_transition, s);
+        }
+
+        /* set power state transition delay */
+        pm_state->pm_delay = 10;
+
+        /* power state transition flags on */
+        pm_state->flags |= PT_FLAG_TRANSITING;
+    }
+    /* in case of transition related to D0, D1 and D2,
+     * no need to use QEMUTimer.
+     * So, we perfom writing to register here and then read it back.
+     */
+    else {
+        /* write power state to I/O device register */
+        host_pci_set_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                          *value);
+
+        /* in case of transition related to D2,
+         * it's necessary to wait 200 usec.
+         * But because QEMUTimer do not support microsec unit right now,
+         * so we do wait ourself here.
+         */
+        if ((pm_state->cur_state == 2) || (pm_state->req_state == 2)) {
+            usleep(200);
+        }
+
+        /* check power state */
+        check_power_state(s);
+
+        /* recreate value for writing to I/O device register */
+        if (host_pci_get_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                              value)) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/* restore Power Management Control/Status register */
+static int pt_pmcsr_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint32_t real_offset, uint16_t dev_value,
+                                uint16_t *value)
+{
+    /* create value for restoring to I/O device register
+     * No need to restore, just clear PME Enable and PME Status bit
+     * Note: register type of PME Status bit is RW1C, so clear by writing 1b
+     */
+    *value = (dev_value & ~PCI_PM_CTRL_PME_ENABLE) | PCI_PM_CTRL_PME_STATUS;
+
+    return 0;
+}
+
+
+/* Power Management Capability reg static infomation table */
+static XenPTRegInfo pt_emu_reg_pm_tbl[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Power Management Capabilities reg */
+    {
+        .offset     = PCI_CAP_FLAGS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xF9C8,
+        .init       = pt_pmc_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* PCI Power Management Control/Status reg */
+    {
+        .offset     = PCI_PM_CTRL,
+        .size       = 2,
+        .init_val   = 0x0008,
+        .ro_mask    = 0xE1FC,
+        .emu_mask   = 0x8100,
+        .init       = pt_pmcsr_reg_init,
+        .u.w.read   = pt_pmcsr_reg_read,
+        .u.w.write  = pt_pmcsr_reg_write,
+        .u.w.restore  = pt_pmcsr_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/****************************
+ * Capabilities
+ */
+
+/* AER register operations */
+
+static void aer_save_one_register(XenPCIPassthroughState *s, int offset)
+{
+    PCIDevice *d = &s->dev;
+    uint32_t aer_base = s->pm_state->aer_base;
+    uint32_t val = 0;
+
+    if (host_pci_get_long(s->real_device, aer_base + offset, &val)) {
+        return;
+    }
+    pci_set_long(d->config + aer_base + offset, val);
+}
+static void pt_aer_reg_save(XenPCIPassthroughState *s)
+{
+    /* after reset, following register values should be restored.
+     * So, save them.
+     */
+    aer_save_one_register(s, PCI_ERR_UNCOR_MASK);
+    aer_save_one_register(s, PCI_ERR_UNCOR_SEVER);
+    aer_save_one_register(s, PCI_ERR_COR_MASK);
+    aer_save_one_register(s, PCI_ERR_CAP);
+}
+static void aer_restore_one_register(XenPCIPassthroughState *s, int offset)
+{
+    PCIDevice *d = &s->dev;
+    uint32_t aer_base = s->pm_state->aer_base;
+    uint32_t config = 0;
+
+    config = pci_get_long(d->config + aer_base + offset);
+    host_pci_set_long(s->real_device, aer_base + offset, config);
+}
+static void pt_aer_reg_restore(XenPCIPassthroughState *s)
+{
+    /* the following registers should be reconfigured to correct values
+     * after reset. restore them.
+     * other registers should not be reconfigured after reset
+     * if there is no reason
+     */
+    aer_restore_one_register(s, PCI_ERR_UNCOR_MASK);
+    aer_restore_one_register(s, PCI_ERR_UNCOR_SEVER);
+    aer_restore_one_register(s, PCI_ERR_COR_MASK);
+    aer_restore_one_register(s, PCI_ERR_CAP);
+}
+
+/* capability structure register group size functions */
+
+static int pt_reg_grp_size_init(XenPCIPassthroughState *s,
+                                const XenPTRegGroupInfo *grp_reg,
+                                uint32_t base_offset, uint8_t *size)
+{
+    *size = grp_reg->grp_size;
+    return 0;
+}
+/* get Power Management Capability Structure register group size */
+static int pt_pm_size_init(XenPCIPassthroughState *s,
+                           const XenPTRegGroupInfo *grp_reg,
+                           uint32_t base_offset, uint8_t *size)
+{
+    *size = grp_reg->grp_size;
+
+    if (!s->power_mgmt) {
+        return 0;
+    }
+
+    s->pm_state = g_new0(XenPTPM, 1);
+
+    /* set Power Management Capability base offset */
+    s->pm_state->pm_base = base_offset;
+
+    /* find AER register and set AER Capability base offset */
+    s->pm_state->aer_base = host_pci_find_ext_cap_offset(s->real_device,
+                                                         PCI_EXT_CAP_ID_ERR);
+
+    /* save AER register */
+    if (s->pm_state->aer_base) {
+        pt_aer_reg_save(s);
+    }
+
+    return 0;
+}
+/* get Vendor Specific Capability Structure register group size */
+static int pt_vendor_size_init(XenPCIPassthroughState *s,
+                               const XenPTRegGroupInfo *grp_reg,
+                               uint32_t base_offset, uint8_t *size)
+{
+    *size = pci_get_byte(s->dev.config + base_offset + 0x02);
+    return 0;
+}
+/* get PCI Express Capability Structure register group size */
+static int pt_pcie_size_init(XenPCIPassthroughState *s,
+                             const XenPTRegGroupInfo *grp_reg,
+                             uint32_t base_offset, uint8_t *size)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t exp_flag = 0;
+    uint16_t type = 0;
+    uint16_t version = 0;
+    uint8_t pcie_size = 0;
+
+    exp_flag = pci_get_word(d->config + base_offset + PCI_EXP_FLAGS);
+    type = (exp_flag & PCI_EXP_FLAGS_TYPE) >> 4;
+    version = exp_flag & PCI_EXP_FLAGS_VERS;
+
+    /* calculate size depend on capability version and device/port type */
+    /* in case of PCI Express Base Specification Rev 1.x */
+    if (version == 1) {
+        /* The PCI Express Capabilities, Device Capabilities, and Device
+         * Status/Control registers are required for all PCI Express devices.
+         * The Link Capabilities and Link Status/Control are required for all
+         * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
+         * are not required to implement registers other than those listed
+         * above and terminate the capability structure.
+         */
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+            pcie_size = 0x14;
+            break;
+        case PCI_EXP_TYPE_RC_END:
+            /* has no link */
+            pcie_size = 0x0C;
+            break;
+        /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            PT_ERR(d, "Internal error: Unsupported device/port type (%d).\n",
+                   type);
+            return -1;
+        }
+    }
+    /* in case of PCI Express Base Specification Rev 2.0 */
+    else if (version == 2) {
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+        case PCI_EXP_TYPE_RC_END:
+            /* For Functions that do not implement the registers,
+             * these spaces must be hardwired to 0b.
+             */
+            pcie_size = 0x3C;
+            break;
+        /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            PT_ERR(d, "Internal error: Unsupported device/port type (%d).\n",
+                   type);
+            return -1;
+        }
+    } else {
+        PT_ERR(d, "Internal error: Unsupported capability version (%d).\n",
+               version);
+        return -1;
+    }
+
+    *size = pcie_size;
+    return 0;
+}
+
+static const XenPTRegGroupInfo pt_emu_reg_grp_tbl[] = {
+    /* Header Type0 reg group */
+    {
+        .grp_id      = 0xFF,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0x40,
+        .size_init   = pt_reg_grp_size_init,
+        .emu_reg_tbl = pt_emu_reg_header0_tbl,
+    },
+    /* PCI PowerManagement Capability reg group */
+    {
+        .grp_id      = PCI_CAP_ID_PM,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = PCI_PM_SIZEOF,
+        .size_init   = pt_pm_size_init,
+        .emu_reg_tbl = pt_emu_reg_pm_tbl,
+    },
+    /* AGP Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vital Product Data Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VPD,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0x08,
+        .size_init   = pt_reg_grp_size_init,
+        .emu_reg_tbl = pt_emu_reg_vpd_tbl,
+    },
+    /* Slot Identification reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SLOTID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x04,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* PCI-X Capabilities List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_PCIX,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x18,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vendor Specific Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VNDR,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = pt_vendor_size_init,
+        .emu_reg_tbl = pt_emu_reg_vendor_tbl,
+    },
+    /* SHPC Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SHPC,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SSVID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* AGP 8x Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP3,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* PCI Express Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_EXP,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = pt_pcie_size_init,
+        .emu_reg_tbl = pt_emu_reg_pcie_tbl,
+    },
+    {
+        .grp_size = 0,
+    },
+};
+
+/* initialize Capabilities Pointer or Next Pointer register */
+static int pt_ptr_reg_init(XenPCIPassthroughState *s,
+                           XenPTRegInfo *reg, uint32_t real_offset,
+                           uint32_t *data)
+{
+    /* uint32_t reg_field = (uint32_t)s->dev.config[real_offset]; */
+    uint32_t reg_field = pci_get_byte(s->dev.config + real_offset);
+    int i;
+
+    /* find capability offset */
+    while (reg_field) {
+        for (i = 0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++) {
+            if (pt_hide_dev_cap(s->real_device,
+                                pt_emu_reg_grp_tbl[i].grp_id)) {
+                continue;
+            }
+            if (pt_emu_reg_grp_tbl[i].grp_id == s->dev.config[reg_field]) {
+                if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU) {
+                    goto out;
+                }
+                /* ignore the 0 hardwired capability, find next one */
+                break;
+            }
+        }
+        /* next capability */
+        /* reg_field = (uint32_t)s->dev.config[reg_field + 1]; */
+        reg_field = pci_get_byte(s->dev.config + reg_field + 1);
+    }
+
+out:
+    *data = reg_field;
+    return 0;
+}
+
+
+/*************
+ * Main
+ */
+
+/* restore a part of I/O device register */
+static int pt_config_restore(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    uint32_t real_offset = 0;
+    uint32_t read_val = 0;
+    uint32_t val = 0;
+    int rc = 0;
+
+    /* find emulate register group entry */
+    QLIST_FOREACH(reg_grp_entry, &s->reg_grp_tbl, entries) {
+        /* find emulate register entry */
+        QLIST_FOREACH(reg_entry, &reg_grp_entry->reg_tbl_list, entries) {
+            reg = reg_entry->reg;
+
+            /* check whether restoring is needed */
+            if (!reg->u.b.restore) {
+                continue;
+            }
+
+            real_offset = reg_grp_entry->base_offset + reg->offset;
+
+            /* read I/O device register value */
+            rc = host_pci_get_block(s->real_device, real_offset,
+                                    (uint8_t *)&read_val, reg->size);
+
+            if (rc < 0) {
+                PT_ERR(&s->dev, "pci_read_block failed. "
+                       "return value: %d.\n", rc);
+                memset(&read_val, 0xff, reg->size);
+            }
+
+            val = 0;
+
+            /* restore based on register size */
+            switch (reg->size) {
+            case 1:
+                /* byte register */
+                rc = reg->u.b.restore(s, reg_entry, real_offset,
+                                      (uint8_t)read_val, (uint8_t *)&val);
+                break;
+            case 2:
+                /* word register */
+                rc = reg->u.w.restore(s, reg_entry, real_offset,
+                                      (uint16_t)read_val, (uint16_t *)&val);
+                break;
+            case 4:
+                /* double word register */
+                rc = reg->u.dw.restore(s, reg_entry, real_offset,
+                                       (uint32_t)read_val, (uint32_t *)&val);
+                break;
+            }
+
+            /* restoring error */
+            if (rc < 0) {
+                xen_shutdown_fatal_error("Internal error: Invalid restoring."
+                                         " (%s, rc: %d)\n", __func__, rc);
+                return -1;
+            }
+
+            PT_LOG_CONFIG(&s->dev, real_offset, val, reg->size);
+
+            rc = host_pci_set_block(s->real_device, real_offset,
+                                    (uint8_t *)&val, reg->size);
+
+            if (rc < 0) {
+                PT_ERR(&s->dev, "pci_write_block failed. "
+                       "return value: %d.\n", rc);
+                return -1;
+            }
+        }
+    }
+
+    /* if AER supported, restore it */
+    if (s->pm_state->aer_base) {
+        pt_aer_reg_restore(s);
+    }
+    return 0;
+}
+/* reinitialize all emulate registers */
+static int pt_config_reinit(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    int rc = 0;
+
+    /* find emulate register group entry */
+    QLIST_FOREACH(reg_grp_entry, &s->reg_grp_tbl, entries) {
+        /* find emulate register entry */
+        QLIST_FOREACH(reg_entry, &reg_grp_entry->reg_tbl_list, entries) {
+            reg = reg_entry->reg;
+            if (reg->init) {
+                /* initialize emulate register */
+                rc = reg->init(s, reg_entry->reg,
+                               reg_grp_entry->base_offset + reg->offset,
+                               &reg_entry->data);
+                if (rc < 0) {
+                    return rc;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static int pt_init_pci_config(XenPCIPassthroughState *s)
+{
+    PCIDevice *d = &s->dev;
+    int rc = 0;
+
+    PT_LOG(d, "Reinitialize PCI configuration registers due to power state"
+           " transition with internal reset.\n");
+
+    /* restore a part of I/O device register */
+    rc = pt_config_restore(s);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /* reinitialize all emulate register */
+    rc = pt_config_reinit(s);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /* rebind machine_irq to device */
+    if (s->machine_irq != 0) {
+        uint8_t e_device = PCI_SLOT(s->dev.devfn);
+        uint8_t e_intx = pci_intx(s);
+
+        rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, s->machine_irq, 0,
+                                       e_device, e_intx);
+        if (rc < 0) {
+            PT_ERR(d, "Rebinding of interrupt failed! rc=%d\n", rc);
+        }
+    }
+
+    return rc;
+}
+
+static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
+{
+    uint8_t id;
+    int max_cap = 48;
+    uint8_t pos = PCI_CAPABILITY_LIST;
+    uint8_t status = 0;
+
+    if (host_pci_get_byte(s->real_device, PCI_STATUS, &status)) {
+        return 0;
+    }
+    if ((status & PCI_STATUS_CAP_LIST) == 0) {
+        return 0;
+    }
+
+    while (max_cap--) {
+        if (host_pci_get_byte(s->real_device, pos, &pos)) {
+            break;
+        }
+        if (pos < 0x40) {
+            break;
+        }
+
+        pos &= ~3;
+        if (host_pci_get_byte(s->real_device, pos + PCI_CAP_LIST_ID, &id)) {
+            break;
+        }
+
+        if (id == 0xff) {
+            break;
+        }
+        if (id == cap) {
+            return pos;
+        }
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+static int pt_config_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegGroup *reg_grp, XenPTRegInfo *reg)
+{
+    XenPTReg *reg_entry;
+    uint32_t data = 0;
+    int rc = 0;
+
+    reg_entry = g_new0(XenPTReg, 1);
+    reg_entry->reg = reg;
+
+    if (reg->init) {
+        /* initialize emulate register */
+        rc = reg->init(s, reg_entry->reg,
+                       reg_grp->base_offset + reg->offset, &data);
+        if (rc < 0) {
+            free(reg_entry);
+            return rc;
+        }
+        if (data == PT_INVALID_REG) {
+            /* free unused BAR register entry */
+            free(reg_entry);
+            return 0;
+        }
+        /* set register value */
+        reg_entry->data = data;
+    }
+    /* list add register entry */
+    QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
+
+    return 0;
+}
+
+int pt_config_init(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    uint32_t reg_grp_offset = 0;
+    XenPTRegInfo *reg_tbl = NULL;
+    int i, j, rc;
+
+    QLIST_INIT(&s->reg_grp_tbl);
+
+    for (i = 0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++) {
+        if (pt_emu_reg_grp_tbl[i].grp_id != 0xFF) {
+            if (pt_hide_dev_cap(s->real_device,
+                                pt_emu_reg_grp_tbl[i].grp_id)) {
+                continue;
+            }
+
+            reg_grp_offset = find_cap_offset(s, pt_emu_reg_grp_tbl[i].grp_id);
+
+            if (!reg_grp_offset) {
+                continue;
+            }
+        }
+
+        reg_grp_entry = g_new0(XenPTRegGroup, 1);
+        QLIST_INIT(&reg_grp_entry->reg_tbl_list);
+        QLIST_INSERT_HEAD(&s->reg_grp_tbl, reg_grp_entry, entries);
+
+        reg_grp_entry->base_offset = reg_grp_offset;
+        reg_grp_entry->reg_grp = pt_emu_reg_grp_tbl + i;
+        if (pt_emu_reg_grp_tbl[i].size_init) {
+            /* get register group size */
+            rc = pt_emu_reg_grp_tbl[i].size_init(s, reg_grp_entry->reg_grp,
+                                                 reg_grp_offset,
+                                                 &reg_grp_entry->size);
+            if (rc < 0) {
+                pt_config_delete(s);
+                return rc;
+            }
+        }
+
+        if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU) {
+            if (pt_emu_reg_grp_tbl[i].emu_reg_tbl) {
+                reg_tbl = pt_emu_reg_grp_tbl[i].emu_reg_tbl;
+                /* initialize capability register */
+                for (j = 0; reg_tbl->size != 0; j++, reg_tbl++) {
+                    /* initialize capability register */
+                    rc = pt_config_reg_init(s, reg_grp_entry, reg_tbl);
+                    if (rc < 0) {
+                        pt_config_delete(s);
+                        return rc;
+                    }
+                }
+            }
+        }
+        reg_grp_offset = 0;
+    }
+
+    return 0;
+}
+
+/* delete all emulate register */
+void pt_config_delete(XenPCIPassthroughState *s)
+{
+    struct XenPTRegGroup *reg_group, *next_grp;
+    struct XenPTReg *reg, *next_reg;
+
+    /* free Power Management info table */
+    if (s->pm_state) {
+        if (s->pm_state->pm_timer) {
+            qemu_del_timer(s->pm_state->pm_timer);
+            qemu_free_timer(s->pm_state->pm_timer);
+            s->pm_state->pm_timer = NULL;
+        }
+
+        g_free(s->pm_state);
+    }
+
+    /* free all register group entry */
+    QLIST_FOREACH_SAFE(reg_group, &s->reg_grp_tbl, entries, next_grp) {
+        /* free all register entry */
+        QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
+            QLIST_REMOVE(reg, entries);
+            g_free(reg);
+        }
+
+        QLIST_REMOVE(reg_group, entries);
+        g_free(reg_group);
+    }
+}
-- 
Anthony PERARD


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

From xen-users-bounces@lists.xensource.com Thu Nov 17 23:20:59 2011
Return-path: <xen-users-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2011 23:20:59 +0000
Received: from lists.colo.xensource.com ([70.42.241.110] helo=lists.xensource.com)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-users-bounces@lists.xensource.com>)
	id 1RRBGM-0002tF-Bs
	for archives@lists.xen.org; Thu, 17 Nov 2011 23:20:59 +0000
Received: from localhost ([127.0.0.1] helo=lists.colo.xensource.com)
	by lists.xensource.com with esmtp (Exim 4.43)
	id 1RRBFy-0008G7-Cu; Thu, 17 Nov 2011 15:20:34 -0800
Received: from mail182.messagelabs.com ([85.158.139.83])
	by lists.xensource.com with smtp (Exim 4.43) id 1RRBFG-0008Cj-6J
	for xen-users@lists.xensource.com; Thu, 17 Nov 2011 15:19:53 -0800
X-Env-Sender: artnapor@yahoo.com
X-Msg-Ref: server-5.tower-182.messagelabs.com!1321571985!3612444!1
X-Originating-IP: [98.138.91.227]
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 32453 invoked from network); 17 Nov 2011 23:19:46 -0000
Received: from nm5-vm5.bullet.mail.ne1.yahoo.com (HELO
	nm5-vm5.bullet.mail.ne1.yahoo.com) (98.138.91.227)
	by server-5.tower-182.messagelabs.com with SMTP;
	17 Nov 2011 23:19:46 -0000
Received: from [98.138.90.50] by nm5.bullet.mail.ne1.yahoo.com with NNFMP;
	17 Nov 2011 23:19:45 -0000
Received: from [98.138.89.197] by tm3.bullet.mail.ne1.yahoo.com with NNFMP;
	17 Nov 2011 23:19:45 -0000
Received: from [127.0.0.1] by omp1055.mail.ne1.yahoo.com with NNFMP;
	17 Nov 2011 23:19:45 -0000
X-Yahoo-Newman-Property: ymail-5
X-Yahoo-Newman-Id: 331198.32727.bm@omp1055.mail.ne1.yahoo.com
Received: (qmail 21619 invoked by uid 60001); 17 Nov 2011 23:19:45 -0000
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s1024;
	t=1321571985; bh=mlIHOCGbi9DLJakxgDvdT6cF0o4p/gacJzJVutIwLWo=;
	h=X-YMail-OSG:Received:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type;
	b=2gzZ7qPZelTtiyt5O4m2uVCcbMgOTVaFwdo81UjCmzdpIaH77eg2ErBgoW8N6/Q+RERUsq7N09zY8y4DRYvQr6/AzQS8k5hP5FPETchcF7aiqj0i3Bb991ri2ChDdH5bBJ3mIFxYvb60k5/hWbVjp7LMUzj6DYbhQFzVbzY3+R0=
DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com;
	h=X-YMail-OSG:Received:X-Mailer:Message-ID:Date:From:Reply-To:Subject:To:MIME-Version:Content-Type;
	b=VNtn14src9EZtBB37nbsbr3PUyjKrX/Zu0QA9dwgHpDeEqHFQ7jsPcsqaT6lvz8FvDawIha46MSTGq5K1qqJ83KKtURIHjwQcMmgp2kkGfjfvWoRpZpamZtbymZ0refGyDgsWytM/JFVyb6YNU2D5SsRK/Qnjg8NPPeHUh6BmE4=;
X-YMail-OSG: Xds2YysVM1kZvx.i.pBbE85ZUkdHD47iVDyeyYL4oj1Uuqg
	6zjCRgnlcQEAKpMBXKefdOgQgRvBAIQg_VmEpv.nPxeTNPl6Yb9zy6xF1Gmh
	CIVgkc8iRd_byxJdsupEySAINeqUkm5cmShuJesWrilIN.YOSEFbRUaKwVjM
	WSwFhtzTBV2XYx6nc8aw48alDsT1wG780IvWulTAHqyuLSygtaOSsPY0jgbg
	RYvXMusNayAL4_o7Ih.x_XtT7ObcXKG.3tta4GM8.ZcR.N_NdXNX5zl5ZqT4
	mV9Nsl1r9cGD25CyHcV5NDP4BKctSv74iBVl5xDAvSvghYGagBbJLezBB_D2
	BNUemfB._B2CRbhSBTzh40sL6EaPYYimJVJt1QIPUtYALHfAzoa51prHulG7
	3L3vrrqu82X9ZsQIbOphFIxIPnkvouCfnFtPdww--
Received: from [50.58.96.2] by web121020.mail.ne1.yahoo.com via HTTP;
	Thu, 17 Nov 2011 15:19:45 PST
X-Mailer: YahooMailWebService/0.8.115.325013
Message-ID: <1321571985.18412.YahooMailNeo@web121020.mail.ne1.yahoo.com>
Date: Thu, 17 Nov 2011 15:19:45 -0800 (PST)
From: Art Napor <artnapor@yahoo.com>
To: "xen-users@lists.xensource.com" <xen-users@lists.xensource.com>
MIME-Version: 1.0
Subject: [Xen-users] ERROR: Unable to locate IOAPIC for GSI 9 and GSI2
X-BeenThere: xen-users@lists.xensource.com
X-Mailman-Version: 2.1.5
Precedence: list
Reply-To: Art Napor <artnapor@yahoo.com>
List-Id: Xen user discussion <xen-users.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-users>,
	<mailto:xen-users-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-users@lists.xensource.com>
List-Help: <mailto:xen-users-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-users>,
	<mailto:xen-users-request@lists.xensource.com?subject=subscribe>
Content-Type: multipart/mixed; boundary="===============0010739811=="
Sender: xen-users-bounces@lists.xensource.com
Errors-To: xen-users-bounces@lists.xensource.com

--===============0010739811==
Content-Type: multipart/alternative;
	boundary="2014727138-887952032-1321571985=:18412"

--2014727138-887952032-1321571985=:18412
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

I've noticed the GSI errors while booting XEN 4.1.1-3 and 4.1.2. I believe =
they stem from the overides at boot. Is there a way to remove the errors or=
 another option that needs to be passed at boot? The system boots and seems=
 to run. =0A=0A__  __            _  _    _   _   _____      _  __   =0A\ \/=
 /___ _ __   | || |  / | / | |___ /  ___| |/ /_  =0A\  // _ \ '_ \  | || |_=
 | | | |__ |_ \ / _ \ | '_ \  =0A/  \  __/ | | | |__   _|| |_| |__|__) |  _=
_/ | (_) | =0A=0A/_/\_\___|_| |_|    |_|(_)_(_)_| |____(_)___|_|\___/   =0A=
  =0A(XEN) Xen version 4.1.1 (root@(none)) (gcc version 4.4.4 20100726 (Red=
 Hat 4.4.4-13) (GCC) ) Thu Aug 25 14:35:46 EDT 2011 =0A(XEN) Latest ChangeS=
et: unavailable =0A(XEN) Bootloader: GNU GRUB 0.97 =0A(XEN) Command line: l=
oglvl=3Dall =0Aguest_loglvl=3Dall dom0_max_vcpus=3D2 dom0_vcpus_pin dom0_me=
m=3D2048M =0Aconsole=3Dtty0 console=3Dcom1 com1=3D38400,8n1 =0A(XEN) Video =
information: =0A(XEN)  VGA is text mode 80x25, font 8x16 =0A(XEN)  VBE/DDC =
methods: none; EDID transfer time: 0 seconds =0A(XEN)  EDID info not retrie=
ved because no DDC retrieval method detected =0A(XEN) Disc information: =0A=
(XEN)  Found 1 MBR signatures =0A(XEN)  Found 1 EDD information structures =
=0A(XEN) Xen-e820 RAM map: =0A(XEN)  0000000000000000 - 00000000000a0000 (u=
sable) =0A(XEN)  0000000000100000 - 00000000cf379000 (usable) =0A(XEN)  000=
00000cf379000 - 00000000cf38f000 (reserved) =0A(XEN)  00000000cf38f000 - 00=
000000cf3ce000 (ACPI data) =0A(XEN)  00000000cf3ce000 - 00000000d0000000 (r=
eserved) =0A(XEN)  00000000e0000000 - 00000000f0000000 (reserved) =0A(XEN) =
 00000000fe000000 - 0000000100000000 (reserved) =0A(XEN)  0000000100000000 =
- 0000000830000000 (usable) =0A(XEN) ACPI: RSDP 000F11A0, 0024 (r2 DELL  ) =
=0A(XEN) ACPI Warning (tbutils-0455): BIOS XSDT has NULL entry, using RSDT =
[20070126] =0A=0A(XEN) ACPI: RSDT 000F11C4, 0060 (r1 DELL   PE_SC3         =
 1 DELL        1)  =0A=0A(XEN) ACPI: FACP CF3B3400, 0074 (r1 DELL   PE_SC3 =
         1 DELL        1)  =0A=0A(XEN) ACPI: DSDT CF38F000, 3D72 (r1 DELL  =
 PE_SC3          1 INTL 20050624)  =0A(XEN) ACPI: FACS CF3B6000, 0040 =0A=
=0A(XEN) ACPI: APIC CF3B3478, 015E (r1 DELL   PE_SC3          1 DELL       =
 1)  =0A=0A(XEN) ACPI: SPCR CF3B35D8, 0050 (r1 DELL   PE_SC3          1 DEL=
L        1)  =0A=0A(XEN) ACPI: HPET CF3B362C, 0038 (r1 DELL   PE_SC3       =
   1 DELL        1)  =0A=0A(XEN) ACPI: DMAR CF3B3668, 01A8 (r1 DELL   PE_SC=
3          1 DELL        1)  =0A=0A(XEN) ACPI: MCFG CF3B38C4, 003C (r1 DELL=
   PE_SC3          1 DELL        1)  =0A=0A(XEN) ACPI: WD__ CF3B3904, 0134 =
(r1 DELL   PE_SC3          1 DELL        1)  =0A=0A(XEN) ACPI: SLIC CF3B3A3=
C, 0176 (r1 DELL   PE_SC3          1 DELL        1)  =0A=0A(XEN) ACPI: ERST=
 CF392EF4, 0270 (r1 DELL   PE_SC3          1 DELL        1)  =0A=0A(XEN) AC=
PI: HEST CF393164, 03A8 (r1 DELL   PE_SC3          1 DELL        1)  =0A=0A=
(XEN) ACPI: BERT CF392D74, 0030 (r1 DELL   PE_SC3          1 DELL        1)=
  =0A=0A(XEN) ACPI: EINJ CF392DA4, 0150 (r1 DELL   PE_SC3          1 DELL  =
      1)  =0A(XEN) ACPI Error (tbutils-0280): Null physical address for ACP=
I table [<NULL>] [20070126] =0A=0A(XEN) ACPI: TCPA CF3B3BC0, 0064 (r2 DELL =
  PE_SC3          1 DELL        1)  =0A(XEN) ACPI: SSDT CF3B7000, 7E9C (r1 =
 INTEL PPM RCM  80000001 INTL 20061109) =0A(XEN) System RAM: 32755MB (33541=
220kB) =0A(XEN) No NUMA configuration found =0A(XEN) Faking a node at 00000=
00000000000-0000000830000000 =0A(XEN) Domain heap initialised =0A(XEN) foun=
d SMP MP-table at 000fe710 =0A(XEN) DMI 2.6 present. =0A(XEN) Using APIC dr=
iver default =0A(XEN) ACPI: PM-Timer IO Port: 0x808 =0A(XEN) ACPI: ACPI SLE=
EP INFO: pm1x_cnt[804,0], pm1x_evt[800,0] =0A=0A(XEN) ACPI:                =
  wakeup_vec[cf3b600c], vec_size[20]  =0A(XEN) ACPI: Local APIC address 0xf=
ee00000 =0A(XEN) ACPI: LAPIC (acpi_id[0x01] lapic_id[0x20] enabled) =0A(XEN=
) Processor #32 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x02] la=
pic_id[0x00] enabled) =0A(XEN) Processor #0 6:12 APIC version 21 =0A(XEN) A=
CPI: LAPIC (acpi_id[0x03] lapic_id[0x22] enabled) =0A(XEN) Processor #34 6:=
12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x04] lapic_id[0x02] enabl=
ed) =0A(XEN) Processor #2 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_i=
d[0x05] lapic_id[0x24] enabled) =0A(XEN) Processor #36 6:12 APIC version 21=
 =0A(XEN) ACPI: LAPIC (acpi_id[0x06] lapic_id[0x04] enabled) =0A(XEN) Proce=
ssor #4 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x07] lapic_id[0=
x30] enabled) =0A(XEN) Processor #48 6:12 APIC version 21 =0A(XEN) ACPI: LA=
PIC (acpi_id[0x08] lapic_id[0x10] enabled) =0A(XEN) Processor #16 6:12 APIC=
 version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x09] lapic_id[0x32] enabled) =0A=
(XEN) Processor #50 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x0a=
] lapic_id[0x12] enabled) =0A(XEN) Processor #18 6:12 APIC version 21 =0A(X=
EN) ACPI: LAPIC (acpi_id[0x0b] lapic_id[0x34] enabled) =0A(XEN) Processor #=
52 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x0c] lapic_id[0x14] =
enabled) =0A(XEN) Processor #20 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (=
acpi_id[0x0d] lapic_id[0x21] enabled) =0A(XEN) Processor #33 6:12 APIC vers=
ion 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x0e] lapic_id[0x01] enabled) =0A(XEN)=
 Processor #1 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x0f] lapi=
c_id[0x23] enabled) =0A(XEN) Processor #35 6:12 APIC version 21 =0A(XEN) AC=
PI: LAPIC (acpi_id[0x10] lapic_id[0x03] enabled) =0A(XEN) Processor #3 6:12=
 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x11] lapic_id[0x25] enabled=
) =0A(XEN) Processor #37 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id=
[0x12] lapic_id[0x05] enabled) =0A(XEN) Processor #5 6:12 APIC version 21 =
=0A(XEN) ACPI: LAPIC (acpi_id[0x13] lapic_id[0x31] enabled) =0A(XEN) Proces=
sor #49 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x14] lapic_id[0=
x11] enabled) =0A(XEN) Processor #17 6:12 APIC version 21 =0A(XEN) ACPI: LA=
PIC (acpi_id[0x15] lapic_id[0x33] enabled) =0A(XEN) Processor #51 6:12 APIC=
 version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x16] lapic_id[0x13] enabled) =0A=
(XEN) Processor #19 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x17=
] lapic_id[0x35] enabled) =0A(XEN) Processor #53 6:12 APIC version 21 =0A(X=
EN) ACPI: LAPIC (acpi_id[0x18] lapic_id[0x15] enabled) =0A(XEN) Processor #=
21 6:12 APIC version 21 =0A(XEN) ACPI: LAPIC (acpi_id[0x19] lapic_id[0xff] =
disabled) =0A(XEN) ACPI: LAPIC (acpi_id[0x1a] lapic_id[0xff] disabled) =0A(=
XEN) ACPI: LAPIC (acpi_id[0x1b] lapic_id[0xff] disabled) =0A(XEN) ACPI: LAP=
IC (acpi_id[0x1c] lapic_id[0xff] disabled) =0A(XEN) ACPI: LAPIC (acpi_id[0x=
1d] lapic_id[0xff] disabled) =0A(XEN) ACPI: LAPIC (acpi_id[0x1e] lapic_id[0=
xff] disabled) =0A(XEN) ACPI: LAPIC (acpi_id[0x1f] lapic_id[0xff] disabled)=
 =0A(XEN) ACPI: LAPIC (acpi_id[0x20] lapic_id[0xff] disabled) =0A(XEN) ACPI=
: LAPIC_NMI (acpi_id[0xff] high edge lint[0x1]) =0A(XEN) Overriding APIC dr=
iver with bigsmp =0A(XEN) ACPI: IOAPIC (id[0x00] address[0xfec00000] gsi_ba=
se[0]) =0A(XEN) IOAPIC[0]: apic_id 0, version 32, address 0xfec00000, GSI 0=
-23 =0A(XEN) ACPI: IOAPIC (id[0x01] address[0xfec80000] gsi_base[32]) =0A(X=
EN) IOAPIC[1]: apic_id 1, version 32, address 0xfec80000, GSI 32-55 =0A(XEN=
) ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl) =0A(XEN) ACPI: I=
NT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level) =0A(XEN) ACPI: IRQ0 us=
ed by override. =0A(XEN) ACPI: IRQ2 used by override. =0A(XEN) ACPI: IRQ9 u=
sed by override. =0A(XEN) Enabling APIC mode:  Phys.  Using 2 I/O APICs =0A=
(XEN) ACPI: HPET id: 0x8086a301 base: 0xfed00000 =0A(XEN) PCI: MCFG configu=
ration 0: base e0000000 segment 0 buses 0 - 255 =0A(XEN) PCI: MCFG area at =
e0000000 reserved in E820 =0A(XEN) ERST table is invalid =0A(XEN) Using ACP=
I (MADT) for SMP configuration information =0A(XEN) IRQ limits: 55 GSI, 456=
9 MSI/MSI-X =0A(XEN) Using scheduler: SMP Credit Scheduler (credit) =0A(XEN=
) Detected 3458.097 MHz processor. =0A(XEN) Initing memory sharing. =0A(XEN=
) mce_intel.c:1162: MCA Capability: BCAST 1 SER 0 CMCI 1 firstbank 0 extend=
ed MCE MSR 0 =0A(XEN) Intel machine check reporting enabled =0A(XEN) Intel =
VT-d Snoop Control enabled. =0A(XEN) Intel VT-d Dom0 DMA Passthrough not en=
abled. =0A(XEN) Intel VT-d Queued Invalidation enabled. =0A(XEN) Intel VT-d=
 Interrupt Remapping enabled. =0A(XEN) Intel VT-d Shared EPT tables not ena=
bled. =0A(XEN) I/O virtualisation enabled =0A(XEN)  - Dom0 mode: Relaxed =
=0A(XEN) Enabled directed EOI with ioapic_ack_old on! =0A(XEN) ENABLING IO-=
APIC IRQs =0A(XEN)  -> Using old ACK method =0A(XEN) ..TIMER: vector=3D0xF0=
 apic1=3D0 pin1=3D2 apic2=3D-1 pin2=3D-1 =0A(XEN) Platform timer is 14.318M=
Hz HPET =0A(XEN) Defaulting to alternative key handling; send 'A' to switch=
 to normal mode. =0A=EF=BF=BD(XEN) Allocated console ring of 256 KiB. =0A(X=
EN) VMX: Supported advanced features: =0A(XEN)  - APIC MMIO access virtuali=
sation =0A(XEN)  - APIC TPR shadow =0A(XEN)  - Extended Page Tables (EPT) =
=0A(XEN)  - Virtual-Processor Identifiers (VPID) =0A(XEN)  - Virtual NMI =
=0A(XEN)  - MSR direct-access bitmap =0A(XEN)  - Unrestricted Guest =0A(XEN=
) EPT supports 1GB super page. =0A(XEN) EPT supports 2MB super page. =0A(XE=
N) HVM: ASIDs enabled. =0A(XEN) HVM: VMX enabled =0A(XEN) HVM: Hardware Ass=
isted Paging detected. =0A(XEN) Brought up 24 CPUs =0A(XEN) ACPI sleep mode=
s: S3 =0A(XEN) mcheck_poll: Machine check polling timer started. =0A(XEN) *=
** LOADING DOMAIN 0 *** =0A(XEN)  Xen  kernel: 64-bit, lsb, compat32 =0A(XE=
N)  Dom0 kernel: 64-bit, PAE, lsb, paddr 0x1000000 -> 0x2744000 =0A(XEN) PH=
YSICAL MEMORY ARRANGEMENT: =0A(XEN)  Dom0 alloc.:   0000000800000000->00000=
00804000000 (431348 pages to be allocated) =0A(XEN)  Init. ramdisk: 0000000=
81d4f4000->000000082ffffe00 =0A(XEN) VIRTUAL MEMORY ARRANGEMENT: =0A(XEN)  =
Loaded kernel: ffffffff81000000->ffffffff82744000 =0A(XEN)  Init. ramdisk: =
ffffffff82744000->ffffffff9524fe00 =0A(XEN)  Phys-Mach map: ffffffff9525000=
0->ffffffff95650000 =0A=0A(XEN)  Start info:    ffffffff95650000->ffffffff9=
56504b4  =0A(XEN)  Page tables:   ffffffff95651000->ffffffff95700000 =0A=0A=
(XEN)  Boot stack:    ffffffff95700000->ffffffff95701000  =0A=0A(XEN)  TOTA=
L:         ffffffff80000000->ffffffff95800000  =0A(XEN)  ENTRY ADDRESS: fff=
fffff8197a200 =0A(XEN) Dom0 has maximum 2 VCPUs =0A(XEN) Scrubbing Free RAM=
: =0A......................................................................=
...........................................................................=
...........................................................................=
...........................................................................=
.......done. =0A(XEN) Xen trace buffers: disabled =0A(XEN) Std. Loglevel: A=
ll =0A(XEN) Guest Loglevel: All =0A(XEN) *** Serial input -> DOM0 (type 'CT=
RL-a' three times to switch input to Xen) =0A(XEN) Freed 228kB init memory.=
 =0Amapping kernel into physical memory =0AXen: setup ISA identity maps =0A=
about to get started... =0A(XEN) PCI add device 00:00.0 =0A(XEN) PCI add de=
vice 00:01.0 =0A(XEN) PCI add device 00:03.0 =0A(XEN) PCI add device 00:07.=
0 =0A(XEN) PCI add device 00:09.0 =0A(XEN) PCI add device 00:14.0 =0A(XEN) =
PCI add device 00:14.1 =0A(XEN) PCI add device 00:14.2 =0A(XEN) PCI add dev=
ice 00:1a.0 =0A(XEN) PCI add device 00:1a.1 =0A(XEN) PCI add device 00:1a.7=
 =0A(XEN) PCI add device 00:1c.0 =0A(XEN) PCI add device 00:1d.0 =0A(XEN) P=
CI add device 00:1d.1 =0A(XEN) PCI add device 00:1d.7 =0A(XEN) PCI add devi=
ce 00:1e.0 =0A(XEN) PCI add device 00:1f.0 =0A(XEN) PCI add device 00:1f.2 =
=0A(XEN) PCI add device 01:00.0 =0A(XEN) PCI add device 01:00.1 =0A(XEN) PC=
I add device 02:00.0 =0A(XEN) PCI add device 02:00.1 =0A(XEN) PCI add devic=
e 03:00.0 =0A(XEN) PCI add device 06:03.0 =0A(XEN) cpuid.MWAIT[.eax=3D40, .=
ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to ent=
er C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D11=
20] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait wi=
ll be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .e=
cx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state=
 =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN)=
 Monitor-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used t=
o enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=
=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XEN) cp=
uid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwa=
it will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D4=
0, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 =
state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A=
(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.e=
ax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be u=
sed to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3,=
 .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XE=
N) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monito=
r-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .eb=
x=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter=
 C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120=
] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWA=
IT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will=
 be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =
=0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) =
Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D4=
0, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to=
 enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=
=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cp=
uid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwa=
it will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D4=
0, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 =
state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A=
(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.e=
ax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be u=
sed to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3,=
 .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XE=
N) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monito=
r-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .eb=
x=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter=
 C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120=
] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWA=
IT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will=
 be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =
=0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) =
Monitor-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D4=
0, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to=
 enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=
=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XEN) cp=
uid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwa=
it will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D4=
0, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 =
state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A=
(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.e=
ax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be u=
sed to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3,=
 .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XE=
N) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monito=
r-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .eb=
x=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter=
 C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120=
] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =0A(XEN) cpuid.MWA=
IT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will=
 be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-1 state =
=0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) =
Monitor-Mwait will be used to enter C-3 state =0A(XEN) cpuid.MWAIT[.eax=3D4=
0, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to=
 enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=
=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 state =0A(XEN) cp=
uid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwa=
it will be used to enter C-1 state =0A(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D4=
0, .ecx=3D3, .edx=3D1120] =0A(XEN) Monitor-Mwait will be used to enter C-3 =
state =0A(XEN) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns16550=
'. =0A(XEN) irq.c:1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'. =
=0A(XEN) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns16550'. =0A=
(XEN) irq.c:1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'. =0A(XE=
N) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns16550'. =0A(XEN) =
irq.c:1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'. =0A(XEN) irq=
.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns16550'. =0A(XEN) irq.c:=
1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'. =0A=0A=0A=0A=0A=0A=
ERROR: Unable to locate IOAPIC for GSI 9=0AERROR: Unable to locate IOAPIC f=
or GSI 9=0AERROR: Unable to locate IOAPIC for GSI 2=0Aregistering netback
--2014727138-887952032-1321571985=:18412
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

<html><body><div style=3D"color:#000; background-color:#fff; font-family:ti=
mes new roman, new york, times, serif;font-size:12pt"><div> </div>I've noti=
ced the GSI errors while booting XEN 4.1.1-3 and 4.1.2. I believe they stem=
 from the overides at boot. Is there a way to remove the errors or another =
option that needs to be passed at boot? The system boots and seems to run. =
<br><div> </div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;"><span style=3D"white-space: =
pre;"> __  __            _  _    _   _   _____      _  __   </span>=0A</fon=
t>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-botto=
m: 0in;">=0A<font style=3D"font-size: 12pt;"> \ \/ /___ _ __   | || |  / | =
/ | |___ /  ___| |/ /_  </font>=0A=0A</div><div style=3D"text-align: left; =
margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;"> =
 \  // _ \ '_ \  | || |_ | | | |__ |_ \ / _ \ | '_ \ </font>=0A=0A</div><di=
v style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font=
 style=3D"font-size: 12pt;">  /  \  __/ | | | |__   _|| |_| |__|__) |  __/ =
| (_) |</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; =
margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=3D"=
white-space: pre;"><br> /_/\_\___|_| |_|    |_|(_)_(_)_| |____(_)___|_|\___=
/ </span>=0A</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span styl=
e=3D"white-space: pre;"><br></span>=0A</font>=0A=0A</div><div style=3D"text=
-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-=
size: 12pt;">(XEN) Xen version 4.1.1 (root@(none)) (gcc version 4.4.4 20100=
726 (Red Hat 4.4.4-13) (GCC) ) Thu Aug 25 14:35:46 EDT 2011</font>=0A=0A</d=
iv><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Latest ChangeSet: unavailable</fo=
nt>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bott=
om: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Bootloader: GNU GRUB 0.=
97</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Command line: log=
lvl=3Dall =0Aguest_loglvl=3Dall dom0_max_vcpus=3D2 dom0_vcpus_pin dom0_mem=
=3D2048M =0Aconsole=3Dtty0 console=3Dcom1 com1=3D38400,8n1</font>=0A=0A</di=
v><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A=
<font style=3D"font-size: 12pt;">(XEN) Video information:</font>=0A=0A</div=
><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<=
font style=3D"font-size: 12pt;">(XEN)  VGA is text mode 80x25, font 8x16</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  VBE/DDC methods: none=
; EDID transfer time: 0 seconds</font>=0A=0A</div><div style=3D"text-align:=
 left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 1=
2pt;">(XEN)  EDID info not retrieved because no DDC retrieval method detect=
ed</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Disc information:=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  Found 1 MBR signat=
ures</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; mar=
gin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  Found 1 EDD in=
formation structures</font>=0A=0A</div><div style=3D"text-align: left; marg=
in-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)=
 Xen-e820 RAM map:</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  =
0000000000000000 - 00000000000a0000 (usable)</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN)  0000000000100000 - 00000000cf379000 (usable)</=
font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bo=
ttom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  00000000cf379000 - 0=
0000000cf38f000 (reserved)</font>=0A=0A</div><div style=3D"text-align: left=
; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;"=
>(XEN)  00000000cf38f000 - 00000000cf3ce000 (ACPI data)</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN)  00000000cf3ce000 - 00000000d0000000 (r=
eserved)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in;=
 margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  00000000e0=
000000 - 00000000f0000000 (reserved)</font>=0A=0A</div><div style=3D"text-a=
lign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-si=
ze: 12pt;">(XEN)  00000000fe000000 - 0000000100000000 (reserved)</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN)  0000000100000000 - 000000083=
0000000 (usable)</font>=0A=0A</div><div style=3D"text-align: left; margin-t=
op: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACP=
I: RSDP 000F11A0, 0024 (r2 DELL  )</font>=0A=0A</div><div style=3D"text-ali=
gn: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size=
: 12pt;">(XEN) ACPI Warning (tbutils-0455): BIOS XSDT has NULL entry, using=
 RSDT [20070126]</font>=0A=0A</div><div style=3D"text-align: left; margin-t=
op: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span =
style=3D"white-space: pre;"><br>(XEN) ACPI: RSDT 000F11C4, 0060 (r1 DELL   =
PE_SC3          1 DELL        1)</span>=0A</font>=0A=0A</div><div style=3D"=
text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"f=
ont-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN) ACPI: FACP =
CF3B3400, 0074 (r1 DELL   PE_SC3          1 DELL        1)</span>=0A</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=3D"white-space: p=
re;"><br>(XEN) ACPI: DSDT CF38F000, 3D72 (r1 DELL   PE_SC3          1 INTL =
20050624)</span>=0A</font>=0A=0A</div><div style=3D"text-align: left; margi=
n-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) =
ACPI: FACS CF3B6000, 0040</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
=0A<span style=3D"white-space: pre;"><br>(XEN) ACPI: APIC CF3B3478, 015E (r=
1 DELL   PE_SC3          1 DELL        1)</span>=0A</font>=0A=0A</div><div =
style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font s=
tyle=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN) AC=
PI: SPCR CF3B35D8, 0050 (r1 DELL   PE_SC3          1 DELL        1)</span>=
=0A</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; marg=
in-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=3D"whit=
e-space: pre;"><br>(XEN) ACPI: HPET CF3B362C, 0038 (r1 DELL   PE_SC3       =
   1 DELL        1)</span>=0A</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">=0A<span style=3D"white-space: pre;"><br>(XEN) ACPI: DMAR CF3B3668, 01A=
8 (r1 DELL   PE_SC3          1 DELL        1)</span>=0A</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN=
) ACPI: MCFG CF3B38C4, 003C (r1 DELL   PE_SC3          1 DELL        1)</sp=
an>=0A</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; m=
argin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=3D"w=
hite-space: pre;"><br>(XEN) ACPI: WD__ CF3B3904, 0134 (r1 DELL   PE_SC3    =
      1 DELL        1)</span>=0A</font>=0A=0A</div><div style=3D"text-align=
: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: =
12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN) ACPI: SLIC CF3B3A3C, =
0176 (r1 DELL   PE_SC3          1 DELL        1)</span>=0A</font>=0A=0A</di=
v><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A=
<font style=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(=
XEN) ACPI: ERST CF392EF4, 0270 (r1 DELL   PE_SC3          1 DELL        1)<=
/span>=0A</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=
=3D"white-space: pre;"><br>(XEN) ACPI: HEST CF393164, 03A8 (r1 DELL   PE_SC=
3          1 DELL        1)</span>=0A</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN) ACPI: BERT CF392=
D74, 0030 (r1 DELL   PE_SC3          1 DELL        1)</span>=0A</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;=
"><br>(XEN) ACPI: EINJ CF392DA4, 0150 (r1 DELL   PE_SC3          1 DELL    =
    1)</span>=0A</font>=0A=0A</div><div style=3D"text-align: left; margin-t=
op: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACP=
I Error (tbutils-0280): Null physical address for ACPI table [&lt;NULL&gt;]=
 [20070126]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=0A<span style=
=3D"white-space: pre;"><br>(XEN) ACPI: TCPA CF3B3BC0, 0064 (r2 DELL   PE_SC=
3          1 DELL        1)</span>=0A</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) ACPI: SSDT CF3B7000, 7E9C (r1  INTEL PPM RCM  80000001 IN=
TL 20061109)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) System =
RAM: 32755MB (33541220kB)</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
(XEN) No NUMA configuration found</font>=0A=0A</div><div style=3D"text-alig=
n: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size:=
 12pt;">(XEN) Faking a node at 0000000000000000-0000000830000000</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) Domain heap initialised</font=
>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom=
: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) found SMP MP-table at 000=
fe710</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; ma=
rgin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) DMI 2.6 presen=
t.</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Using APIC driver=
 default</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in;=
 margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: PM-Ti=
mer IO Port: 0x808</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) A=
CPI: ACPI SLEEP INFO: pm1x_cnt[804,0], pm1x_evt[800,0]</font>=0A=0A</div><d=
iv style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fon=
t style=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN)=
 ACPI:                  wakeup_vec[cf3b600c], vec_size[20]</span>=0A</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: Local APIC address 0=
xfee00000</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPI=
C (acpi_id[0x01] lapic_id[0x20] enabled)</font>=0A=0A</div><div style=3D"te=
xt-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fon=
t-size: 12pt;">(XEN) Processor #32 6:12 APIC version 21</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x02] lapic_id[0x0=
0] enabled)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processo=
r #0 6:12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
(XEN) ACPI: LAPIC (acpi_id[0x03] lapic_id[0x22] enabled)</font>=0A=0A</div>=
<div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<f=
ont style=3D"font-size: 12pt;">(XEN) Processor #34 6:12 APIC version 21</fo=
nt>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bott=
om: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x=
04] lapic_id[0x02] enabled)</font>=0A=0A</div><div style=3D"text-align: lef=
t; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;=
">(XEN) Processor #2 6:12 APIC version 21</font>=0A=0A</div><div style=3D"t=
ext-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fo=
nt-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x05] lapic_id[0x24] enabled)</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor #36 6:12 API=
C version 21</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: L=
APIC (acpi_id[0x06] lapic_id[0x04] enabled)</font>=0A=0A</div><div style=3D=
"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"=
font-size: 12pt;">(XEN) Processor #4 6:12 APIC version 21</font>=0A=0A</div=
><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<=
font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x07] lapic_id[0=
x30] enabled)</font>=0A=0A</div><div style=3D"text-align: left; margin-top:=
 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Proces=
sor #48 6:12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: le=
ft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt=
;">(XEN) ACPI: LAPIC (acpi_id[0x08] lapic_id[0x10] enabled)</font>=0A=0A</d=
iv><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Processor #16 6:12 APIC version 2=
1</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin=
-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_=
id[0x09] lapic_id[0x32] enabled)</font>=0A=0A</div><div style=3D"text-align=
: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: =
12pt;">(XEN) Processor #50 6:12 APIC version 21</font>=0A=0A</div><div styl=
e=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x0a] lapic_id[0x12] enabl=
ed)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; marg=
in-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor #18 6:=
12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) A=
CPI: LAPIC (acpi_id[0x0b] lapic_id[0x34] enabled)</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Processor #52 6:12 APIC version 21</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x0c] la=
pic_id[0x14] enabled)</font>=0A=0A</div><div style=3D"text-align: left; mar=
gin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN=
) Processor #20 6:12 APIC version 21</font>=0A=0A</div><div style=3D"text-a=
lign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-si=
ze: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x0d] lapic_id[0x21] enabled)</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor #33 6:12 APIC ve=
rsion 21</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in;=
 margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC=
 (acpi_id[0x0e] lapic_id[0x01] enabled)</font>=0A=0A</div><div style=3D"tex=
t-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font=
-size: 12pt;">(XEN) Processor #1 6:12 APIC version 21</font>=0A=0A</div><di=
v style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font=
 style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x0f] lapic_id[0x23]=
 enabled)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor =
#35 6:12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: left; =
margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(=
XEN) ACPI: LAPIC (acpi_id[0x10] lapic_id[0x03] enabled)</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) Processor #3 6:12 APIC version 21</font=
>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom=
: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x11=
] lapic_id[0x25] enabled)</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
(XEN) Processor #37 6:12 APIC version 21</font>=0A=0A</div><div style=3D"te=
xt-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fon=
t-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x12] lapic_id[0x05] enabled)</fo=
nt>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bott=
om: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor #5 6:12 APIC =
version 21</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0i=
n; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAP=
IC (acpi_id[0x13] lapic_id[0x31] enabled)</font>=0A=0A</div><div style=3D"t=
ext-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fo=
nt-size: 12pt;">(XEN) Processor #49 6:12 APIC version 21</font>=0A=0A</div>=
<div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<f=
ont style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x14] lapic_id[0x=
11] enabled)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Process=
or #17 6:12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: lef=
t; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;=
">(XEN) ACPI: LAPIC (acpi_id[0x15] lapic_id[0x33] enabled)</font>=0A=0A</di=
v><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A=
<font style=3D"font-size: 12pt;">(XEN) Processor #51 6:12 APIC version 21</=
font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bo=
ttom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[=
0x16] lapic_id[0x13] enabled)</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Processor #19 6:12 APIC version 21</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x17] lapic_id[0x35] enabl=
ed)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; marg=
in-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Processor #53 6:=
12 APIC version 21</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) A=
CPI: LAPIC (acpi_id[0x18] lapic_id[0x15] enabled)</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Processor #21 6:12 APIC version 21</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x19] la=
pic_id[0xff] disabled)</font>=0A=0A</div><div style=3D"text-align: left; ma=
rgin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XE=
N) ACPI: LAPIC (acpi_id[0x1a] lapic_id[0xff] disabled)</font>=0A=0A</div><d=
iv style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fon=
t style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x1b] lapic_id[0xff=
] disabled)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LA=
PIC (acpi_id[0x1c] lapic_id[0xff] disabled)</font>=0A=0A</div><div style=3D=
"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"=
font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x1d] lapic_id[0xff] disabled)=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_i=
d[0x1e] lapic_id[0xff] disabled)</font>=0A=0A</div><div style=3D"text-align=
: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: =
12pt;">(XEN) ACPI: LAPIC (acpi_id[0x1f] lapic_id[0xff] disabled)</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: LAPIC (acpi_id[0x20] la=
pic_id[0xff] disabled)</font>=0A=0A</div><div style=3D"text-align: left; ma=
rgin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XE=
N) ACPI: LAPIC_NMI (acpi_id[0xff] high edge lint[0x1])</font>=0A=0A</div><d=
iv style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fon=
t style=3D"font-size: 12pt;">(XEN) Overriding APIC driver with bigsmp</font=
>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom=
: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: IOAPIC (id[0x00] ad=
dress[0xfec00000] gsi_base[0])</font>=0A=0A</div><div style=3D"text-align: =
left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12=
pt;">(XEN) IOAPIC[0]: apic_id 0, version 32, address 0xfec00000, GSI 0-23</=
font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bo=
ttom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: IOAPIC (id[0x01=
] address[0xfec80000] gsi_base[32])</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) IOAPIC[1]: apic_id 1, version 32, address 0xfec80000, GSI 3=
2-55</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; mar=
gin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: INT_SRC_O=
VR (bus 0 bus_irq 0 global_irq 2 dfl dfl)</font>=0A=0A</div><div style=3D"t=
ext-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fo=
nt-size: 12pt;">(XEN) ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high =
level)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; m=
argin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: IRQ0 us=
ed by override.</font>=0A=0A</div><div style=3D"text-align: left; margin-to=
p: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ACPI=
: IRQ2 used by override.</font>=0A=0A</div><div style=3D"text-align: left; =
margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(=
XEN) ACPI: IRQ9 used by override.</font>=0A=0A</div><div style=3D"text-alig=
n: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size:=
 12pt;">(XEN) Enabling APIC mode:  Phys.  Using 2 I/O APICs</font>=0A=0A</d=
iv><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) ACPI: HPET id: 0x8086a301 base: 0=
xfed00000</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI: MCFG =
configuration 0: base e0000000 segment 0 buses 0 - 255</font>=0A=0A</div><d=
iv style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fon=
t style=3D"font-size: 12pt;">(XEN) PCI: MCFG area at e0000000 reserved in E=
820</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; marg=
in-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) ERST table is in=
valid</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; ma=
rgin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Using ACPI (MA=
DT) for SMP configuration information</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) IRQ limits: 55 GSI, 4569 MSI/MSI-X</font>=0A=0A</div><div=
 style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font =
style=3D"font-size: 12pt;">(XEN) Using scheduler: SMP Credit Scheduler (cre=
dit)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; mar=
gin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Detected 3458.0=
97 MHz processor.</font>=0A=0A</div><div style=3D"text-align: left; margin-=
top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) In=
iting memory sharing.</font>=0A=0A</div><div style=3D"text-align: left; mar=
gin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN=
) mce_intel.c:1162: MCA Capability: BCAST 1 SER 0 CMCI 1 firstbank 0 extend=
ed MCE MSR 0</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Intel m=
achine check reporting enabled</font>=0A=0A</div><div style=3D"text-align: =
left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12=
pt;">(XEN) Intel VT-d Snoop Control enabled.</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) Intel VT-d Dom0 DMA Passthrough not enabled.</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Intel VT-d Queued Inva=
lidation enabled.</font>=0A=0A</div><div style=3D"text-align: left; margin-=
top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) In=
tel VT-d Interrupt Remapping enabled.</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Intel VT-d Shared EPT tables not enabled.</font>=0A=0A</d=
iv><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) I/O virtualisation enabled</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  - Dom0 mode: Relaxed</fon=
t>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-botto=
m: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Enabled directed EOI wit=
h ioapic_ack_old on!</font>=0A=0A</div><div style=3D"text-align: left; marg=
in-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)=
 ENABLING IO-APIC IRQs</font>=0A=0A</div><div style=3D"text-align: left; ma=
rgin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XE=
N)  -&gt; Using old ACK method</font>=0A=0A</div><div style=3D"text-align: =
left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12=
pt;">(XEN) ..TIMER: vector=3D0xF0 apic1=3D0 pin1=3D2 apic2=3D-1 pin2=3D-1</=
font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bo=
ttom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Platform timer is 14.=
318MHz HPET</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Defaulti=
ng to alternative key handling; send 'A' to switch to normal mode.</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">=EF=BF=BD(XEN) Allocated console=
 ring of 256 KiB.</font>=0A=0A</div><div style=3D"text-align: left; margin-=
top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) VM=
X: Supported advanced features:</font>=0A=0A</div><div style=3D"text-align:=
 left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 1=
2pt;">(XEN)  - APIC MMIO access virtualisation</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN)  - APIC TPR shadow</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN)  - Extended Page Tables (EPT)</font>=0A=0A</div=
><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<=
font style=3D"font-size: 12pt;">(XEN)  - Virtual-Processor Identifiers (VPI=
D)</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  - Virtual NMI</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  - MSR direct-access b=
itmap</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; ma=
rgin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  - Unrestricte=
d Guest</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; =
margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) EPT supports=
 1GB super page.</font>=0A=0A</div><div style=3D"text-align: left; margin-t=
op: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) EPT=
 supports 2MB super page.</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
(XEN) HVM: ASIDs enabled.</font>=0A=0A</div><div style=3D"text-align: left;=
 margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
(XEN) HVM: VMX enabled</font>=0A=0A</div><div style=3D"text-align: left; ma=
rgin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XE=
N) HVM: Hardware Assisted Paging detected.</font>=0A=0A</div><div style=3D"=
text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"f=
ont-size: 12pt;">(XEN) Brought up 24 CPUs</font>=0A=0A</div><div style=3D"t=
ext-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fo=
nt-size: 12pt;">(XEN) ACPI sleep modes: S3</font>=0A=0A</div><div style=3D"=
text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"f=
ont-size: 12pt;">(XEN) mcheck_poll: Machine check polling timer started.</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) *** LOADING DOMAIN 0 *=
**</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  Xen  kernel: 64-=
bit, lsb, compat32</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  =
Dom0 kernel: 64-bit, PAE, lsb, paddr 0x1000000 -&gt; 0x2744000</font>=0A=0A=
</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;"=
>=0A<font style=3D"font-size: 12pt;">(XEN) PHYSICAL MEMORY ARRANGEMENT:</fo=
nt>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bott=
om: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)  Dom0 alloc.:   0000000=
800000000-&gt;0000000804000000 (431348 pages to be allocated)</font>=0A=0A<=
/div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN)  Init. ramdisk: 000000081d4f4000-=
&gt;000000082ffffe00</font>=0A=0A</div><div style=3D"text-align: left; marg=
in-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)=
 VIRTUAL MEMORY ARRANGEMENT:</font>=0A=0A</div><div style=3D"text-align: le=
ft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt=
;">(XEN)  Loaded kernel: ffffffff81000000-&gt;ffffffff82744000</font>=0A=0A=
</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;"=
>=0A<font style=3D"font-size: 12pt;">(XEN)  Init. ramdisk: ffffffff82744000=
-&gt;ffffffff9524fe00</font>=0A=0A</div><div style=3D"text-align: left; mar=
gin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN=
)  Phys-Mach map: ffffffff95250000-&gt;ffffffff95650000</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN=
)  Start info:    ffffffff95650000-&gt;ffffffff956504b4</span>=0A</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN)  Page tables:   ffffffff95651=
000-&gt;ffffffff95700000</font>=0A=0A</div><div style=3D"text-align: left; =
margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">=
=0A<span style=3D"white-space: pre;"><br>(XEN)  Boot stack:    ffffffff9570=
0000-&gt;ffffffff95701000</span>=0A</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">=0A<span style=3D"white-space: pre;"><br>(XEN)  TOTAL:         ff=
ffffff80000000-&gt;ffffffff95800000</span>=0A</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN)  ENTRY ADDRESS: ffffffff8197a200</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Dom0 has maximum 2 VCPUs</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Scrubbing Free RAM: =0A...=
...........................................................................=
...........................................................................=
...........................................................................=
..........................................................................d=
one.</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; mar=
gin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Xen trace buffe=
rs: disabled</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Std. Lo=
glevel: All</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Guest Lo=
glevel: All</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) *** Seri=
al input -&gt; DOM0 (type 'CTRL-a' three times to switch input to Xen)</fon=
t>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-botto=
m: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Freed 228kB init memory.=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">mapping kernel into physi=
cal memory</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0i=
n; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">Xen: setup ISA =
identity maps</font>=0A=0A</div><div style=3D"text-align: left; margin-top:=
 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">about to get=
 started...</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add =
device 00:00.0</font>=0A=0A</div><div style=3D"text-align: left; margin-top=
: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI a=
dd device 00:01.0</font>=0A=0A</div><div style=3D"text-align: left; margin-=
top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PC=
I add device 00:03.0</font>=0A=0A</div><div style=3D"text-align: left; marg=
in-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN)=
 PCI add device 00:07.0</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) PCI add device 00:09.0</font>=0A=0A</div><div style=3D"text-align: left=
; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;"=
>(XEN) PCI add device 00:14.0</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) PCI add device 00:14.1</font>=0A=0A</div><div style=3D"text-align=
: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: =
12pt;">(XEN) PCI add device 00:14.2</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) PCI add device 00:1a.0</font>=0A=0A</div><div style=3D"text=
-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-=
size: 12pt;">(XEN) PCI add device 00:1a.1</font>=0A=0A</div><div style=3D"t=
ext-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fo=
nt-size: 12pt;">(XEN) PCI add device 00:1a.7</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) PCI add device 00:1c.0</font>=0A=0A</div><div s=
tyle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font st=
yle=3D"font-size: 12pt;">(XEN) PCI add device 00:1d.0</font>=0A=0A</div><di=
v style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font=
 style=3D"font-size: 12pt;">(XEN) PCI add device 00:1d.1</font>=0A=0A</div>=
<div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<f=
ont style=3D"font-size: 12pt;">(XEN) PCI add device 00:1d.7</font>=0A=0A</d=
iv><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 00:1e.0</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 00:1f.0</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 00:1f.2</fo=
nt>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bott=
om: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 01:00.0<=
/font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-b=
ottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 01:00=
.1</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device 02=
:00.0</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; ma=
rgin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add device=
 02:00.1</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in;=
 margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add dev=
ice 03:00.0</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0=
in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) PCI add =
device 06:03.0</font>=0A=0A</div><div style=3D"text-align: left; margin-top=
: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid=
.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div =
style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font s=
tyle=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 sta=
te</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margi=
n-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=
=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"te=
xt-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"fon=
t-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .eb=
x=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: =
left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12=
pt;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=0A</div>=
<div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<f=
ont style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-1 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-3 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-1 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-3 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-1 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-3 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-1 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-3 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-1 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-3 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-1 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-3 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-1 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-3 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-1 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-3 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-1 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</=
div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=
=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to ent=
er C-3 state</font>=0A=0A</div><div style=3D"text-align: left; margin-top: =
0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.M=
WAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div st=
yle=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font sty=
le=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be used to enter C-1 state=
</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-=
bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D=
40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-=
align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-s=
ize: 12pt;">(XEN) Monitor-Mwait will be used to enter C-3 state</font>=0A=
=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0i=
n;">=0A<font style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=
=3D40, .ecx=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: l=
eft; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12p=
t;">(XEN) Monitor-Mwait will be used to enter C-1 state</font>=0A=0A</div><=
div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<fo=
nt style=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=
=3D3, .edx=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin=
-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) M=
onitor-Mwait will be used to enter C-3 state</font>=0A=0A</div><div style=
=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .ed=
x=3D1120]</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in=
; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mw=
ait will be used to enter C-1 state</font>=0A=0A</div><div style=3D"text-al=
ign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-siz=
e: 12pt;">(XEN) cpuid.MWAIT[.eax=3D40, .ebx=3D40, .ecx=3D3, .edx=3D1120]</f=
ont>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bot=
tom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) Monitor-Mwait will be =
used to enter C-3 state</font>=0A=0A</div><div style=3D"text-align: left; m=
argin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(X=
EN) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns16550'.</font>=
=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; margin-bottom:=
 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) irq.c:1195:d0 Cannot bind =
IRQ 2 to guest. In use by 'cascade'.</font>=0A=0A</div><div style=3D"text-a=
lign: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-si=
ze: 12pt;">(XEN) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In use by 'ns165=
50'.</font>=0A=0A</div><div style=3D"text-align: left; margin-top: 0in; mar=
gin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) irq.c:1195:d0 C=
annot bind IRQ 2 to guest. In use by 'cascade'.</font>=0A=0A</div><div styl=
e=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A<font style=
=3D"font-size: 12pt;">(XEN) irq.c:1195:d0 Cannot bind IRQ 4 to guest. In us=
e by 'ns16550'.</font>=0A=0A</div><div style=3D"text-align: left; margin-to=
p: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;">(XEN) irq.=
c:1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'.</font>=0A=0A</di=
v><div style=3D"text-align: left; margin-top: 0in; margin-bottom: 0in;">=0A=
<font style=3D"font-size: 12pt;">(XEN) irq.c:1195:d0 Cannot bind IRQ 4 to g=
uest. In use by 'ns16550'.</font>=0A=0A</div><div style=3D"text-align: left=
; margin-top: 0in; margin-bottom: 0in;">=0A<font style=3D"font-size: 12pt;"=
>(XEN) irq.c:1195:d0 Cannot bind IRQ 2 to guest. In use by 'cascade'.</font=
>=0A</div>=0A <br><div><br></div><div><br></div><div><br></div><div><br></d=
iv><div>ERROR: Unable to locate IOAPIC for GSI 9</div><div>ERROR: Unable to=
 locate IOAPIC for GSI 9</div><div>ERROR: Unable to locate IOAPIC for GSI 2=
</div><div>registering netback<br><br></div></div></body></html>
--2014727138-887952032-1321571985=:18412--


--===============0010739811==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Xen-users mailing list
Xen-users@lists.xensource.com
http://lists.xensource.com/xen-users
--===============0010739811==--


From xen-devel-bounces@lists.xensource.com Thu Nov 17 23:39:37 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 17 Nov 2011 23:39:37 +0000
Received: from lists.colo.xensource.com ([70.42.241.110] helo=lists.xensource.com)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RRBYM-0002tk-QK
	for archives@lists.xen.org; Thu, 17 Nov 2011 23:39:37 +0000
Received: from localhost ([127.0.0.1] helo=lists.colo.xensource.com)
	by lists.xensource.com with esmtp (Exim 4.43)
	id 1RRBXy-0001HM-45; Thu, 17 Nov 2011 15:39:10 -0800
Received: from mail174.messagelabs.com ([85.158.138.51])
	by lists.xensource.com with esmtp (Exim 4.43) id 1RRBXl-0001Fj-NU
	for Xen-devel@lists.xensource.com; Thu, 17 Nov 2011 15:38:59 -0800
X-Env-Sender: mukesh.rathor@oracle.com
X-Msg-Ref: server-2.tower-174.messagelabs.com!1321573131!2012017!1
X-Originating-IP: [141.146.126.227]
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 14120 invoked from network); 17 Nov 2011 23:38:53 -0000
Received: from acsinet15.oracle.com (HELO acsinet15.oracle.com)
	(141.146.126.227)
	by server-2.tower-174.messagelabs.com with DHE-RSA-AES256-SHA encrypted
	SMTP; 17 Nov 2011 23:38:53 -0000
Received: from ucsinet21.oracle.com (ucsinet21.oracle.com [156.151.31.93])
	by acsinet15.oracle.com (Switch-3.4.4/Switch-3.4.4) with ESMTP id
	pAHNcl4b014166
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK);
	Thu, 17 Nov 2011 23:38:47 GMT
Received: from acsmt357.oracle.com (acsmt357.oracle.com [141.146.40.157])
	by ucsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id
	pAHNcjWY015860
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO);
	Thu, 17 Nov 2011 23:38:46 GMT
Received: from abhmt101.oracle.com (abhmt101.oracle.com [141.146.116.53])
	by acsmt357.oracle.com (8.12.11.20060308/8.12.11) with ESMTP id
	pAHNceEY005255; Thu, 17 Nov 2011 17:38:40 -0600
Received: from mantra.us.oracle.com (/130.35.68.95)
	by default (Oracle Beehive Gateway v4.0)
	with ESMTP ; Thu, 17 Nov 2011 15:38:39 -0800
Date: Thu, 17 Nov 2011 15:38:38 -0800
From: Mukesh Rathor <mukesh.rathor@oracle.com>
To: "Xen-devel@lists.xensource.com" <Xen-devel@lists.xensource.com>
Subject: Re: [Xen-devel] HYBRID: PV in HVM container
Message-ID: <20111117153838.04e15aa9@mantra.us.oracle.com>
In-Reply-To: <20110727185828.55099372@mantra.us.oracle.com>
References: <20110627122404.23d2d0ce@mantra.us.oracle.com>
	<20110630185431.3ea308c6@mantra.us.oracle.com>
	<20110708185301.4b040a21@mantra.us.oracle.com>
	<20110727185828.55099372@mantra.us.oracle.com>
Organization: Oracle Corporation
X-Mailer: Claws Mail 3.7.6 (GTK+ 2.18.9; x86_64-redhat-linux-gnu)
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="MP_/R.1sMt_LjPbCVVbgRW8Pwbf"
X-Source-IP: ucsinet21.oracle.com [156.151.31.93]
X-CT-RefId: str=0001.0A090205.4EC59B08.00B0,ss=1,re=-15.000,fgs=0
Cc: Keir Fraser <keir.xen@gmail.com>, Ian Campbell <Ian.Campbell@citrix.com>
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.5
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com

--MP_/R.1sMt_LjPbCVVbgRW8Pwbf
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Alright, got hybrid with EPT numbers in now from my prototype, it needs
some perf work.. 

Attaching the diffs from my prototype. Linux: 2.6.39. Xen 4.0.2.


Processor, Processes - times in microseconds - smaller is better
------------------------------------------------------------------------------
Host                 OS  Mhz null null      open slct sig  sig  fork exec sh  
                             call  I/O stat clos TCP  inst hndl proc proc proc
--------- ------------- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
PV        Linux 2.6.39f 2639 0.65 0.88 2.14 4.59 3.77 0.79 3.62 535. 1294 3308
Hybrid    Linux 2.6.39f 2639 0.13 0.21 0.89 1.96 3.08 0.24 1.10 529. 1294 3246
HVM       Linux 2.6.39f 2639 0.12 0.21 0.64 1.76 3.04 0.24 3.37 113. 354. 1324
Baremetal Linux 2.6.39+ 2649 0.13 0.23 0.74 1.93 3.46 0.28 1.58 127. 386. 1434
HYB-EPT   Linux 2.6.39f 2639 0.13 0.21 0.68 1.95 3.04 0.25 3.09 145. 452. 1542


Basic integer operations - times in nanoseconds - smaller is better
-------------------------------------------------------------------
Host                 OS  intgr intgr  intgr  intgr  intgr  
                          bit   add    mul    div    mod   
--------- ------------- ------ ------ ------ ------ ------ 
PV        Linux 2.6.39f 0.3800 0.0100 0.1700 9.1000 9.0400
Hybrid    Linux 2.6.39f 0.3800 0.0100 0.1700 9.1100 9.0300
HVM       Linux 2.6.39f 0.3800 0.0100 0.1700 9.1100 9.0600
Baremetal Linux 2.6.39+ 0.3800 0.0100 0.1700 9.0600 8.9800
HYB-EPT   Linux 2.6.39f 0.3800 0.0100 0.1700 9.1200 9.0500


Basic float operations - times in nanoseconds - smaller is better
-----------------------------------------------------------------
Host                 OS  float  float  float  float
                         add    mul    div    bogo
--------- ------------- ------ ------ ------ ------ 
PV        Linux 2.6.39f 1.1300 1.5200 5.6200 5.2900
Hybrid    Linux 2.6.39f 1.1300 1.5200 5.6300 5.2900
HVM       Linux 2.6.39f 1.1400 1.5200 5.6300 5.3000
Baremetal Linux 2.6.39+ 1.1300 1.5100 5.6000 5.2700
HYB-EPT   Linux 2.6.39f 1.1400 1.5200 5.6300 5.3000


Basic double operations - times in nanoseconds - smaller is better
------------------------------------------------------------------
Host                 OS  double double double double
                         add    mul    div    bogo
--------- ------------- ------  ------ ------ ------ 
PV        Linux 2.6.39f 1.1300 1.9000 8.6400 8.3200
Hybrid    Linux 2.6.39f 1.1400 1.9000 8.6600 8.3200
HVM       Linux 2.6.39f 1.1400 1.9000 8.6600 8.3300
Baremetal Linux 2.6.39+ 1.1300 1.8900 8.6100 8.2800
HYB-EPT   Linux 2.6.39f 1.1400 1.9000 8.6600 8.3300


Context switching - times in microseconds - smaller is better
-------------------------------------------------------------------------
Host                 OS  2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K
                         ctxsw  ctxsw  ctxsw ctxsw  ctxsw   ctxsw   ctxsw
--------- ------------- ------ ------ ------ ------ ------ ------- -------
PV        Linux 2.6.39f 5.2800 5.7600 6.3600 6.3200 7.3600 6.69000 7.46000
Hybrid    Linux 2.6.39f 4.9200 4.9300 5.2200 5.7600 6.9600 6.12000 7.31000
HVM       Linux 2.6.39f 1.3100 1.2200 1.6200 1.9200 3.2600 2.23000 3.48000
Baremetal Linux 2.6.39+ 1.5500 1.4100 2.0600 2.2500 3.3900 2.44000 3.38000
HYB-EPT   Linux 2.6.39f 3.2000 3.6100 4.1700 4.3600 6.1200 4.81000 6.20000


*Local* Communication latencies in microseconds - smaller is better
---------------------------------------------------------------------
Host                 OS 2p/0K  Pipe AF     UDP  RPC/   TCP  RPC/ TCP
                        ctxsw       UNIX         UDP         TCP conn
--------- ------------- ----- ----- ---- ----- ----- ----- ----- ----
PV        Linux 2.6.39f 5.280  16.6 21.3  25.9  33.7  34.7  41.8  87.
Hybrid    Linux 2.6.39f 4.920  11.2 14.4  19.6  26.1  27.5  32.9  71.
HVM       Linux 2.6.39f 1.310 4.416 6.15 9.386  14.8  15.8  20.1  45.
Baremetal Linux 2.6.39+ 1.550 4.625 7.34  14.3  19.8  21.4  26.4  66.
HYB-EPT   Linux 2.6.39f 3.200 8.669 15.3  17.5  23.5  25.1  30.4  66.


File & VM system latencies in microseconds - smaller is better
-------------------------------------------------------------------------------
Host                 OS   0K File      10K File     Mmap    Prot   Page   100fd
                        Create Delete Create Delete Latency Fault  Fault  selct
--------- ------------- ------ ------ ------ ------ ------- ----- ------- -----
PV        Linux 2.6.39f                               24.0K 0.746 3.55870 2.184
Hybrid    Linux 2.6.39f                               24.6K 0.238 4.00100 1.480
HVM       Linux 2.6.39f                              4716.0 0.202 0.96600 1.468
Baremetal Linux 2.6.39+                              6898.0 0.325 0.93610 1.620
HYB-EPT   Linux 2.6.39f                              5321.0 0.347 1.19510 1.480


*Local* Communication bandwidths in MB/s - bigger is better
-----------------------------------------------------------------------------
Host                OS  Pipe AF    TCP  File   Mmap  Bcopy  Bcopy  Mem   Mem
                             UNIX      reread reread (libc) (hand) read write
--------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- -----
PV        Linux 2.6.39f 1661 2081 1041 3293.3 5528.3 3106.6 2800.0 4472 5633.
Hybrid    Linux 2.6.39f 1974 2450 1183 3481.5 5529.6 3114.9 2786.6 4470 5672.
HVM       Linux 2.6.39f 3232 2929 1622 3541.3 5527.5 3077.1 2765.6 4453 5634.
Baremetal Linux 2.6.39+ 3320 2800 1666 3523.6 5578.9 3147.0 2841.6 4541 5752.
HYB-EPT   Linux 2.6.39f 2104 2480 1231 3451.5 5503.4 3067.7 2751.0 4438 5636.


Memory latencies in nanoseconds - smaller is better
    (WARNING - may not be correct, check graphs)
------------------------------------------------------------------------------
Host                 OS   Mhz   L1 $   L2 $    Main mem    Rand mem    Guesses
--------- -------------   ---   ----   ----    --------    --------    -------
PV        Linux 2.6.39f  2639 1.5160 5.9170   29.7        97.5
Hybrid    Linux 2.6.39f  2639 1.5170 7.5000   29.7        97.4
HVM       Linux 2.6.39f  2639 1.5190 4.0210   29.8       105.4
Baremetal Linux 2.6.39+  2649 1.5090 3.8370   29.2        78.0
HYB-EPT   Linux 2.6.39f  2639 1.5180 4.0060   29.9       109.9


thanks,
Mukesh


On Wed, 27 Jul 2011 18:58:28 -0700
Mukesh Rathor <mukesh.rathor@oracle.com> wrote:

> Hi folks,
> 
> Well, I did some benchmarking and found interesting results. Following
> runs are on a westmere with 2 sockets and 10GB RAM.  Xen was booted
> with maxcpus=2 and entire RAM. All guests were started with 1vcpu and
> 2GB RAM. dom0 started with 1 vcpu and 704MB. Baremetal was booted
> with 2GB and 1 cpu.  HVM guest has EPT enabled. HT is on.
> 
> So, unless the NUMA'ness interfered with results (using some memory
> on remote socket), it appears HVM does very well. To the point that it
> seems a hybrid is not going to be worth it. I am currently running
> tests on a single socket system just to be sure.
> 
> I am attaching my diff's in case any one wants to see what I did. I
> used xen 4.0.2 and linux 2.6.39. 
> 
> thanks,
> Mukesh
> 
>                  L M B E N C H  3 . 0   S U M M A R Y
> 
> Processor, Processes - times in microseconds - smaller is better
> ------------------------------------------------------------------------------

--MP_/R.1sMt_LjPbCVVbgRW8Pwbf
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=lin.diff

diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 615e188..7791d31 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -1,7 +1,7 @@
 menu "Kernel hacking"
 
 config TRACE_IRQFLAGS_SUPPORT
-	def_bool y
+	def_bool n
 
 source "lib/Kconfig.debug"
 
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 91f3e08..bdd7022 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -238,7 +238,8 @@ extern const char * const x86_power_flags[32];
 #define cpu_has_fpu		boot_cpu_has(X86_FEATURE_FPU)
 #define cpu_has_vme		boot_cpu_has(X86_FEATURE_VME)
 #define cpu_has_de		boot_cpu_has(X86_FEATURE_DE)
-#define cpu_has_pse		boot_cpu_has(X86_FEATURE_PSE)
+#define cpu_has_pse		0
+/* #define cpu_has_pse		boot_cpu_has(X86_FEATURE_PSE) */
 #define cpu_has_tsc		boot_cpu_has(X86_FEATURE_TSC)
 #define cpu_has_pae		boot_cpu_has(X86_FEATURE_PAE)
 #define cpu_has_pge		boot_cpu_has(X86_FEATURE_PGE)
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 7a15153..f0bbb51 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -49,6 +49,7 @@ extern const struct hypervisor_x86 *x86_hyper;
 extern const struct hypervisor_x86 x86_hyper_vmware;
 extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
 extern const struct hypervisor_x86 x86_hyper_xen_hvm;
+extern const struct hypervisor_x86 x86_hyper_xen_hybrid;
 
 static inline bool hypervisor_x2apic_available(void)
 {
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index 8095f86..5ec8dbb 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -37,6 +37,7 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] =
 #ifdef CONFIG_XEN_PVHVM
 	&x86_hyper_xen_hvm,
 #endif
+        &x86_hyper_xen_hybrid,
 };
 
 const struct hypervisor_x86 *x86_hyper;
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c
index bd33620..89bfe86 100644
--- a/arch/x86/pci/direct.c
+++ b/arch/x86/pci/direct.c
@@ -282,6 +282,9 @@ int __init pci_direct_probe(void)
 {
 	struct resource *region, *region2;
 
+        if (xen_hybrid_domain())
+                return 0;
+
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
 	region = request_region(0xCF8, 8, "PCI conf1");
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index e3c6a06..53ceae0 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -110,7 +110,7 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement = 0;
 
 static void clamp_max_cpus(void)
 {
@@ -195,6 +195,13 @@ static void __init xen_banner(void)
 	printk(KERN_INFO "Xen version: %d.%d%s%s\n",
 	       version >> 16, version & 0xffff, extra.extraversion,
 	       xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
+
+        if (xen_hybrid_domain()) {
+	        printk(KERN_INFO "MUK: is MUK HYBRID domain....");
+		if (xen_feature(XENFEAT_auto_translated_physmap))
+                	printk(KERN_INFO "with EPT...");
+        	printk(KERN_INFO "\n");
+        }
 }
 
 static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
@@ -222,8 +229,10 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
 		maskebx = 0;
 		break;
 	}
-
-	asm(XEN_EMULATE_PREFIX "cpuid"
+        if (xen_hybrid_domain()) {
+                native_cpuid(ax, bx, cx, dx);
+        } else
+	        asm(XEN_EMULATE_PREFIX "cpuid"
 		: "=a" (*ax),
 		  "=b" (*bx),
 		  "=c" (*cx),
@@ -244,6 +253,7 @@ static __init void xen_init_cpuid_mask(void)
 		~((1 << X86_FEATURE_MCE)  |  /* disable MCE */
 		  (1 << X86_FEATURE_MCA)  |  /* disable MCA */
 		  (1 << X86_FEATURE_MTRR) |  /* disable MTRR */
+                  (1 << X86_FEATURE_PSE)  |  /* disable 2M pages */
 		  (1 << X86_FEATURE_ACC));   /* thermal monitoring */
 
 	if (!xen_initial_domain())
@@ -393,6 +403,10 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
 		make_lowmem_page_readonly(virt);
 	}
 
+        if (xen_hybrid_domain()) {
+                native_load_gdt(dtr);
+                return;
+        }
 	if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct)))
 		BUG();
 }
@@ -431,6 +445,10 @@ static __init void xen_load_gdt_boot(const struct desc_ptr *dtr)
 		frames[f] = mfn;
 	}
 
+        if (xen_hybrid_domain()) {
+                native_load_gdt(dtr);
+                return;
+        }
 	if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct)))
 		BUG();
 }
@@ -849,9 +867,11 @@ void xen_setup_shared_info(void)
 
 		HYPERVISOR_shared_info =
 			(struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
-	} else
+	} else {
 		HYPERVISOR_shared_info =
 			(struct shared_info *)__va(xen_start_info->shared_info);
+        	return;
+	}
 
 #ifndef CONFIG_SMP
 	/* In UP this is as good a place as any to set up shared info */
@@ -944,6 +964,71 @@ static const struct pv_init_ops xen_init_ops __initdata = {
 	.patch = xen_patch,
 };
 
+extern void native_iret(void);
+extern void native_irq_enable_sysexit(void);
+extern void native_usergs_sysret32(void);
+extern void native_usergs_sysret64(void);
+
+static const struct pv_cpu_ops xen_hybrid_cpu_ops __initdata = {
+	.cpuid = xen_cpuid,
+
+	.set_debugreg = xen_set_debugreg,
+	.get_debugreg = xen_get_debugreg,
+
+	.clts = xen_clts,
+
+	.read_cr0 = xen_read_cr0,
+	.write_cr0 = xen_write_cr0,
+
+	.read_cr4 = native_read_cr4,
+	.read_cr4_safe = native_read_cr4_safe,
+	.write_cr4 = native_write_cr4,
+
+	.wbinvd = native_wbinvd,
+
+	.read_msr = native_read_msr_safe,
+	.write_msr = native_write_msr_safe,
+	.read_tsc = native_read_tsc,
+	.read_pmc = native_read_pmc,
+
+	.iret = native_iret,
+	.irq_enable_sysexit = native_irq_enable_sysexit,
+#ifdef CONFIG_X86_64
+	.usergs_sysret32 = native_usergs_sysret32,
+	.usergs_sysret64 = native_usergs_sysret64,
+#endif
+
+	.load_tr_desc = native_load_tr_desc,
+	.set_ldt = native_set_ldt,
+	.load_gdt = native_load_gdt,
+	.load_idt = native_load_idt,
+	.load_tls = native_load_tls,
+#ifdef CONFIG_X86_64
+	.load_gs_index = native_load_gs_index,
+#endif
+
+	.alloc_ldt = paravirt_nop,
+	.free_ldt = paravirt_nop,
+
+	.store_gdt = native_store_gdt,
+	.store_idt = native_store_idt,
+	.store_tr = native_store_tr,
+
+	.write_ldt_entry = native_write_ldt_entry,
+	.write_gdt_entry = native_write_gdt_entry,
+	.write_idt_entry = native_write_idt_entry,
+	.load_sp0 = native_load_sp0,
+
+	.set_iopl_mask = native_set_iopl_mask,
+	.io_delay = xen_io_delay,
+
+	/* Xen takes care of %gs when switching to usermode for us */
+	.swapgs = native_swapgs,
+
+	.start_context_switch = paravirt_start_context_switch,
+	.end_context_switch = xen_end_context_switch,
+};
+
 static const struct pv_cpu_ops xen_cpu_ops __initdata = {
 	.cpuid = xen_cpuid,
 
@@ -1010,6 +1095,11 @@ static const struct pv_apic_ops xen_apic_ops __initdata = {
 #endif
 };
 
+static void __init xen_hybrid_override_autox_cpu_ops(void)
+{
+        pv_cpu_ops.cpuid = xen_cpuid;
+}
+
 static void xen_reboot(int reason)
 {
 	struct sched_shutdown r = { .reason = reason };
@@ -1071,6 +1161,10 @@ static const struct machine_ops __initdata xen_machine_ops = {
  */
 static void __init xen_setup_stackprotector(void)
 {
+        if (xen_hybrid_domain()) {
+                switch_to_new_gdt(0);
+                return;
+        }
 	pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot;
 	pv_cpu_ops.load_gdt = xen_load_gdt_boot;
 
@@ -1093,14 +1187,22 @@ asmlinkage void __init xen_start_kernel(void)
 
 	xen_domain_type = XEN_PV_DOMAIN;
 
+	xen_setup_features();
 	xen_setup_machphys_mapping();
 
 	/* Install Xen paravirt ops */
 	pv_info = xen_info;
 	pv_init_ops = xen_init_ops;
-	pv_cpu_ops = xen_cpu_ops;
 	pv_apic_ops = xen_apic_ops;
 
+        if (xen_hybrid_domain()) {
+	        if (xen_feature(XENFEAT_auto_translated_physmap))
+                        xen_hybrid_override_autox_cpu_ops();
+                else
+	        	pv_cpu_ops = xen_hybrid_cpu_ops;
+        } else
+	        pv_cpu_ops = xen_cpu_ops;
+
 	x86_init.resources.memory_setup = xen_memory_setup;
 	x86_init.oem.arch_setup = xen_arch_setup;
 	x86_init.oem.banner = xen_banner;
@@ -1129,7 +1231,6 @@ asmlinkage void __init xen_start_kernel(void)
 	/* Work out if we support NX */
 	x86_configure_nx();
 
-	xen_setup_features();
 
 	/* Get mfn list */
 	if (!xen_feature(XENFEAT_auto_translated_physmap))
@@ -1214,10 +1315,12 @@ asmlinkage void __init xen_start_kernel(void)
 	 * were early_cpu_init (run before ->arch_setup()) calls early_amd_init
 	 * which pokes 0xcf8 port.
 	 */
-	set_iopl.iopl = 1;
-	rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
-	if (rc != 0)
-		xen_raw_printk("physdev_op failed %d\n", rc);
+        if (!xen_hybrid_domain()) {
+	        set_iopl.iopl = 1;
+	        rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+	        if (rc != 0)
+		        xen_raw_printk("physdev_op failed %d\n", rc);
+        }
 
 #ifdef CONFIG_X86_32
 	/* set up basic CPUID stuff */
@@ -1388,3 +1491,29 @@ const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
 };
 EXPORT_SYMBOL(x86_hyper_xen_hvm);
 #endif
+
+static bool __init xen_hybrid_platform_detect(void)
+{
+        return (xen_hybrid_domain());
+}
+
+
+const int xen_hybrid_rsvd_top_frames = 48;    /* 32 for grant + future */
+static void __init xen_hybrid_guest_init(void)
+{
+        if (xen_feature(XENFEAT_hvm_callback_vector))
+                xen_have_vector_callback = 1;
+
+	/* xen_hvm_smp_init(); */   /* <======================== */
+
+        /* adjust iomem_resource set in setup_arch() and reserve some frames
+         * for grant table etc for us */
+        iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1
+                             - xen_hybrid_rsvd_top_frames;
+}
+
+const __refconst struct hypervisor_x86 x86_hyper_xen_hybrid = {
+	.name			= "Xen Hybrid",
+	.detect			= xen_hybrid_platform_detect,
+	.init_platform		= xen_hybrid_guest_init,
+};
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 6a6fe89..1a161db 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -100,6 +100,9 @@ PV_CALLEE_SAVE_REGS_THUNK(xen_irq_enable);
 
 static void xen_safe_halt(void)
 {
+        if (xen_hybrid_domain())
+                local_irq_enable();
+
 	/* Blocking includes an implicit local_irq_enable(). */
 	if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
 		BUG();
@@ -113,6 +116,19 @@ static void xen_halt(void)
 		xen_safe_halt();
 }
 
+static const struct pv_irq_ops xen_hybrid_irq_ops __initdata = {
+        .save_fl = __PV_IS_CALLEE_SAVE(native_save_fl),
+        .restore_fl = __PV_IS_CALLEE_SAVE(native_restore_fl),
+        .irq_disable = __PV_IS_CALLEE_SAVE(native_irq_disable),
+        .irq_enable = __PV_IS_CALLEE_SAVE(native_irq_enable),
+
+	.safe_halt = xen_safe_halt,
+	.halt = xen_halt,
+#ifdef CONFIG_X86_64
+	.adjust_exception_frame = paravirt_nop,
+#endif
+};
+
 static const struct pv_irq_ops xen_irq_ops __initdata = {
 	.save_fl = PV_CALLEE_SAVE(xen_save_fl),
 	.restore_fl = PV_CALLEE_SAVE(xen_restore_fl),
@@ -128,6 +144,9 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
 
 void __init xen_init_irq_ops(void)
 {
-	pv_irq_ops = xen_irq_ops;
+        if (xen_hybrid_domain())
+	        pv_irq_ops = xen_hybrid_irq_ops;
+        else
+	        pv_irq_ops = xen_irq_ops;
 	x86_init.irqs.intr_init = xen_init_IRQ;
 }
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index f298bd7..2c50554 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1294,6 +1294,10 @@ static void xen_post_allocator_init(void);
 static __init void xen_pagetable_setup_done(pgd_t *base)
 {
 	xen_setup_shared_info();
+
+        if (xen_feature(XENFEAT_auto_translated_physmap))
+        	return;
+
 	xen_post_allocator_init();
 }
 
@@ -1685,15 +1689,18 @@ static void set_page_prot(void *addr, pgprot_t prot)
 	unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
 	pte_t pte = pfn_pte(pfn, prot);
 
-	if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
+	if (xen_feature(XENFEAT_auto_translated_physmap)) {
+                return;
+        }
+        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
 		BUG();
 }
 
-static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
+static __init int xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 {
-	unsigned pmdidx, pteidx;
-	unsigned ident_pte;
-	unsigned long pfn;
+	unsigned int pmdidx, pteidx;
+	unsigned int ident_pte;
+	unsigned int long pfn;
 
 	level1_ident_pgt = extend_brk(sizeof(pte_t) * LEVEL1_IDENT_ENTRIES,
 				      PAGE_SIZE);
@@ -1728,13 +1735,10 @@ static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
 			pte_page[pteidx] = pte;
 		}
 	}
-
-	for (pteidx = 0; pteidx < ident_pte; pteidx += PTRS_PER_PTE)
-		set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO);
-
-	set_page_prot(pmd, PAGE_KERNEL_RO);
+        return ident_pte;
 }
 
+/* TBD: DON'T NEED THIS FOR HYBRID EPT???? */
 void __init xen_setup_machphys_mapping(void)
 {
 	struct xen_machphys_mapping mapping;
@@ -1775,6 +1779,7 @@ static void convert_pfn_mfn(void *v)
 __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 					 unsigned long max_pfn)
 {
+        unsigned int pteidx, ident_ptes;
 	pud_t *l3;
 	pmd_t *l2;
 
@@ -1787,11 +1792,12 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 	/* Zap identity mapping */
 	init_level4_pgt[0] = __pgd(0);
 
-	/* Pre-constructed entries are in pfn, so convert to mfn */
-	convert_pfn_mfn(init_level4_pgt);
-	convert_pfn_mfn(level3_ident_pgt);
-	convert_pfn_mfn(level3_kernel_pgt);
-
+	if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+	        /* Pre-constructed entries are in pfn, so convert to mfn */
+	        convert_pfn_mfn(init_level4_pgt);
+	        convert_pfn_mfn(level3_ident_pgt);
+	        convert_pfn_mfn(level3_kernel_pgt);
+        }
 	l3 = m2v(pgd[pgd_index(__START_KERNEL_map)].pgd);
 	l2 = m2v(l3[pud_index(__START_KERNEL_map)].pud);
 
@@ -1803,7 +1809,11 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 	memcpy(level2_fixmap_pgt, l2, sizeof(pmd_t) * PTRS_PER_PMD);
 
 	/* Set up identity map */
-	xen_map_identity_early(level2_ident_pgt, max_pfn);
+	ident_ptes = xen_map_identity_early(level2_ident_pgt, max_pfn);
+
+	for (pteidx = 0; pteidx < ident_ptes; pteidx += PTRS_PER_PTE)
+		set_page_prot(&level1_ident_pgt[pteidx], PAGE_KERNEL_RO);
+	set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO);
 
 	/* Make pagetable pieces RO */
 	set_page_prot(init_level4_pgt, PAGE_KERNEL_RO);
@@ -1813,12 +1823,14 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 	set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
 	set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO);
 
-	/* Pin down new L4 */
-	pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE,
-			  PFN_DOWN(__pa_symbol(init_level4_pgt)));
+	if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+		/* Pin down new L4 */
+		pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE,
+			  	PFN_DOWN(__pa_symbol(init_level4_pgt)));
 
-	/* Unpin Xen-provided one */
-	pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
+		/* Unpin Xen-provided one */
+		pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
+	}
 
 	/* Switch over */
 	pgd = init_level4_pgt;
@@ -1828,9 +1840,13 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 	 * structure to attach it to, so make sure we just set kernel
 	 * pgd.
 	 */
-	xen_mc_batch();
-	__xen_write_cr3(true, __pa(pgd));
-	xen_mc_issue(PARAVIRT_LAZY_CPU);
+	if (xen_feature(XENFEAT_auto_translated_physmap)) {
+                native_write_cr3(__pa(pgd));
+        } else {
+	        xen_mc_batch();
+	        __xen_write_cr3(true, __pa(pgd));
+	        xen_mc_issue(PARAVIRT_LAZY_CPU);
+        }
 
 	memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
 		      __pa(xen_start_info->pt_base +
@@ -2117,14 +2133,26 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
 	.set_fixmap = xen_set_fixmap,
 };
 
+static __init void xen_hyb_override_mmu_ops(void)
+{
+        pv_mmu_ops.read_cr2 = native_read_cr2;
+        pv_mmu_ops.write_cr2 = native_write_cr2;
+}
+
 void __init xen_init_mmu_ops(void)
 {
+	memset(dummy_mapping, 0xff, PAGE_SIZE);
+	x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
+
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+        	return;
+
 	x86_init.mapping.pagetable_reserve = xen_mapping_pagetable_reserve;
 	x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start;
-	x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
-	pv_mmu_ops = xen_mmu_ops;
+        pv_mmu_ops = xen_mmu_ops;
 
-	memset(dummy_mapping, 0xff, PAGE_SIZE);
+        if (xen_hybrid_domain())      /* hybrid without EPT, ie, pv paging. */
+		xen_hyb_override_mmu_ops();
 }
 
 /* Protected by xen_reservation_lock. */
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index adaf127..9a2a576 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -391,12 +391,9 @@ void __cpuinit xen_enable_syscall(void)
 #endif /* CONFIG_X86_64 */
 }
 
-void __init xen_arch_setup(void)
+static __init void xen_nonhybrid_arch_setup(void)
 {
-	xen_panic_handler_init();
-
 	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
-	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
 
 	if (!xen_feature(XENFEAT_auto_translated_physmap))
 		HYPERVISOR_vm_assist(VMASST_CMD_enable,
@@ -415,6 +412,14 @@ void __init xen_arch_setup(void)
 		disable_acpi();
 	}
 #endif
+}
+
+void __init xen_arch_setup(void)
+{
+	xen_panic_handler_init();
+	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+	if (!xen_hybrid_domain())
+                xen_nonhybrid_arch_setup();
 
 	memcpy(boot_command_line, xen_start_info->cmd_line,
 	       MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 3061244..0b0464e 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -195,10 +195,11 @@ static void __init xen_smp_prepare_boot_cpu(void)
 	BUG_ON(smp_processor_id() != 0);
 	native_smp_prepare_boot_cpu();
 
-	/* We've switched to the "real" per-cpu gdt, so make sure the
-	   old memory can be recycled */
-	make_lowmem_page_readwrite(xen_initial_gdt);
-
+	if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+		/* We've switched to the "real" per-cpu gdt, so make sure the
+	   	   old memory can be recycled */
+		make_lowmem_page_readwrite(xen_initial_gdt);
+	}
 	xen_filter_cpu_maps();
 	xen_setup_vcpu_info_placement();
 }
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 6611535..1a3ebbc 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -3294,6 +3294,9 @@ static int __init serial8250_init(void)
 {
 	int ret;
 
+	if (xen_hybrid_domain())
+		return -ENODEV;
+
 	if (nr_uarts > UART_NR)
 		nr_uarts = UART_NR;
 
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
index 14e2d99..631a019 100644
--- a/drivers/xen/cpu_hotplug.c
+++ b/drivers/xen/cpu_hotplug.c
@@ -99,7 +99,7 @@ static int __init setup_vcpu_hotplug_event(void)
 	static struct notifier_block xsn_cpu = {
 		.notifier_call = setup_cpu_watcher };
 
-	if (!xen_pv_domain())
+	if (!xen_pv_domain() || xen_hybrid_domain())
 		return -ENODEV;
 
 	register_xenstore_notifier(&xsn_cpu);
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 33167b4..69bad2e 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -1632,5 +1632,7 @@ void __init xen_init_IRQ(void)
 		irq_ctx_init(smp_processor_id());
 		if (xen_initial_domain())
 			xen_setup_pirqs();
+                if (xen_hybrid_domain())
+		        xen_callback_vector();
 	}
 }
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 3745a31..ff57b55 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -46,6 +46,8 @@
 #include <xen/interface/memory.h>
 #include <asm/xen/hypercall.h>
 
+#include <asm/page.h>
+#include <asm/tlbflush.h>
 #include <asm/pgtable.h>
 #include <asm/sync_bitops.h>
 
@@ -503,6 +505,56 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
 }
 EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
 
+static int ptefunc(pte_t *pte, pgtable_t table, unsigned long addr, void *data)
+{
+        pte_t pteval = pfn_pte(virt_to_pfn(addr), PAGE_KERNEL);
+        set_pte(pte, pteval);
+	return 0;
+}
+
+
+extern int xen_hybrid_rsvd_top_frames;
+static int gnttab_map_hyb_autox(unsigned int start_idx, unsigned int end_idx)
+{
+	struct xen_add_to_physmap xatp;
+	unsigned int i = end_idx;
+	unsigned int nr_gframes = end_idx + 1;
+	int rc = 0;
+
+        if (shared == NULL) {
+                unsigned long numgf = gnttab_max_grant_frames();
+                unsigned long maxp = (1ULL << boot_cpu_data.x86_phys_bits) - 1;
+                unsigned long gntpfn = (maxp >> PAGE_SHIFT) - numgf;
+
+                BUG_ON(numgf > xen_hybrid_rsvd_top_frames);
+                shared = __va(gntpfn << PAGE_SHIFT);
+        }
+
+        /* will reinsert entries in shared[0...n-1], but its OK */
+        rc = apply_to_page_range(&init_mm, shared, 
+                                 PAGE_SIZE*nr_gframes, ptefunc, NULL);
+        BUG_ON(rc);
+
+	/*
+	 * Loop backwards, so that the first hypercall has the largest
+	 * index, ensuring that the table will grow only once.
+	 */
+	do {
+		xatp.domid = DOMID_SELF;
+		xatp.idx = i;
+		xatp.space = XENMAPSPACE_grant_table;
+		xatp.gpfn = (virt_to_pfn(shared)) + i;
+		rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
+		if (rc != 0) {
+			printk(KERN_WARNING
+			     "grant table add_to_physmap failed, err=%d\n", rc);
+			break;
+		}
+	} while (i-- > start_idx);
+
+        return rc;
+}
+
 static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
 {
 	struct gnttab_setup_table setup;
@@ -510,6 +562,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
 	unsigned int nr_gframes = end_idx + 1;
 	int rc;
 
+        if (xen_hybrid_autoxlate_domain())
+        	return gnttab_map_hyb_autox(start_idx, end_idx);
+
 	if (xen_hvm_domain()) {
 		struct xen_add_to_physmap xatp;
 		unsigned int i = end_idx;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 7397695..2429d0e 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -737,7 +737,13 @@ static int __init xenbus_init(void)
 
 		xen_store_interface = mfn_to_virt(xen_store_mfn);
 	} else {
-		if (xen_hvm_domain()) {
+		if (xen_hybrid_autoxlate_domain()) {
+                	xen_store_evtchn = xen_start_info->store_evtchn;
+			xen_store_mfn = xen_start_info->store_mfn;  /* pfn */
+			xen_store_interface = __va(xen_store_mfn<<PAGE_SHIFT);
+			xenstored_ready = 1;
+
+		} else if (xen_hvm_domain()) {
 			uint64_t v = 0;
 			err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
 			if (err)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index ee048e7..0758b26 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -1,6 +1,8 @@
 #ifndef __KERNEL_PRINTK__
 #define __KERNEL_PRINTK__
 
+extern void mukchk(unsigned long);
+
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index b33257b..805eb60 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -452,6 +452,7 @@ struct start_info {
 /* These flags are passed in the 'flags' field of start_info_t. */
 #define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
 #define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
+#define SIF_IS_HYBRID     (1<<3)  /* Is it a PV running in HVM container? */
 
 typedef uint64_t cpumap_t;
 
diff --git a/include/xen/xen.h b/include/xen/xen.h
index a164024..0c3fca1 100644
--- a/include/xen/xen.h
+++ b/include/xen/xen.h
@@ -18,7 +18,11 @@ extern enum xen_domain_type xen_domain_type;
 				 xen_domain_type == XEN_PV_DOMAIN)
 #define xen_hvm_domain()	(xen_domain() &&			\
 				 xen_domain_type == XEN_HVM_DOMAIN)
-
+/* xen_pv_domain check is necessary as start_info ptr is null in HVM */
+#define xen_hybrid_domain()     (xen_pv_domain () &&                    \
+                                 (xen_start_info->flags & SIF_IS_HYBRID))
+#define xen_hybrid_autoxlate_domain() (xen_hybrid_domain() &&  \
+                                 (xen_feature(XENFEAT_auto_translated_physmap)))
 #ifdef CONFIG_XEN_DOM0
 #include <xen/interface/xen.h>
 #include <asm/xen/hypervisor.h>

--MP_/R.1sMt_LjPbCVVbgRW8Pwbf
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=xen.diff

diff -r f2cf898c7ff8 tools/debugger/gdbsx/xg/xg_main.c
--- a/tools/debugger/gdbsx/xg/xg_main.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/debugger/gdbsx/xg/xg_main.c	Thu Nov 17 15:37:30 2011 -0800
@@ -80,6 +80,7 @@ int xgtrc_on = 0;
 struct xen_domctl domctl;         /* just use a global domctl */
 
 static int     _hvm_guest;        /* hvm guest? 32bit HVMs have 64bit context */
+static int     _hybrid_guest;
 static domid_t _dom_id;           /* guest domid */
 static int     _max_vcpu_id;      /* thus max_vcpu_id+1 VCPUs */
 static int     _dom0_fd;          /* fd of /dev/privcmd */
@@ -308,6 +309,8 @@ xg_attach(int domid, int guest_bitness)
 
     _max_vcpu_id = domctl.u.getdomaininfo.max_vcpu_id;
     _hvm_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_hvm_guest);
+    _hybrid_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_hybrid_guest);
+
     return _max_vcpu_id;
 }
 
@@ -368,7 +371,7 @@ _change_TF(vcpuid_t which_vcpu, int gues
     int sz = sizeof(anyc);
 
     /* first try the MTF for hvm guest. otherwise do manually */
-    if (_hvm_guest) {
+    if (_hvm_guest || _hybrid_guest) {
         domctl.u.debug_op.vcpu = which_vcpu;
         domctl.u.debug_op.op = setit ? XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON :
                                        XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF;
diff -r f2cf898c7ff8 tools/libxc/Makefile
--- a/tools/libxc/Makefile	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxc/Makefile	Thu Nov 17 15:37:30 2011 -0800
@@ -58,7 +58,7 @@ GUEST_SRCS-$(CONFIG_IA64)    += xc_dom_i
 -include $(XEN_TARGET_ARCH)/Makefile
 
 CFLAGS   += -Werror -Wmissing-prototypes
-CFLAGS   += $(INCLUDES) -I. -I../xenstore -I../include
+CFLAGS   += $(INCLUDES) -I. -I../xenstore -I../include -g -O0
 
 # Needed for posix_fadvise64() in xc_linux.c
 CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE
diff -r f2cf898c7ff8 tools/libxc/xc_dom.h
--- a/tools/libxc/xc_dom.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxc/xc_dom.h	Thu Nov 17 15:37:30 2011 -0800
@@ -110,6 +110,9 @@ struct xc_dom_image {
     struct xc_dom_arch *arch_hooks;
     /* allocate up to virt_alloc_end */
     int (*allocate) (struct xc_dom_image * dom, xen_vaddr_t up_to);
+
+    /* hybrid flags */
+    char hybrid_hap;
 };
 
 /* --- pluggable kernel loader ------------------------------------- */
@@ -241,7 +244,8 @@ static inline void *xc_dom_vaddr_to_ptr(
 
 static inline int xc_dom_feature_translated(struct xc_dom_image *dom)
 {
-    return elf_xen_feature_get(XENFEAT_auto_translated_physmap, dom->f_active);
+    return(dom->hybrid_hap || 
+           elf_xen_feature_get(XENFEAT_auto_translated_physmap, dom->f_active));
 }
 
 static inline xen_pfn_t xc_dom_p2m_host(struct xc_dom_image *dom, xen_pfn_t pfn)
diff -r f2cf898c7ff8 tools/libxc/xc_dom_x86.c
--- a/tools/libxc/xc_dom_x86.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxc/xc_dom_x86.c	Thu Nov 17 15:37:30 2011 -0800
@@ -372,7 +372,8 @@ static int setup_pgtables_x86_64(struct 
         pgpfn = (addr - dom->parms.virt_base) >> PAGE_SHIFT_X86;
         l1tab[l1off] =
             pfn_to_paddr(xc_dom_p2m_guest(dom, pgpfn)) | L1_PROT;
-        if ( (addr >= dom->pgtables_seg.vstart) && 
+        if ( !dom->hybrid_hap                   &&
+             (addr >= dom->pgtables_seg.vstart) && 
              (addr < dom->pgtables_seg.vend) )
             l1tab[l1off] &= ~_PAGE_RW; /* page tables are r/o */
         if ( l1off == (L1_PAGETABLE_ENTRIES_X86_64 - 1) )
@@ -819,7 +820,7 @@ int arch_setup_bootlate(struct xc_dom_im
         }
 
         /* Map grant table frames into guest physmap. */
-        for ( i = 0; ; i++ )
+        for ( i = 0; !dom->hybrid_hap ; i++ )
         {
             xatp.domid = dom->guest_domid;
             xatp.space = XENMAPSPACE_grant_table;
diff -r f2cf898c7ff8 tools/libxl/Makefile
--- a/tools/libxl/Makefile	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxl/Makefile	Thu Nov 17 15:37:30 2011 -0800
@@ -12,7 +12,7 @@ XLUMAJOR = 1.0
 XLUMINOR = 0
 
 CFLAGS += -Werror
-CFLAGS += -I. -fPIC
+CFLAGS += -I. -fPIC -g -O0
 CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore)
 
 LIBS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore)
diff -r f2cf898c7ff8 tools/libxl/libxl.c
--- a/tools/libxl/libxl.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxl/libxl.c	Thu Nov 17 15:37:30 2011 -0800
@@ -99,6 +99,7 @@ int libxl_domain_make(struct libxl_ctx *
     if (!uuid_string) return ERROR_NOMEM;
 
     flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
+    flags |= info->hybrid ? XEN_DOMCTL_CDF_hybrid_guest : 0;
     flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
     flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
     *domid = -1;
diff -r f2cf898c7ff8 tools/libxl/libxl.h
--- a/tools/libxl/libxl.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxl/libxl.h	Thu Nov 17 15:37:30 2011 -0800
@@ -78,6 +78,7 @@ const libxl_version_info* libxl_get_vers
 
 typedef struct {
     bool hvm;
+    bool hybrid;
     bool hap;
     bool oos;
     int ssidref;
@@ -97,6 +98,8 @@ typedef struct {
     uint32_t shadow_memkb;
     const char *kernel;
     int hvm;
+    int hybrid;
+    int hybrid_hap;
     union {
         struct {
             bool pae;
diff -r f2cf898c7ff8 tools/libxl/libxl_dom.c
--- a/tools/libxl/libxl_dom.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxl/libxl_dom.c	Thu Nov 17 15:37:30 2011 -0800
@@ -69,7 +69,7 @@ int build_pre(struct libxl_ctx *ctx, uin
             (info->max_memkb + info->u.pv.slack_memkb));
     xc_domain_set_tsc_info(ctx->xch, domid, info->tsc_mode, 0, 0, 0);
 
-    if (info->hvm) {
+    if (info->hvm || info->hybrid) {
         unsigned long shadow;
         shadow = (info->shadow_memkb + 1023) / 1024;
         xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
@@ -139,13 +139,16 @@ int build_pv(struct libxl_ctx *ctx, uint
 {
     struct xc_dom_image *dom;
     int ret;
-    int flags = 0;
+    int flags;               /* start info flags: start_info_x86_64() */
+
+    flags = info->hybrid ? SIF_IS_HYBRID : 0;
 
     dom = xc_dom_allocate(info->u.pv.cmdline, info->u.pv.features);
     if (!dom) {
         XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed");
         return -1;
     }
+    dom->hybrid_hap = info->hybrid_hap ? 1 : 0;
     ret = xc_dom_linux_build(ctx->xch, dom, domid, info->target_memkb / 1024,
                                   info->kernel, info->u.pv.ramdisk, flags,
                                   state->store_port, &state->store_mfn,
diff -r f2cf898c7ff8 tools/libxl/xl_cmdimpl.c
--- a/tools/libxl/xl_cmdimpl.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/tools/libxl/xl_cmdimpl.c	Thu Nov 17 15:37:30 2011 -0800
@@ -197,6 +197,11 @@ static void init_build_info(libxl_domain
     } else {
         b_info->u.pv.slack_memkb = 8 * 1024;
     }
+    if (c_info->hybrid) {
+        b_info->hybrid = 1;
+        if (c_info->hap)
+            b_info->hybrid_hap = 1;
+    }
 }
 
 static void init_dm_info(libxl_device_model_info *dm_info,
@@ -469,6 +474,11 @@ static void parse_config_data(const char
         !strncmp(buf, "hvm", strlen(buf)))
         c_info->hvm = 1;
 
+    c_info->hybrid = 0;
+    if (!xlu_cfg_get_long (config, "hybrid", &l))
+        c_info->hybrid = 1;
+
+    c_info->hap = 0;
     if (!xlu_cfg_get_long (config, "hap", &l))
         c_info->hap = l;
 
diff -r f2cf898c7ff8 xen/arch/x86/debug.c
--- a/xen/arch/x86/debug.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/debug.c	Thu Nov 17 15:37:30 2011 -0800
@@ -43,7 +43,6 @@ extern void kdbp(const char *fmt, ...);
 typedef unsigned long dbgva_t;
 typedef unsigned char dbgbyte_t;
 
-
 /* Returns: mfn for the given (hvm guest) vaddr */
 static unsigned long 
 dbg_hvm_va2mfn(dbgva_t vaddr, struct domain *dp, int toaddr)
@@ -55,6 +54,7 @@ dbg_hvm_va2mfn(dbgva_t vaddr, struct dom
     DBGP2("vaddr:%lx domid:%d\n", vaddr, dp->domain_id);
 
     gfn = paging_gva_to_gfn(dp->vcpu[0], vaddr, &pfec);
+
     if ( gfn == INVALID_GFN )
     {
         DBGP2("kdb:bad gfn from gva_to_gfn\n");
@@ -200,7 +200,7 @@ dbg_rw_guest_mem(dbgva_t addr, dbgbyte_t
 
         pagecnt = min_t(long, PAGE_SIZE - (addr & ~PAGE_MASK), len);
 
-        mfn = (dp->is_hvm
+        mfn = ( (is_hvm_domain(dp) || is_hyb_hap_domain(dp))
                ? dbg_hvm_va2mfn(addr, dp, toaddr)
                : dbg_pv_va2mfn(addr, dp, pgd3));
         if ( mfn == INVALID_MFN ) 
@@ -225,7 +225,6 @@ dbg_rw_guest_mem(dbgva_t addr, dbgbyte_t
         buf += pagecnt;
         len -= pagecnt;
     }
-
     return len;
 }
 
diff -r f2cf898c7ff8 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/domain.c	Thu Nov 17 15:37:30 2011 -0800
@@ -160,6 +160,7 @@ void dump_pageframe_info(struct domain *
         spin_unlock(&d->page_alloc_lock);
     }
 
+    KASSERT(!is_hybrid_domain(d) );
     if ( is_hvm_domain(d) )
     {
         p2m_pod_dump_data(d);
@@ -354,7 +355,7 @@ int vcpu_initialise(struct vcpu *v)
 
     paging_vcpu_init(v);
 
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
     {
         if ( (rc = hvm_vcpu_initialise(v)) != 0 )
             return rc;
@@ -410,7 +411,7 @@ int arch_domain_create(struct domain *d,
     int rc = -ENOMEM;
 
     d->arch.hvm_domain.hap_enabled =
-        is_hvm_domain(d) &&
+        (is_hvm_or_hyb_domain(d)) &&
         hvm_funcs.hap_supported &&
         (domcr_flags & DOMCRF_hap);
     d->arch.hvm_domain.mem_sharing_enabled = 0;
@@ -508,7 +509,7 @@ int arch_domain_create(struct domain *d,
         mce_init_msr(d);
     }
 
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
     {
         if ( (rc = hvm_domain_initialise(d)) != 0 )
         {
@@ -562,7 +563,7 @@ void arch_domain_destroy(struct domain *
     unsigned int i;
 #endif
 
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         hvm_domain_destroy(d);
 
     pci_release_devices(d);
@@ -608,6 +609,8 @@ unsigned long pv_guest_cr4_fixup(unsigne
     return (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask);
 }
 
+extern void hybrid_update_cr3(struct vcpu *);
+
 /* This is called by arch_final_setup_guest and do_boot_vcpu */
 int arch_set_info_guest(
     struct vcpu *v, vcpu_guest_context_u c)
@@ -628,7 +631,7 @@ int arch_set_info_guest(
 #endif
     flags = c(flags);
 
-    if ( !is_hvm_vcpu(v) )
+    if ( !is_hvm_or_hyb_domain(d) )
     {
         if ( !compat )
         {
@@ -677,7 +680,7 @@ int arch_set_info_guest(
     v->fpu_initialised = !!(flags & VGCF_I387_VALID);
 
     v->arch.flags &= ~TF_kernel_mode;
-    if ( (flags & VGCF_in_kernel) || is_hvm_vcpu(v)/*???*/ )
+    if ( (flags & VGCF_in_kernel) || is_hvm_or_hyb_vcpu(v) )
         v->arch.flags |= TF_kernel_mode;
 
     if ( !compat )
@@ -689,18 +692,13 @@ int arch_set_info_guest(
 
     v->arch.guest_context.user_regs.eflags |= 2;
 
-    if ( is_hvm_vcpu(v) )
+    if ( is_hvm_or_hyb_vcpu(v) )
     {
         hvm_set_info_guest(v);
-        goto out;
+        if ( !is_hybrid_vcpu(v) ) 
+            goto out;
     }
 
-    /* Only CR0.TS is modifiable by guest or admin. */
-    v->arch.guest_context.ctrlreg[0] &= X86_CR0_TS;
-    v->arch.guest_context.ctrlreg[0] |= read_cr0() & ~X86_CR0_TS;
-
-    init_int80_direct_trap(v);
-
     /* IOPL privileges are virtualised. */
     v->arch.iopl = (v->arch.guest_context.user_regs.eflags >> 12) & 3;
     v->arch.guest_context.user_regs.eflags &= ~X86_EFLAGS_IOPL;
@@ -708,38 +706,50 @@ int arch_set_info_guest(
     /* Ensure real hardware interrupts are enabled. */
     v->arch.guest_context.user_regs.eflags |= X86_EFLAGS_IF;
 
-    cr4 = v->arch.guest_context.ctrlreg[4];
-    v->arch.guest_context.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(cr4) :
-        real_cr4_to_pv_guest_cr4(mmu_cr4_features);
-
     memset(v->arch.guest_context.debugreg, 0,
            sizeof(v->arch.guest_context.debugreg));
     for ( i = 0; i < 8; i++ )
         (void)set_debugreg(v, i, c(debugreg[i]));
 
+    if ( !is_hybrid_vcpu(v) )
+    {
+        /* Only CR0.TS is modifiable by guest or admin. */
+        v->arch.guest_context.ctrlreg[0] &= X86_CR0_TS;
+        v->arch.guest_context.ctrlreg[0] |= read_cr0() & ~X86_CR0_TS;
+
+        init_int80_direct_trap(v);
+
+        cr4 = v->arch.guest_context.ctrlreg[4];
+        v->arch.guest_context.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(cr4) :
+            real_cr4_to_pv_guest_cr4(mmu_cr4_features);
+    }
+
     if ( v->is_initialised )
         goto out;
 
     if ( v->vcpu_id == 0 )
         d->vm_assist = c(vm_assist);
 
-    if ( !compat )
-        rc = (int)set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
+    if ( !is_hybrid_vcpu(v) )
+    {
+        if ( !compat )
+            rc = (int)set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
 #ifdef CONFIG_COMPAT
-    else
-    {
-        unsigned long gdt_frames[ARRAY_SIZE(c.cmp->gdt_frames)];
-        unsigned int i, n = (c.cmp->gdt_ents + 511) / 512;
+        else
+        {
+            unsigned long gdt_frames[ARRAY_SIZE(c.cmp->gdt_frames)];
+            unsigned int i, n = (c.cmp->gdt_ents + 511) / 512;
 
-        if ( n > ARRAY_SIZE(c.cmp->gdt_frames) )
-            return -EINVAL;
-        for ( i = 0; i < n; ++i )
-            gdt_frames[i] = c.cmp->gdt_frames[i];
-        rc = (int)set_gdt(v, gdt_frames, c.cmp->gdt_ents);
+            if ( n > ARRAY_SIZE(c.cmp->gdt_frames) )
+                return -EINVAL;
+            for ( i = 0; i < n; ++i )
+                gdt_frames[i] = c.cmp->gdt_frames[i];
+            rc = (int)set_gdt(v, gdt_frames, c.cmp->gdt_ents);
+        }
+#endif
+        if ( rc != 0 )
+            return rc;
     }
-#endif
-    if ( rc != 0 )
-        return rc;
 
     if ( !compat )
     {
@@ -751,10 +761,17 @@ int arch_set_info_guest(
               : !get_page_and_type(mfn_to_page(cr3_pfn), d,
                                    PGT_base_page_table)) )
         {
-            destroy_gdt(v);
+            if ( !is_hybrid_vcpu(v) )
+                destroy_gdt(v);
             return -EINVAL;
         }
 
+        if (is_hybrid_vcpu(v) && paging_mode_enabled(d))
+        {
+            v->arch.cr3 = cr3_pfn;
+            v->arch.hvm_vcpu.guest_cr[3] = c.nat->ctrlreg[3];
+        }
+
         v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
 
 #ifdef __x86_64__
@@ -782,7 +799,8 @@ int arch_set_info_guest(
         }
         else if ( !(flags & VGCF_in_kernel) )
         {
-            destroy_gdt(v);
+            if ( !is_hybrid_vcpu(v) )
+                destroy_gdt(v);
             return -EINVAL;
         }
     }
@@ -818,6 +836,13 @@ int arch_set_info_guest(
         paging_update_paging_modes(v);
 
     update_cr3(v);
+    if (is_hybrid_vcpu(v))
+    {
+        if (paging_mode_enabled(d))   /* HAP is enabled */
+            hvm_update_host_cr3(v);   /* GUEST_CR3 updated in update_cr3() */
+        else
+            hybrid_update_cr3(v);
+    }
 
  out:
     if ( flags & VGCF_online )
@@ -1347,10 +1372,10 @@ static void update_runstate_area(struct 
 
 static inline int need_full_gdt(struct vcpu *v)
 {
-    return (!is_hvm_vcpu(v) && !is_idle_vcpu(v));
+    return (!is_hvm_vcpu(v) && !is_idle_vcpu(v) && !is_hybrid_vcpu(v)); 
 }
 
-static void __context_switch(void)
+static noinline void __context_switch(void)
 {
     struct cpu_user_regs *stack_regs = guest_cpu_user_regs();
     unsigned int          cpu = smp_processor_id();
@@ -1475,18 +1500,30 @@ void context_switch(struct vcpu *prev, s
         /* Re-enable interrupts before restoring state which may fault. */
         local_irq_enable();
 
-        if ( !is_hvm_vcpu(next) )
+        if ( !is_hvm_or_hyb_vcpu(next) )
         {
             load_LDT(next);
             load_segments(next);
         }
     }
-
     context_saved(prev);
 
     if (prev != next)
         update_runstate_area(next);
 
+#if 0
+{
+struct vcpu_runstate_info rst; 
+struct vcpu_runstate_info *tp = 
+        (struct vcpu_runstate_info *)(runstate_guest(next)).p;
+if (tp)
+    copy_from_guest(&rst, runstate_guest(next), 1);
+
+kdbtrc(0xeeffee, rst.state, (ulong)next, (ulong)tp, 
+       (ulong)next->runstate.state);
+}
+#endif
+
     schedule_tail(next);
     BUG();
 }
@@ -2034,7 +2071,7 @@ int domain_relinquish_resources(struct d
         BUG();
     }
 
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         hvm_domain_relinquish_resources(d);
 
     return 0;
@@ -2115,7 +2152,7 @@ void vcpu_mark_events_pending(struct vcp
     if ( already_pending )
         return;
 
-    if ( is_hvm_vcpu(v) )
+    if ( is_hvm_or_hyb_vcpu(v) ) 
         hvm_assert_evtchn_irq(v);
     else
         vcpu_kick(v);
diff -r f2cf898c7ff8 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/domctl.c	Thu Nov 17 15:37:30 2011 -0800
@@ -466,6 +466,7 @@ long arch_do_domctl(
             goto sethvmcontext_out;
 
         ret = -EINVAL;
+        KASSERT(!is_hybrid_domain(d));
         if ( !is_hvm_domain(d) ) 
             goto sethvmcontext_out;
 
@@ -503,6 +504,7 @@ long arch_do_domctl(
             goto gethvmcontext_out;
 
         ret = -EINVAL;
+        KASSERT(!is_hybrid_domain(d));
         if ( !is_hvm_domain(d) ) 
             goto gethvmcontext_out;
 
@@ -558,6 +560,7 @@ long arch_do_domctl(
             goto gethvmcontext_partial_out;
 
         ret = -EINVAL;
+        KASSERT(!is_hybrid_domain(d));
         if ( !is_hvm_domain(d) ) 
             goto gethvmcontext_partial_out;
 
@@ -719,6 +722,7 @@ long arch_do_domctl(
         case XEN_DOMCTL_SENDTRIGGER_POWER:
         {
             ret = -EINVAL;
+            KASSERT(!is_hybrid_domain(d));
             if ( is_hvm_domain(d) ) 
             {
                 ret = 0;
@@ -731,6 +735,7 @@ long arch_do_domctl(
         {
             extern void hvm_acpi_sleep_button(struct domain *d);
 
+            KASSERT(!is_hybrid_domain(d));
             ret = -EINVAL;
             if ( is_hvm_domain(d) ) 
             {
@@ -1285,7 +1290,7 @@ long arch_do_domctl(
             goto debug_op_out;
 
         ret = -EINVAL;
-        if ( !is_hvm_domain(d))
+        if ( !is_hvm_or_hyb_domain(d))
             goto debug_op_out;
 
         ret = hvm_debug_op(v, domctl->u.debug_op.op);
@@ -1465,8 +1470,9 @@ void arch_get_info_guest(struct vcpu *v,
         c(flags |= VGCF_i387_valid);
     if ( !test_bit(_VPF_down, &v->pause_flags) )
         c(flags |= VGCF_online);
-
-    if ( is_hvm_vcpu(v) )
+        
+    /* HYBRID TDB: debugregs? Verify this again */
+    if ( is_hvm_or_hyb_vcpu(v) )
     {
         struct segment_register sreg;
         memset(c.nat->ctrlreg, 0, sizeof(c.nat->ctrlreg));
diff -r f2cf898c7ff8 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/hvm.c	Thu Nov 17 15:37:30 2011 -0800
@@ -227,6 +227,9 @@ void hvm_do_resume(struct vcpu *v)
 {
     ioreq_t *p;
 
+    if (is_hybrid_vcpu(v))
+        return;
+
     pt_restore_timer(v);
 
     /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
@@ -367,16 +370,21 @@ int hvm_domain_initialise(struct domain 
         return -EINVAL;
     }
 
-    spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
     spin_lock_init(&d->arch.hvm_domain.irq_lock);
-    spin_lock_init(&d->arch.hvm_domain.uc_lock);
-
-    INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list);
-    spin_lock_init(&d->arch.hvm_domain.msixtbl_list_lock);
-
     hvm_init_guest_time(d);
-
-    d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1;
+    
+    if (is_hybrid_domain(d)) {
+        if (!d->arch.hvm_domain.hap_enabled)
+            return 0;
+    } else {
+        spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
+        spin_lock_init(&d->arch.hvm_domain.uc_lock);
+
+        INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list);
+        spin_lock_init(&d->arch.hvm_domain.msixtbl_list_lock);
+
+        d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1;
+    }
 
     hvm_init_cacheattr_region_list(d);
 
@@ -384,20 +392,22 @@ int hvm_domain_initialise(struct domain 
     if ( rc != 0 )
         goto fail1;
 
-    vpic_init(d);
-
-    rc = vioapic_init(d);
-    if ( rc != 0 )
-        goto fail1;
-
-    stdvga_init(d);
-
-    rtc_init(d);
-
-    hvm_init_ioreq_page(d, &d->arch.hvm_domain.ioreq);
-    hvm_init_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq);
-
-    register_portio_handler(d, 0xe9, 1, hvm_print_line);
+    if (!is_hybrid_domain(d)) {
+        vpic_init(d);
+
+        rc = vioapic_init(d);
+        if ( rc != 0 )
+            goto fail1;
+
+        stdvga_init(d);
+
+        rtc_init(d);
+
+        hvm_init_ioreq_page(d, &d->arch.hvm_domain.ioreq);
+        hvm_init_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq);
+
+        register_portio_handler(d, 0xe9, 1, hvm_print_line);
+    }
 
     rc = hvm_funcs.domain_initialise(d);
     if ( rc != 0 )
@@ -406,9 +416,11 @@ int hvm_domain_initialise(struct domain 
     return 0;
 
  fail2:
-    rtc_deinit(d);
-    stdvga_deinit(d);
-    vioapic_deinit(d);
+    if (!is_hybrid_domain(d)) {
+        rtc_deinit(d);
+        stdvga_deinit(d);
+        vioapic_deinit(d);
+    }
  fail1:
     hvm_destroy_cacheattr_region_list(d);
     return rc;
@@ -418,6 +430,10 @@ extern void msixtbl_pt_cleanup(struct do
 
 void hvm_domain_relinquish_resources(struct domain *d)
 {
+    if (is_hybrid_domain(d)) {
+        printk("MUK: WARN: Hybrid ignoring pit/pmtimer/hpet cleanup\n");
+        return;
+    }
     hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq);
     hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.buf_ioreq);
 
@@ -436,10 +452,14 @@ void hvm_domain_relinquish_resources(str
 void hvm_domain_destroy(struct domain *d)
 {
     hvm_funcs.domain_destroy(d);
+
+    if (is_hybrid_domain(d))
+        return;
+
+    hvm_destroy_cacheattr_region_list(d);
     rtc_deinit(d);
     stdvga_deinit(d);
     vioapic_deinit(d);
-    hvm_destroy_cacheattr_region_list(d);
 }
 
 static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
@@ -737,13 +757,25 @@ static int hvm_load_cpu_ctxt(struct doma
 HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt,
                           1, HVMSR_PER_VCPU);
 
+static noinline int hybrid_vcpu_finish_init(struct vcpu *v)
+{
+    if ( v->vcpu_id == 0 )
+        hvm_set_guest_tsc(v, 0);
+
+    /* PV guests by default have a 100Hz ticker. */
+    v->periodic_period = MILLISECS(10);  /* ???? */
+
+    return 0;
+}
+
 int hvm_vcpu_initialise(struct vcpu *v)
 {
     int rc;
 
     hvm_asid_flush_vcpu(v);
 
-    if ( cpu_has_xsave )
+    /* HYBRID TBD: investigate xsave/xrestore for hybrid ??? */
+    if ( cpu_has_xsave && !is_hybrid_vcpu(v) )
     {
         /* XSAVE/XRSTOR requires the save area be 64-byte-boundary aligned. */
         void *xsave_area = _xmalloc(xsave_cntxt_size, 64);
@@ -755,12 +787,21 @@ int hvm_vcpu_initialise(struct vcpu *v)
         v->arch.hvm_vcpu.xfeature_mask = XSTATE_FP_SSE;
     }
 
-    if ( (rc = vlapic_init(v)) != 0 )
+    if ( !is_hybrid_vcpu(v) && ((rc = vlapic_init(v)) != 0) )
         goto fail1;
 
     if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 )
         goto fail2;
 
+    tasklet_init(&v->arch.hvm_vcpu.assert_evtchn_irq_tasklet,
+                 (void(*)(unsigned long))hvm_assert_evtchn_irq,
+                 (unsigned long)v);
+
+    v->arch.guest_context.user_regs.eflags = 2;
+
+    if (is_hybrid_vcpu(v))
+        return hybrid_vcpu_finish_init(v);
+
     /* Create ioreq event channel. */
     rc = alloc_unbound_xen_event_channel(v, 0);
     if ( rc < 0 )
@@ -780,12 +821,6 @@ int hvm_vcpu_initialise(struct vcpu *v)
     if ( rc != 0 )
         goto fail3;
 
-    tasklet_init(&v->arch.hvm_vcpu.assert_evtchn_irq_tasklet,
-                 (void(*)(unsigned long))hvm_assert_evtchn_irq,
-                 (unsigned long)v);
-
-    v->arch.guest_context.user_regs.eflags = 2;
-
     if ( v->vcpu_id == 0 )
     {
         /* NB. All these really belong in hvm_domain_initialise(). */
@@ -828,6 +863,8 @@ void hvm_vcpu_down(struct vcpu *v)
     struct domain *d = v->domain;
     int online_count = 0;
 
+printk("MUK: hvm_vcpu_down(): kdb trap\n");
+
     /* Doesn't halt us immediately, but we'll never return to guest context. */
     set_bit(_VPF_down, &v->pause_flags);
     vcpu_sleep_nosync(v);
@@ -2222,6 +2259,14 @@ static long hvm_vcpu_op(
     case VCPUOP_stop_singleshot_timer:
         rc = do_vcpu_op(cmd, vcpuid, arg);
         break;
+
+    case VCPUOP_is_up:
+    case VCPUOP_up:
+        if (is_hybrid_vcpu(current)) {
+            rc = do_vcpu_op(cmd, vcpuid, arg);
+            break;
+        }
+
     default:
         rc = -ENOSYS;
         break;
@@ -2292,11 +2337,17 @@ static long hvm_vcpu_op_compat32(
     return rc;
 }
 
-static hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = {
+hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = {
     [ __HYPERVISOR_memory_op ] = (hvm_hypercall_t *)hvm_memory_op,
     [ __HYPERVISOR_grant_table_op ] = (hvm_hypercall_t *)hvm_grant_table_op,
     [ __HYPERVISOR_vcpu_op ] = (hvm_hypercall_t *)hvm_vcpu_op,
+    HYPERCALL(set_debugreg),
+    HYPERCALL(multicall),
+    HYPERCALL(update_va_mapping),
     HYPERCALL(xen_version),
+    HYPERCALL(console_io),
+    HYPERCALL(vm_assist),
+    HYPERCALL(mmuext_op),
     HYPERCALL(event_channel_op),
     HYPERCALL(sched_op),
     HYPERCALL(set_timer_op),
@@ -2321,6 +2372,31 @@ static hvm_hypercall_t *hvm_hypercall32_
 
 #endif /* defined(__x86_64__) */
 
+/* Returns: 1 if hcall is valid, 0 otherwise. */
+static int hcall_valid(uint32_t eax)
+{
+#ifndef __x86_64__
+    if ( unlikely(eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
+#else
+    if ( unlikely(eax >= NR_hypercalls) || !hvm_hypercall64_table[eax] ||
+        (!is_hybrid_vcpu(current) && 
+                   ( (eax==__HYPERVISOR_set_trap_table) ||
+                     (eax==__HYPERVISOR_set_debugreg) ||
+                     (eax==__HYPERVISOR_update_descriptor) ||
+                     (eax==__HYPERVISOR_multicall) ||
+                     (eax==__HYPERVISOR_update_va_mapping) ||
+                     (eax==__HYPERVISOR_console_io) ||
+                     (eax==__HYPERVISOR_set_segment_base) ||
+                     (eax==__HYPERVISOR_vm_assist) ||
+                     (eax==__HYPERVISOR_mmuext_op) ) )    ||
+        ((is_hybrid_vcpu(current) && hap_enabled(current->domain)) &&
+                     (eax==__HYPERVISOR_update_va_mapping)) )
+#endif
+        return 0;
+
+    return 1;
+}
+
 int hvm_do_hypercall(struct cpu_user_regs *regs)
 {
     struct vcpu *curr = current;
@@ -2349,8 +2425,7 @@ int hvm_do_hypercall(struct cpu_user_reg
     if ( (eax & 0x80000000) && is_viridian_domain(curr->domain) )
         return viridian_hypercall(regs);
 
-    if ( (eax >= NR_hypercalls) || !hvm_hypercall32_table[eax] )
-    {
+    if ( !hcall_valid(eax)) {
         regs->eax = -ENOSYS;
         return HVM_HCALL_completed;
     }
@@ -2734,12 +2809,46 @@ static int hvmop_flush_tlb_all(void)
     return 0;
 }
 
+static noinline long _do_hybrid_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
+{
+    long rc = -EINVAL;
+    struct xen_hvm_param a;
+    struct domain *d;
+
+    if (op == HVMOP_set_param) {
+        if ( copy_from_guest(&a, arg, 1) )
+            return -EFAULT;
+
+        rc = rcu_lock_target_domain_by_id(a.domid, &d);
+        if ( rc != 0 )
+            return rc;
+
+        if (a.index == HVM_PARAM_CALLBACK_IRQ) {
+            struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+            uint64_t via = a.value;
+            uint8_t via_type = (uint8_t)(via >> 56) + 1;
+
+            if (via_type == HVMIRQ_callback_vector) {
+                hvm_irq->callback_via_type = HVMIRQ_callback_vector;
+                hvm_irq->callback_via.vector = (uint8_t)via;
+                rc = 0;
+            }
+        }
+    }
+    KASSERT(rc == 0);
+    return rc;
+}
+
 long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
 
 {
     struct domain *curr_d = current->domain;
     long rc = 0;
 
+    if (is_hybrid_domain(curr_d)) {
+        return (_do_hybrid_op(op, arg)); 
+    }
+
     switch ( op )
     {
     case HVMOP_set_param:
diff -r f2cf898c7ff8 xen/arch/x86/hvm/irq.c
--- a/xen/arch/x86/hvm/irq.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/irq.c	Thu Nov 17 15:37:30 2011 -0800
@@ -333,6 +333,9 @@ struct hvm_intack hvm_vcpu_has_pending_i
          && vcpu_info(v, evtchn_upcall_pending) )
         return hvm_intack_vector(plat->irq.callback_via.vector);
 
+    if (is_hybrid_vcpu(v))       /* Hybrid TBD: See NMI / MCE below */
+        return hvm_intack_none;
+
     if ( unlikely(v->nmi_pending) )
         return hvm_intack_nmi;
 
diff -r f2cf898c7ff8 xen/arch/x86/hvm/mtrr.c
--- a/xen/arch/x86/hvm/mtrr.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/mtrr.c	Thu Nov 17 15:37:30 2011 -0800
@@ -573,6 +573,7 @@ int32_t hvm_get_mem_pinned_cacheattr(
     uint32_t *type)
 {
     struct hvm_mem_pinned_cacheattr_range *range;
+    KASSERT(!is_hybrid_domain(d));
 
     *type = 0;
 
@@ -601,6 +602,8 @@ int32_t hvm_set_mem_pinned_cacheattr(
 {
     struct hvm_mem_pinned_cacheattr_range *range;
 
+    KASSERT(!is_hybrid_domain(d));
+
     if ( !((type == PAT_TYPE_UNCACHABLE) ||
            (type == PAT_TYPE_WRCOMB) ||
            (type == PAT_TYPE_WRTHROUGH) ||
diff -r f2cf898c7ff8 xen/arch/x86/hvm/svm/vmcb.c
--- a/xen/arch/x86/hvm/svm/vmcb.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/svm/vmcb.c	Thu Nov 17 15:37:30 2011 -0800
@@ -419,7 +419,7 @@ void kdb_dump_vmcb(domid_t did, int vid)
 
     rcu_read_lock(&domlist_read_lock);
     for_each_domain (dp) {
-        if (!is_hvm_domain(dp) || dp->is_dying)
+        if (!is_hvm_or_hyb_domain(dp) || dp->is_dying)
             continue;
         if (did != 0 && did != dp->domain_id)
             continue;
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vmx/Makefile
--- a/xen/arch/x86/hvm/vmx/Makefile	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/vmx/Makefile	Thu Nov 17 15:37:30 2011 -0800
@@ -5,3 +5,4 @@ obj-y += vmcs.o
 obj-y += vmx.o
 obj-y += vpmu.o
 obj-y += vpmu_core2.o
+obj-y += hybrid.o
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vmx/hybrid.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/vmx/hybrid.c	Thu Nov 17 15:37:30 2011 -0800
@@ -0,0 +1,576 @@
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/trace.h>
+#include <xen/sched.h>
+#include <xen/irq.h>
+#include <xen/softirq.h>
+#include <xen/domain_page.h>
+#include <xen/hypercall.h>
+#include <xen/perfc.h>
+#include <asm/current.h>
+#include <asm/io.h>
+#include <asm/regs.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/types.h>
+#include <asm/debugreg.h>
+#include <asm/msr.h>
+#include <asm/spinlock.h>
+#include <asm/paging.h>
+#include <asm/p2m.h>
+#include <asm/mem_sharing.h>
+#include <asm/hvm/emulate.h>
+#include <asm/hvm/hvm.h>
+#include <asm/hvm/support.h>
+#include <asm/hvm/vmx/vmx.h>
+#include <asm/hvm/vmx/vmcs.h>
+#include <public/sched.h>
+#include <public/hvm/ioreq.h>
+#include <asm/hvm/vpic.h>
+#include <asm/hvm/vlapic.h>
+#include <asm/x86_emulate.h>
+#include <asm/hvm/vpt.h>
+#include <public/hvm/save.h>
+#include <asm/hvm/trace.h>
+#include <asm/xenoprof.h>
+#include <asm/debugger.h>
+
+extern void vmx_do_extint(struct cpu_user_regs *regs);
+extern void vmx_do_cpuid(struct cpu_user_regs *regs);
+enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
+extern enum handler_return long_mode_do_msr_read(struct cpu_user_regs *);
+extern enum handler_return long_mode_do_msr_write(struct cpu_user_regs *);
+
+
+volatile int mukprint=0, mukspin=1;
+#define dbgp0(...) dprintk(XENLOG_ERR, __VA_ARGS__);
+#define dbgp1(...) {(mukprint==1) ? kdbp(__VA_ARGS__):0;}
+#define dbgp2(...) {(mukprint==2) ? kdbp(__VA_ARGS__):0;}
+
+
+/* returns : 0 success */
+static noinline int vmxit_msr_read(struct cpu_user_regs *regs)
+{
+    uint inst_len = __get_instruction_length();
+    int rc=1;
+
+    u64 msr_content = 0;
+    switch (regs->ecx)
+    {
+        case MSR_IA32_MISC_ENABLE:
+        {
+            rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
+            msr_content |= MSR_IA32_MISC_ENABLE_BTS_UNAVAIL |
+                           MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
+            break;
+        }
+        default:
+        {
+            rdmsrl(regs->ecx, msr_content);
+            break;
+        }
+    }
+    regs->eax = (uint32_t)msr_content;
+    regs->edx = (uint32_t)(msr_content >> 32);
+    __update_guest_eip(inst_len);
+    rc = 0;
+
+#if 0
+    rc = (long_mode_do_msr_read(regs) == HNDL_done) ? 0 : 1;
+
+    if ( hvm_msr_read_intercept(regs) == X86EMUL_OKAY ) {
+        __update_guest_eip(inst_len);
+        rc = 0;
+    }
+#endif
+
+    dbgp1("msr read c:%lx a:%lx d:%lx RIP:%lx RSP:%lx\n", regs->ecx, regs->eax, 
+          regs->edx, vmr(GUEST_RIP), vmr(GUEST_RSP));
+    return rc;
+}
+
+/* for now just scratch the cpu since nothing else will run on it. eventually
+ * we need to save and restore these MSRs 
+ * returns : 0 success */
+static noinline int vmxit_msr_write(struct cpu_user_regs *regs)
+{
+    uint inst_len = __get_instruction_length();
+    int rc=1;
+#if 0
+    wrmsr(regs->ecx, regs->eax, regs->edx);
+
+    rc = (long_mode_do_msr_write(regs) == HNDL_done) ? 0 : 1;
+    return rc;
+#endif
+
+    dbgp1("MUK: msr write:0x%lx. eax:0x%lx edx:0x%lx\n", regs->ecx, 
+          regs->eax,regs->edx);
+    if ( hvm_msr_write_intercept(regs) == X86EMUL_OKAY ) {
+        __update_guest_eip(inst_len);
+        rc = 0;
+    }
+    return rc;
+}
+
+/* rc == 0: handled the MTF vmexit */
+static noinline int vmxit_mtf(struct cpu_user_regs *regs)
+{
+    struct vcpu *vp = current;
+    int rc=1, ss=vp->arch.hvm_vcpu.single_step; 
+
+    dbgp2("\n");
+    vp->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
+    __vmwrite(CPU_BASED_VM_EXEC_CONTROL, vp->arch.hvm_vmx.exec_control);
+    vp->arch.hvm_vcpu.single_step = 0;
+
+    /* kdb will set hvm_vcpu.single_step again if ss command */
+    if (kdb_handle_trap_entry(TRAP_debug, regs)) { /* TBD: ifdef KDB */
+        rc = 0;
+    } else if ( vp->domain->debugger_attached && ss ) {
+        domain_pause_for_debugger();
+        rc = 0;
+    }
+    return rc;
+}
+
+volatile int mukprintpf;
+/* rc == 0: handled the exception or NMI */
+static noinline int vmxit_exception(struct cpu_user_regs *regs)
+{
+    unsigned int vector = (__vmread(VM_EXIT_INTR_INFO)) & INTR_INFO_VECTOR_MASK;
+    int rc=1; 
+
+    dbgp2(" exception. vec:%d cs:%x\n", vector, vmr(GUEST_CS_SELECTOR));
+    if (vector == TRAP_debug) {
+        if (kdb_handle_trap_entry(vector, regs)) /* TBD: ifdef KDB */
+            rc = 0;
+        else {
+            domain_pause_for_debugger();
+            rc = 0;
+        }
+    } 
+    if (vector == TRAP_int3) {
+        int inst_len = __get_instruction_length();
+        __update_guest_eip(inst_len);
+
+        if (kdb_handle_trap_entry(vector, regs))
+            rc = 0;
+        else {
+            kdbp("[%d]MUK: domain pause for debugger\n", smp_processor_id());
+            current->arch.gdbsx_vcpu_event = TRAP_int3;
+            domain_pause_for_debugger();
+            rc = 0;
+        }
+    } 
+
+    if (vector == TRAP_no_device) {
+        vmx_fpu_dirty_intercept();
+        rc = 0;
+    }
+
+    if (vector == TRAP_gp_fault) {
+        regs->error_code = __vmread(VM_EXIT_INTR_ERROR_CODE);
+        kdbp("MUK: inject GP: errcode:0x%04x RIP:%016lx RSP:%016lx\n", 
+             regs->error_code, (ulong)vmr(GUEST_RIP), 
+             (ulong)vmr(GUEST_RSP));
+
+        kdb_trap_immed(KDB_TRAP_NONFATAL);
+        /* vmx_inject_hw_exception(TRAP_gp_fault, regs->error_code); */
+        rc = 1;
+    }
+
+    if (vector == TRAP_page_fault) {
+        extern int fixup_page_fault(unsigned long , struct cpu_user_regs *);
+        ulong eflags_sav = regs->eflags;
+        unsigned long va = __vmread(EXIT_QUALIFICATION);
+
+        regs->error_code = __vmread(VM_EXIT_INTR_ERROR_CODE);
+
+        if (mukprintpf)
+            kdbp("MUK:PF va:%016lx errcode:0x%04x RIP:%016lx RSP:%016lx", 
+                 va, regs->error_code, (ulong)vmr(GUEST_RIP), 
+                 (ulong)vmr(GUEST_RSP));
+
+        regs->eflags |= X86_EFLAGS_IF;
+        if (fixup_page_fault(va, regs) == 0) {
+            if (mukprintpf)
+                kdbp(" NOT ");
+            current->arch.hvm_vcpu.guest_cr[2] = va;
+            vmx_inject_hw_exception(TRAP_page_fault, regs->error_code);
+        }
+        regs->eflags = eflags_sav;
+        if (mukprintpf)
+            kdbp(" fixedup\n");
+        rc = 0;
+    }
+
+    /* TBD: call do_guest_trap() here */
+    if (rc)
+        kdbp("MUK: Unhandled trap vector:%d\n", vector);
+    return rc;
+}
+
+int vmxit_invlpg(void)
+{
+    int inst_len = __get_instruction_length();
+    ulong vaddr = __vmread(EXIT_QUALIFICATION);
+
+    KASSERT(hap_enabled(current->domain));
+    __update_guest_eip(inst_len);
+    vpid_sync_vcpu_gva(current, vaddr);
+    return 0;
+}
+
+/* rc == 0: success */
+static noinline int vmxit_vmcall(struct cpu_user_regs *regs)
+{
+    extern void *hvm_hypercall64_table[NR_hypercalls];
+    int rc, inst_len=__get_instruction_length();
+
+    if (regs->eax >= NR_hypercalls || hvm_hypercall64_table[regs->eax] ==NULL) {
+        kdbp("MUK: UnImplemented HCALL:%d\n", regs->eax);
+        return 1;
+    }
+    dbgp2("vmxit_vmcall: hcall eax:$%ld\n", regs->eax);
+    if (regs->eax == __HYPERVISOR_sched_op && regs->rdi == SCHEDOP_shutdown) {
+        kdbp("MUK: SCHEDOP_shutdown\n");
+        return 1;
+    }
+
+    rc = hvm_do_hypercall(regs);
+#if 0
+    extern int hybrid_do_hypercall(struct cpu_user_regs *regs);
+    rc = hybrid_do_hypercall(regs);
+#endif
+
+    if (rc != HVM_HCALL_preempted)
+        __update_guest_eip(inst_len);
+
+    if (rc != HVM_HCALL_completed) {
+        printk("hvm_do_hypercall rc:%d\n", rc);
+        rc = 1;
+    } else
+        rc = 0;
+
+    return rc;
+}
+
+static noinline uint64_t *get_gpr_ptr(struct cpu_user_regs *regs, uint gpr)
+{
+    switch (gpr)
+    {
+        case VMX_CONTROL_REG_ACCESS_GPR_EAX:
+            return &regs->eax;
+        case VMX_CONTROL_REG_ACCESS_GPR_ECX:
+            return &regs->ecx;
+        case VMX_CONTROL_REG_ACCESS_GPR_EDX:
+            return &regs->edx;
+        case VMX_CONTROL_REG_ACCESS_GPR_EBX:
+            return &regs->ebx;
+        case VMX_CONTROL_REG_ACCESS_GPR_ESP:
+            return &regs->esp;
+        case VMX_CONTROL_REG_ACCESS_GPR_EBP:
+            return &regs->ebp;
+        case VMX_CONTROL_REG_ACCESS_GPR_ESI:
+            return &regs->esi;
+        case VMX_CONTROL_REG_ACCESS_GPR_EDI:
+            return &regs->edi;
+        case VMX_CONTROL_REG_ACCESS_GPR_R8:
+            return &regs->r8;
+        case VMX_CONTROL_REG_ACCESS_GPR_R9:
+            return &regs->r9;
+        case VMX_CONTROL_REG_ACCESS_GPR_R10:
+            return &regs->r10;
+        case VMX_CONTROL_REG_ACCESS_GPR_R11:
+            return &regs->r11;
+        case VMX_CONTROL_REG_ACCESS_GPR_R12:
+            return &regs->r12;
+        case VMX_CONTROL_REG_ACCESS_GPR_R13:
+            return &regs->r13;
+        case VMX_CONTROL_REG_ACCESS_GPR_R14:
+            return &regs->r14;
+        case VMX_CONTROL_REG_ACCESS_GPR_R15:
+            return &regs->r15;
+        default:
+            return NULL;
+    }
+}
+/* rc == 0: success */
+static noinline int access_cr0(struct cpu_user_regs *regs, uint acc_typ, 
+                               uint64_t *regp)
+{
+    struct vcpu *vp = current;
+
+    if (acc_typ == VMX_CONTROL_REG_ACCESS_TYPE_MOV_TO_CR )
+    {
+        unsigned long new_cr0 = *regp;
+        unsigned long old_cr0 = __vmread(GUEST_CR0);
+
+        dbgp2("MUK:writing to CR0. RIP:%lx val:0x%lx\n", vmr(GUEST_RIP),*regp);
+        if ( (u32)new_cr0 != new_cr0 )
+        {
+            HVM_DBG_LOG(DBG_LEVEL_1, 
+                        "Guest setting upper 32 bits in CR0: %lx", new_cr0);
+            return 1;
+        }
+
+        new_cr0 &= ~HVM_CR0_GUEST_RESERVED_BITS;
+        /* ET is reserved and should be always be 1. */
+        new_cr0 |= X86_CR0_ET;
+
+        /* hybrid cannot change to real mode */
+        if ( (new_cr0 & (X86_CR0_PE|X86_CR0_PG)) != (X86_CR0_PG|X86_CR0_PE) ) {
+            kdbp("Guest attempting to turn off PE/PG. CR0:%lx\n", new_cr0);
+            return 1;
+        }
+        /* TS going from 1 to 0 */
+        if ( (old_cr0 & X86_CR0_TS) && ((new_cr0 & X86_CR0_TS)==0) )
+            vmx_fpu_enter(vp);
+
+        vp->arch.hvm_vcpu.hw_cr[0] = vp->arch.hvm_vcpu.guest_cr[0] = new_cr0;
+        __vmwrite(GUEST_CR0, new_cr0);
+        __vmwrite(CR0_READ_SHADOW, new_cr0);
+    } else {
+        *regp = __vmread(GUEST_CR0);
+    } 
+    return 0;
+}
+
+/* rc == 0: success */
+static noinline int access_cr4(struct cpu_user_regs *regs, uint acc_typ, 
+                               uint64_t *regp)
+{
+    if (acc_typ == VMX_CONTROL_REG_ACCESS_TYPE_MOV_TO_CR )
+    {
+        u64 old_cr4 = __vmread(GUEST_CR4);
+        /* kdbp("MUK:writing to CR4. val:0x%lx\n", *regp); */
+
+        if ( (old_cr4 ^ (*regp)) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE) )
+            vpid_sync_all();
+
+        /* hybrid_verify_cr4_wr(*regp)); */
+        __vmwrite(GUEST_CR4, *regp);
+    } else {
+        *regp = __vmread(GUEST_CR4);
+        kdbp("MUK: read cr4. val:0x%lx\n", *regp);
+    } 
+    return 0;
+}
+
+/* rc == 0: success */
+static noinline int vmxit_cr_access(struct cpu_user_regs *regs)
+{
+    unsigned long exit_qualification = __vmread(EXIT_QUALIFICATION);
+    uint inst_len = __get_instruction_length();
+    uint acc_typ = exit_qualification & VMX_CONTROL_REG_ACCESS_TYPE;
+    int cr, rc = 1;
+
+    switch ( acc_typ )
+    {
+        case VMX_CONTROL_REG_ACCESS_TYPE_MOV_TO_CR:
+        case VMX_CONTROL_REG_ACCESS_TYPE_MOV_FROM_CR:
+        {
+            uint gpr = exit_qualification & VMX_CONTROL_REG_ACCESS_GPR;
+            uint64_t *regp = get_gpr_ptr(regs, gpr);
+            cr = exit_qualification & VMX_CONTROL_REG_ACCESS_NUM;
+
+            if (regp == NULL)
+                break;
+
+            /* pl don't embed switch statements */
+            if (cr == 0)
+                rc = access_cr0(regs, acc_typ, regp);
+            else if (cr == 4) 
+                rc = access_cr4(regs, acc_typ, regp);
+
+            if (rc == 0)
+                __update_guest_eip(inst_len);
+            break;
+        }
+        case VMX_CONTROL_REG_ACCESS_TYPE_CLTS:
+        {
+#if 0
+            unsigned long cr0 = __vmread(GUEST_CR0);
+            cr0 &= ~X86_CR0_TS;
+#endif
+            struct vcpu *vp = current;
+            unsigned long cr0 = vp->arch.hvm_vcpu.guest_cr[0] & ~X86_CR0_TS;
+            vp->arch.hvm_vcpu.hw_cr[0] = vp->arch.hvm_vcpu.guest_cr[0] = cr0;
+            vmx_fpu_enter(vp);
+            __vmwrite(GUEST_CR0, cr0);
+            __vmwrite(CR0_READ_SHADOW, cr0);
+            __update_guest_eip(inst_len);
+            rc = 0;
+        }
+    }
+    return rc;
+}
+
+#if 0
+/* emulate write_cr3(read_cr3()) in guest. */
+static noinline int vmxit_invvpid(void)
+{
+    hvm_asid_flush_vcpu(current);
+    return 0;
+}
+#endif
+
+volatile int mukprtsc=1;
+void hybrid_vmx_vmexit_handler(struct cpu_user_regs *regs)
+{
+    unsigned int vector, exit_reason = __vmread(VM_EXIT_REASON);
+    int rc=0, ccpu = smp_processor_id();
+    struct vcpu *vp = current;
+
+    dbgp1("MUK:[%d]left VMCS exitreas:%d RIP:%lx RSP:%lx EFLAGS:%lx CR0:%lx\n", 
+          ccpu, exit_reason, vmr(GUEST_RIP), vmr(GUEST_RSP), regs->rflags, 
+          vmr(GUEST_CR0));
+
+    KASSERT( (vmr(GUEST_CR0)) != 0x8);
+    switch ( (uint16_t)exit_reason )
+    {
+        case EXIT_REASON_EXCEPTION_NMI:      /* 0 */
+            rc = vmxit_exception(regs);
+            break;
+            
+        case EXIT_REASON_EXTERNAL_INTERRUPT: /* 1 */
+        {
+            vector = __vmread(VM_EXIT_INTR_INFO);
+            vector &= INTR_INFO_VECTOR_MASK;
+            dbgp2("MUK: [%d] exit vmcs reas:%d vec:%d cr0:0x%016lx\n", ccpu, 
+                 exit_reason, vector, vmr(GUEST_CR0));
+            vmx_do_extint(regs);
+            break;
+        }
+
+        case EXIT_REASON_TRIPLE_FAULT:  /* 2 */
+        {
+#if 0
+            static int once;
+     if (!once)
+     kdbp("MUK:[%d]left VMCS exitreas:%d RIP:%lx RSP:%lx EFLAGS:%lx CR0:%lx\n",
+          ccpu, exit_reason, vmr(GUEST_RIP), vmr(GUEST_RSP), regs->rflags, 
+          vmr(GUEST_CR0));
+            once = 1;
+            vmx_inject_hw_exception(TRAP_gp_fault, regs->error_code);
+            rc = 0;
+#endif
+     kdbp("MUK:[%d]left VMCS exitreas:%d RIP:%lx RSP:%lx EFLAGS:%lx CR3:%lx\n",
+          ccpu, exit_reason, vmr(GUEST_RIP), vmr(GUEST_RSP), regs->rflags, 
+          vmr(GUEST_CR3));
+
+            __vmwrite(GUEST_CR3, 0x1803000);
+    if ( paging_mode_hap(vp->domain) && hvm_paging_enabled(vp) )
+        vp->arch.hvm_vcpu.guest_cr[3] = vp->arch.hvm_vcpu.hw_cr[3] =
+                                                           __vmread(GUEST_CR3);
+            kdb_trap_immed(KDB_TRAP_NONFATAL);
+            rc = 1;
+            break;
+        }
+        case EXIT_REASON_PENDING_VIRT_INTR:  /* 7 */
+        {
+            struct vcpu *v = current;
+            /* Disable the interrupt window. */
+            v->arch.hvm_vmx.exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+            __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
+            break;
+        }
+
+        case EXIT_REASON_CPUID:              /* 10 */
+        {
+            int ilen=__get_instruction_length();
+            __update_guest_eip(ilen);
+            dbgp2("cpuid:%d RIP:%lx\n", regs->eax, vmr(GUEST_RIP));
+            vmx_do_cpuid(regs);
+            break;
+        }
+
+#if 0
+        case EXIT_REASON_INVLPG:             /* 14 */
+            rc = vmxit_invlpg();
+            break;
+#endif
+        case EXIT_REASON_RDTSC:              /* 16 */
+        {
+#if 0
+            uint64_t tsc;
+            int ilen=__get_instruction_length();
+            rdtscll(tsc);
+            regs->eax = (uint32_t)tsc;
+            regs->edx = (uint32_t)(tsc >> 32);
+#endif
+            rdtsc(regs->eax, regs->edx);
+if (mukprtsc)
+    kdbp(" RDTSC: eax:%lx edx:%lx\n", regs->eax, regs->edx);
+            __update_guest_eip(__get_instruction_length());
+            rc = 0;
+            break;
+        }
+
+        case EXIT_REASON_VMCALL:             /* 18 */
+            rc = vmxit_vmcall(regs);
+            break;
+
+        case EXIT_REASON_CR_ACCESS:          /* 28 */
+            rc = vmxit_cr_access(regs);
+            break;
+
+        case EXIT_REASON_DR_ACCESS:          /* 29 */
+        {
+            unsigned long exit_qualification = __vmread(EXIT_QUALIFICATION);
+            vmx_dr_access(exit_qualification, regs);
+            break;
+        }
+        case EXIT_REASON_MSR_READ:           /* 31 */
+            rc = vmxit_msr_read(regs);
+            break;
+
+        case EXIT_REASON_MSR_WRITE:          /* 32 */
+            rc = vmxit_msr_write(regs);
+            break;
+
+        case EXIT_REASON_MONITOR_TRAP_FLAG:  /* 37 */
+            rc = vmxit_mtf(regs);
+            break;
+#if 0
+        case EXIT_REASON_INVVPID:            /* 53 */
+            rc = vmxit_invvpid();
+            break;
+#endif
+        default: 
+            rc = 1;
+    }
+    if (rc) {
+        unsigned long exit_qualification = __vmread(EXIT_QUALIFICATION);
+        local_irq_enable();
+        kdbp("MUK: [%d] exit_reas:%d 0x%lx qual:%ld 0x%lx cr0:0x%016lx\n", 
+             ccpu, exit_reason, exit_reason, exit_qualification,
+             exit_qualification, vmr(GUEST_CR0));
+        kdbp("MUK: [%d] RIP:%lx RSP:%lx\n", ccpu, 
+             vmr(GUEST_RIP), vmr(GUEST_RSP));
+        domain_crash_synchronous();
+    }
+
+    /*dbgp("MUK: will enter vmcs: cs:%x ss:%x\n", vmr(GUEST_CS_SELECTOR),
+         vmr(GUEST_SS_SELECTOR)); */
+
+    dbgp1("MUK: will enter vmcs:RIP:%lx RSP:%lx cr0:%lx eflags:%lx\n", 
+          vmr(GUEST_RIP), vmr(GUEST_RSP), vmr(GUEST_CR0), regs->rflags);
+
+    local_irq_enable();
+    KASSERT( (vmr(GUEST_CR0)) != 0x8);
+}
+
+void hybrid_flush_tlb(void)
+{
+    vpid_sync_all();
+}
+
+void hybrid_do_invlpg(ulong addr)
+{
+    /* vpid_sync_all(); */
+    vpid_sync_vcpu_gva(current, addr);
+}
+
+
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/vmx/intr.c	Thu Nov 17 15:37:30 2011 -0800
@@ -125,8 +125,9 @@ asmlinkage void vmx_intr_assist(void)
         return;
     }
 
-    /* Crank the handle on interrupt state. */
-    pt_update_irq(v);
+    if (!is_hybrid_vcpu(v))
+        /* Crank the handle on interrupt state. */
+        pt_update_irq(v);
 
     do {
         intack = hvm_vcpu_has_pending_irq(v);
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/vmx/vmcs.c	Thu Nov 17 15:37:30 2011 -0800
@@ -593,6 +593,311 @@ void vmx_disable_intercept_for_msr(struc
     }
 }
 
+
+void hybrid_update_cr3(struct vcpu *v)
+{
+    vmx_vmcs_enter(v);
+    __vmwrite(GUEST_CR3, v->arch.cr3);
+    __vmwrite(HOST_CR3, v->arch.cr3);
+
+    vpid_sync_all();
+    /* hvm_asid_flush_vcpu(v); */
+    vmx_vmcs_exit(v);
+}
+
+static int hybrid_construct_vmcs(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    uint16_t sysenter_cs;
+    unsigned long sysenter_eip;
+    u32 vmexit_ctl = vmx_vmexit_control;
+    u32 vmentry_ctl = vmx_vmentry_control;
+    u64 u64val;
+
+    vmx_vmcs_enter(v);
+
+    /* VMCS controls. */
+    vmx_pin_based_exec_control &= ~PIN_BASED_VIRTUAL_NMIS;
+    __vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_control);
+
+    v->arch.hvm_vmx.exec_control = vmx_cpu_based_exec_control;
+
+    if ( v->domain->arch.vtsc )
+        v->arch.hvm_vmx.exec_control &= ~CPU_BASED_RDTSC_EXITING;
+
+    if ( paging_mode_hap(d) )
+    {
+        v->arch.hvm_vmx.exec_control &= ~(CPU_BASED_INVLPG_EXITING |
+                                          CPU_BASED_CR3_LOAD_EXITING |
+                                          CPU_BASED_CR3_STORE_EXITING);
+    }
+    v->arch.hvm_vmx.exec_control |= CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
+    v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
+    v->arch.hvm_vmx.exec_control &= ~CPU_BASED_ACTIVATE_IO_BITMAP; /* ??? */
+    v->arch.hvm_vmx.exec_control |= CPU_BASED_ACTIVATE_MSR_BITMAP;
+    v->arch.hvm_vmx.exec_control &= ~CPU_BASED_TPR_SHADOW;
+    v->arch.hvm_vmx.exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
+
+    kdbp("MUK: writing proc based exec controls:%x\n", 
+                 v->arch.hvm_vmx.exec_control);
+    __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
+
+    /* MSR access bitmap. */
+    if ( cpu_has_vmx_msr_bitmap )
+    {
+        unsigned long *msr_bitmap = alloc_xenheap_page();
+
+        if ( msr_bitmap == NULL )
+            return -ENOMEM;
+
+        memset(msr_bitmap, ~0, PAGE_SIZE);
+        v->arch.hvm_vmx.msr_bitmap = msr_bitmap;
+        __vmwrite(MSR_BITMAP, virt_to_maddr(msr_bitmap));
+
+        vmx_disable_intercept_for_msr(v, MSR_FS_BASE);
+        vmx_disable_intercept_for_msr(v, MSR_GS_BASE);
+        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_CS);
+        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_ESP);
+        vmx_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_EIP);
+
+        /* pure hvm doesn't do this. safe? see: long_mode_do_msr_write() */
+#if 0
+        vmx_disable_intercept_for_msr(v, MSR_STAR);
+        vmx_disable_intercept_for_msr(v, MSR_LSTAR);
+        vmx_disable_intercept_for_msr(v, MSR_CSTAR);
+        vmx_disable_intercept_for_msr(v, MSR_SYSCALL_MASK);
+#endif
+        vmx_disable_intercept_for_msr(v, MSR_SHADOW_GS_BASE);
+
+        kdbp("MUK: disabled intercepts for few msrs\n");
+
+    } else {
+        kdbp("MUK: CPU does NOT have msr bitmap\n");
+        for (;;) cpu_relax();
+    }
+
+    if ( !cpu_has_vmx_vpid ) {
+        printk("ERROR: VPID support is required to run PV in HVM container\n");
+        return -ESRCH;
+    }
+
+    v->arch.hvm_vmx.secondary_exec_control = vmx_secondary_exec_control;
+
+    if ( cpu_has_vmx_secondary_exec_control ) {
+        v->arch.hvm_vmx.secondary_exec_control &= ~0x4FF; /* turn off all */
+#if 0
+        v->arch.hvm_vmx.secondary_exec_control &= 
+                                       ~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
+        v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_RDTSCP;
+
+        v->arch.hvm_vmx.secondary_exec_control &= 
+                                             ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
+#endif
+        v->arch.hvm_vmx.secondary_exec_control |= 
+                                              SECONDARY_EXEC_PAUSE_LOOP_EXITING;
+        v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_VPID;
+
+        if ( paging_mode_hap(d) )
+            v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_EPT;
+
+        kdbp("MUK: muk_construct_vmcs: sec exec:0x%x\n",
+                                        v->arch.hvm_vmx.secondary_exec_control);
+        __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+                  v->arch.hvm_vmx.secondary_exec_control);
+    } else {
+        printk("ERROR: NO Secondary Exec control\n");
+        return -ESRCH;
+    }
+
+    __vmwrite(VIRTUAL_PROCESSOR_ID, v->arch.hvm_vcpu.asid);
+
+    if ( !paging_mode_hap(d) )
+        vmexit_ctl &= ~(VM_EXIT_SAVE_GUEST_PAT | VM_EXIT_LOAD_HOST_PAT);
+    __vmwrite(VM_EXIT_CONTROLS, vmexit_ctl);
+
+    #define VM_ENTRY_LOAD_DEBUG_CTLS 0x4
+    #define VM_ENTRY_LOAD_EFER 0x8000
+    #define GUEST_EFER 0x2806        /* see page 23-20 */
+    #define GUEST_EFER_HIGH 0x2807   /* see page 23-20 */
+    vmentry_ctl &= ~VM_ENTRY_LOAD_DEBUG_CTLS;
+    vmentry_ctl &= ~VM_ENTRY_LOAD_EFER;
+    vmentry_ctl &= ~VM_ENTRY_SMM;
+    vmentry_ctl &= ~VM_ENTRY_DEACT_DUAL_MONITOR;
+    vmentry_ctl |= VM_ENTRY_IA32E_MODE;
+    if ( !paging_mode_hap(d) )
+        vmentry_ctl &= ~VM_ENTRY_LOAD_GUEST_PAT;
+    kdbp("MUK:muk_construct_vmcs(). vmentry_ctl:0x%x\n", vmentry_ctl);
+    __vmwrite(VM_ENTRY_CONTROLS, vmentry_ctl);
+
+    /* MSR intercepts. */
+    __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
+    __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
+    __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
+
+    /* Host data selectors. */
+    __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
+    __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
+    __vmwrite(HOST_ES_SELECTOR, __HYPERVISOR_DS);
+    __vmwrite(HOST_FS_SELECTOR, 0);
+    __vmwrite(HOST_GS_SELECTOR, 0);
+    __vmwrite(HOST_FS_BASE, 0);
+    __vmwrite(HOST_GS_BASE, 0);
+
+    vmx_set_host_env(v);
+
+    /* Host control registers. */
+    v->arch.hvm_vmx.host_cr0 = read_cr0() | X86_CR0_TS;
+    __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0);
+    __vmwrite(HOST_CR4, mmu_cr4_features|(cpu_has_xsave ? X86_CR4_OSXSAVE : 0));
+
+    /* Host CS:RIP. */
+    __vmwrite(HOST_CS_SELECTOR, __HYPERVISOR_CS);
+    __vmwrite(HOST_RIP, (unsigned long)vmx_asm_vmexit_handler);
+
+    /* Host SYSENTER CS:RIP. */
+    rdmsrl(MSR_IA32_SYSENTER_CS, sysenter_cs);
+    __vmwrite(HOST_SYSENTER_CS, sysenter_cs);
+    rdmsrl(MSR_IA32_SYSENTER_EIP, sysenter_eip);
+    __vmwrite(HOST_SYSENTER_EIP, sysenter_eip);
+
+    __vmwrite(VM_ENTRY_INTR_INFO, 0);
+
+    __vmwrite(CR3_TARGET_COUNT, 0);
+
+    __vmwrite(GUEST_ACTIVITY_STATE, 0);
+
+    __vmwrite(GUEST_CS_BASE, 0);
+    __vmwrite(GUEST_CS_LIMIT, ~0u);
+    __vmwrite(GUEST_CS_AR_BYTES, 0xa09b); /* CS.L == 1 */
+    __vmwrite(GUEST_CS_SELECTOR, 0x10);
+
+    __vmwrite(GUEST_DS_BASE, 0);
+    __vmwrite(GUEST_DS_LIMIT, ~0u);
+    __vmwrite(GUEST_DS_AR_BYTES, 0xc093);
+    __vmwrite(GUEST_DS_SELECTOR, 0x18);
+
+    __vmwrite(GUEST_SS_BASE, 0);         /* use same seg as DS */
+    __vmwrite(GUEST_SS_LIMIT, ~0u);
+    __vmwrite(GUEST_SS_AR_BYTES, 0xc093);
+    __vmwrite(GUEST_SS_SELECTOR, 0x18);
+
+    __vmwrite(GUEST_ES_SELECTOR, 0);
+    __vmwrite(GUEST_FS_SELECTOR, 0);
+    __vmwrite(GUEST_GS_SELECTOR, 0);
+
+    /* Guest segment bases. */
+    __vmwrite(GUEST_ES_BASE, 0);
+    __vmwrite(GUEST_FS_BASE, 0);
+    __vmwrite(GUEST_GS_BASE, 0);
+
+    /* Guest segment limits. */
+    __vmwrite(GUEST_ES_LIMIT, ~0u);
+    __vmwrite(GUEST_FS_LIMIT, ~0u);
+    __vmwrite(GUEST_GS_LIMIT, ~0u);
+
+    /* Guest segment AR bytes. */
+    __vmwrite(GUEST_ES_AR_BYTES, 0xc093); /* read/write, accessed */
+    __vmwrite(GUEST_FS_AR_BYTES, 0xc093);
+    __vmwrite(GUEST_GS_AR_BYTES, 0xc093);
+
+    /* Guest IDT. */
+    __vmwrite(GUEST_GDTR_BASE, 0);
+    __vmwrite(GUEST_GDTR_LIMIT, 0);
+
+    /* Guest LDT. */
+    __vmwrite(GUEST_LDTR_AR_BYTES, 0x82); /* LDT */
+    __vmwrite(GUEST_LDTR_SELECTOR, 0);
+    __vmwrite(GUEST_LDTR_BASE, 0);
+    __vmwrite(GUEST_LDTR_LIMIT, 0);
+
+    /* Guest TSS. */
+    __vmwrite(GUEST_TR_AR_BYTES, 0x8b); /* 32-bit TSS (busy) */
+    __vmwrite(GUEST_TR_BASE, 0);
+    __vmwrite(GUEST_TR_LIMIT, 0xff);
+
+    __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+    __vmwrite(GUEST_DR7, 0);
+    __vmwrite(VMCS_LINK_POINTER, ~0UL);
+
+    if (paging_mode_hap(d)) {
+        __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
+        __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+        __vmwrite(EXCEPTION_BITMAP,
+                  HVM_TRAP_MASK | TRAP_debug | 
+                  (1U<<TRAP_int3) | (1U << TRAP_no_device));
+    } else {
+        /* vmexit only on write to protected page, err code: 0x3 */
+        __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0xffffffff);
+        __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0x3);
+        __vmwrite(EXCEPTION_BITMAP, 0xffffffff);
+    }
+
+#if 0
+    __vmwrite(EXCEPTION_BITMAP,
+              HVM_TRAP_MASK | TRAP_debug | TRAP_gp_fault |
+              (1U<<TRAP_int3) | (1U << TRAP_page_fault)|(1U << TRAP_no_device));
+#endif
+    __vmwrite(TSC_OFFSET, 0);
+
+#if 0
+    v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PG | X86_CR0_PE | X86_CR0_ET;
+    hvm_update_guest_cr(v, 0);
+
+    v->arch.hvm_vcpu.guest_cr[4] = 0;
+    hvm_update_guest_cr(v, 4);
+#endif
+
+#if 0
+    u64val = X86_CR0_PG | X86_CR0_PE | X86_CR0_ET | X86_CR0_TS |
+             X86_CR0_NE | X86_CR0_WP;
+#endif
+    /* make sure to set WP bit so rdonly pages are not written from CPL 0 */
+    u64val = X86_CR0_PG | X86_CR0_NE | X86_CR0_PE | X86_CR0_WP;
+    __vmwrite(GUEST_CR0, u64val);
+    __vmwrite(CR0_READ_SHADOW, u64val);
+    v->arch.hvm_vcpu.hw_cr[0] = v->arch.hvm_vcpu.guest_cr[0] = u64val;
+
+    u64val = X86_CR4_PAE | X86_CR4_VMXE;
+    __vmwrite(GUEST_CR4, u64val);
+    __vmwrite(CR4_READ_SHADOW, u64val);
+    v->arch.hvm_vcpu.guest_cr[4] = u64val;
+
+    __vmwrite(CR0_GUEST_HOST_MASK, ~0UL);
+    __vmwrite(CR4_GUEST_HOST_MASK, ~0UL);
+
+     v->arch.hvm_vmx.vmx_realmode = 0;
+
+    if ( paging_mode_hap(d) )
+    {
+        __vmwrite(EPT_POINTER, d->arch.hvm_domain.vmx.ept_control.eptp);
+#ifdef __i386__
+        __vmwrite(EPT_POINTER_HIGH,
+                  d->arch.hvm_domain.vmx.ept_control.eptp >> 32);
+#endif
+    }
+
+    if ( cpu_has_vmx_pat && paging_mode_hap(d) )
+    {
+        u64 host_pat, guest_pat;
+
+        rdmsrl(MSR_IA32_CR_PAT, host_pat);
+        guest_pat = MSR_IA32_CR_PAT_RESET;
+
+        __vmwrite(HOST_PAT, host_pat);
+        __vmwrite(GUEST_PAT, guest_pat);
+#ifdef __i386__
+JUNK
+        __vmwrite(HOST_PAT_HIGH, host_pat >> 32);
+        __vmwrite(GUEST_PAT_HIGH, guest_pat >> 32);
+#endif
+    }
+    vmx_vmcs_exit(v);
+#if 0
+    paging_update_paging_modes(v); /* will update HOST & GUEST_CR3 as reqd */
+#endif
+    return 0;
+}
+
 static int construct_vmcs(struct vcpu *v)
 {
     struct domain *d = v->domain;
@@ -601,6 +906,9 @@ static int construct_vmcs(struct vcpu *v
     u32 vmexit_ctl = vmx_vmexit_control;
     u32 vmentry_ctl = vmx_vmentry_control;
 
+    if (is_hybrid_domain(d))
+        return hybrid_construct_vmcs(v);
+
     vmx_vmcs_enter(v);
 
     /* VMCS controls. */
@@ -1001,8 +1309,10 @@ void vmx_do_resume(struct vcpu *v)
 
         vmx_clear_vmcs(v);
         vmx_load_vmcs(v);
-        hvm_migrate_timers(v);
-        hvm_migrate_pirqs(v);
+        if (!is_hybrid_vcpu(v)) {
+            hvm_migrate_timers(v);
+            hvm_migrate_pirqs(v);
+        }
         vmx_set_host_env(v);
         hvm_asid_flush_vcpu(v);
     }
@@ -1018,14 +1328,6 @@ void vmx_do_resume(struct vcpu *v)
     reset_stack_and_jump(vmx_asm_do_vmentry);
 }
 
-static unsigned long vmr(unsigned long field)
-{
-    int rc;
-    unsigned long val;
-    val = __vmread_safe(field, &rc);
-    return rc ? 0 : val;
-}
-
 static void vmx_dump_sel(char *name, uint32_t selector)
 {
     uint32_t sel, attr, limit;
@@ -1263,6 +1565,8 @@ static void noinline kdb_print_vmcs(stru
     vmx_dump_sel("LDTR", GUEST_LDTR_SELECTOR);
     vmx_dump_sel2("IDTR", GUEST_IDTR_LIMIT);
     vmx_dump_sel("TR", GUEST_TR_SELECTOR);
+    kdbp("Guest EFER = 0x%08x%08x\n",
+           (uint32_t)vmr(GUEST_EFER_HIGH), (uint32_t)vmr(GUEST_EFER));
     kdbp("Guest PAT = 0x%08x%08x\n",
            (uint32_t)vmr(GUEST_PAT_HIGH), (uint32_t)vmr(GUEST_PAT));
     x  = (unsigned long long)vmr(TSC_OFFSET_HIGH) << 32;
@@ -1276,6 +1580,10 @@ static void noinline kdb_print_vmcs(stru
            (int)vmr(GUEST_INTERRUPTIBILITY_INFO),
            (int)vmr(GUEST_ACTIVITY_STATE));
 
+    kdbp("MSRs: entry_load:$%d exit_load:$%d exit_store:$%d\n",
+         vmr(VM_ENTRY_MSR_LOAD_COUNT), vmr(VM_EXIT_MSR_LOAD_COUNT),
+         vmr(VM_EXIT_MSR_STORE_COUNT));
+
     kdbp("\n*** Host State ***\n");
     kdbp("RSP = 0x%016llx  RIP = 0x%016llx\n", 
            (unsigned long long)vmr(HOST_RSP),
@@ -1316,6 +1624,9 @@ static void noinline kdb_print_vmcs(stru
            (uint32_t)vmr(VM_EXIT_CONTROLS));
     kdbp("ExceptionBitmap=%08x\n",
            (uint32_t)vmr(EXCEPTION_BITMAP));
+    kdbp("PAGE_FAULT_ERROR_CODE  MASK:0x%lx  MATCH:0x%lx\n", 
+         (unsigned long)vmr(PAGE_FAULT_ERROR_CODE_MASK),
+         (unsigned long)vmr(PAGE_FAULT_ERROR_CODE_MATCH));
     kdbp("VMEntry: intr_info=%08x errcode=%08x ilen=%08x\n",
            (uint32_t)vmr(VM_ENTRY_INTR_INFO),
            (uint32_t)vmr(VM_ENTRY_EXCEPTION_ERROR_CODE),
@@ -1344,8 +1655,7 @@ static void noinline kdb_print_vmcs(stru
  *     do __vmreads. So, the VMCS pointer can't be left cleared.
  *   - Doing __vmpclear will set the vmx state to 'clear', so to resume a
  *     vmlaunch must be done and not vmresume. This means, we must clear 
- *     arch_vmx->launched. Just call __vmx_clear_vmcs(), hopefully it won't keep
- *     changing...
+ *     arch_vmx->launched.
  */
 void kdb_curr_cpu_flush_vmcs(void)
 {
@@ -1358,12 +1668,14 @@ void kdb_curr_cpu_flush_vmcs(void)
     /* looks like we got one. unfortunately, current_vmcs points to vmcs 
      * and not VCPU, so we gotta search the entire list... */
     for_each_domain (dp) {
-        if ( !is_hvm_domain(dp) || dp->is_dying)
+        if ( !(is_hvm_or_hyb_domain(dp)) || dp->is_dying)
             continue;
         for_each_vcpu (dp, vp) {
             if (vp->arch.hvm_vmx.active_cpu == smp_processor_id()) {
-                __vmx_clear_vmcs(vp);
+                __vmpclear(virt_to_maddr(vp->arch.hvm_vmx.vmcs));
                 __vmptrld(virt_to_maddr(vp->arch.hvm_vmx.vmcs));
+                vp->arch.hvm_vmx.launched   = 0;
+                kdbp("KDB:[%d] vmcs flushed\n", smp_processor_id());
             }
         }
     }
@@ -1382,7 +1694,7 @@ void kdb_dump_vmcs(domid_t did, int vid)
     ASSERT(!local_irq_is_enabled());     /* kdb should always run disabled */
 
     for_each_domain (dp) {
-        if ( !is_hvm_domain(dp) || dp->is_dying)
+        if ( !(is_hvm_or_hyb_domain(dp)) || dp->is_dying)
             continue;
         if (did != 0 && did != dp->domain_id)
             continue;
@@ -1400,7 +1712,7 @@ void kdb_dump_vmcs(domid_t did, int vid)
         kdbp("\n");
     }
     /* restore orig vmcs pointer for __vmreads in vmx_vmexit_handler() */
-    if (is_hvm_vcpu(current))
+    if (is_hvm_or_hyb_vcpu(current)) 
         __vmptrld(virt_to_maddr(current->arch.hvm_vmx.vmcs));
 }
 #endif
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c	Thu Nov 17 15:37:30 2011 -0800
@@ -68,7 +68,6 @@ static void vmx_cpuid_intercept(
     unsigned int *eax, unsigned int *ebx,
     unsigned int *ecx, unsigned int *edx);
 static void vmx_wbinvd_intercept(void);
-static void vmx_fpu_dirty_intercept(void);
 static int vmx_msr_read_intercept(struct cpu_user_regs *regs);
 static int vmx_msr_write_intercept(struct cpu_user_regs *regs);
 static void vmx_invlpg_intercept(unsigned long vaddr);
@@ -87,6 +86,8 @@ static int vmx_domain_initialise(struct 
     d->arch.hvm_domain.vmx.ept_control.asr  =
         pagetable_get_pfn(d->arch.phys_table);
 
+    if (is_hybrid_domain(d))
+        return 0;
 
     if ( (rc = vmx_alloc_vlapic_mapping(d)) != 0 )
         return rc;
@@ -98,6 +99,10 @@ static void vmx_domain_destroy(struct do
 {
     if ( d->arch.hvm_domain.hap_enabled )
         on_each_cpu(__ept_sync_domain, d, 1);
+
+    if (is_hybrid_domain(d))
+        return;
+
     vmx_free_vlapic_mapping(d);
 }
 
@@ -119,13 +124,19 @@ static int vmx_vcpu_initialise(struct vc
         return rc;
     }
 
-    vpmu_initialise(v);
-
-    vmx_install_vlapic_mapping(v);
-
-    /* %eax == 1 signals full real-mode support to the guest loader. */
-    if ( v->vcpu_id == 0 )
-        v->arch.guest_context.user_regs.eax = 1;
+    /* Hybrid TBD: pmu */
+    if ( !is_hybrid_vcpu(v)) {
+        vpmu_initialise(v);
+
+        vmx_install_vlapic_mapping(v);
+
+        /* %eax == 1 signals full real-mode support to the guest loader. */
+        if ( v->vcpu_id == 0 )
+            v->arch.guest_context.user_regs.eax = 1;
+    } else {
+        /* for hvm_long_mode_enabled(v) */
+        v->arch.hvm_vcpu.guest_efer = EFER_SCE | EFER_LMA | EFER_LME;
+    }
 
     return 0;
 }
@@ -398,6 +409,9 @@ static int vmx_guest_x86_mode(struct vcp
 {
     unsigned int cs_ar_bytes;
 
+if (is_hybrid_vcpu(v))
+    return 8;
+
     if ( unlikely(!(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE)) )
         return 0;
     if ( unlikely(guest_cpu_user_regs()->eflags & X86_EFLAGS_VM) )
@@ -628,7 +642,7 @@ static int vmx_load_vmcs_ctxt(struct vcp
     return 0;
 }
 
-static void vmx_fpu_enter(struct vcpu *v)
+void vmx_fpu_enter(struct vcpu *v)
 {
     setup_fpu(v);
     __vm_clear_bit(EXCEPTION_BITMAP, TRAP_no_device);
@@ -657,6 +671,7 @@ static void vmx_fpu_leave(struct vcpu *v
     {
         v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_TS;
         __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
+KASSERT( (vmr(GUEST_CR0)) != 0x8);
         __vm_set_bit(EXCEPTION_BITMAP, TRAP_no_device);
     }
 }
@@ -1155,6 +1170,7 @@ static void vmx_update_guest_cr(struct v
         v->arch.hvm_vcpu.hw_cr[0] =
             v->arch.hvm_vcpu.guest_cr[0] | hw_cr0_mask;
         __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]);
+KASSERT( (vmr(GUEST_CR0)) != 0x8);
         __vmwrite(CR0_READ_SHADOW, v->arch.hvm_vcpu.guest_cr[0]);
         break;
     }
@@ -1299,6 +1315,7 @@ void vmx_inject_hw_exception(int trap, i
     if ( unlikely(intr_info & INTR_INFO_VALID_MASK) &&
          (((intr_info >> 8) & 7) == X86_EVENTTYPE_HW_EXCEPTION) )
     {
+        KASSERT(!is_hybrid_vcpu(curr));
         trap = hvm_combine_hw_exceptions((uint8_t)intr_info, trap);
         if ( trap == TRAP_double_fault )
             error_code = 0;
@@ -1459,38 +1476,7 @@ void start_vmx(void)
     hvm_enable(&vmx_function_table);
 }
 
-/*
- * Not all cases receive valid value in the VM-exit instruction length field.
- * Callers must know what they're doing!
- */
-static int __get_instruction_length(void)
-{
-    int len;
-    len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe: callers audited */
-    BUG_ON((len < 1) || (len > 15));
-    return len;
-}
-
-static void __update_guest_eip(unsigned long inst_len)
-{
-    struct cpu_user_regs *regs = guest_cpu_user_regs();
-    unsigned long x;
-
-    regs->eip += inst_len;
-    regs->eflags &= ~X86_EFLAGS_RF;
-
-    x = __vmread(GUEST_INTERRUPTIBILITY_INFO);
-    if ( x & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) )
-    {
-        x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS);
-        __vmwrite(GUEST_INTERRUPTIBILITY_INFO, x);
-    }
-
-    if ( regs->eflags & X86_EFLAGS_TF )
-        vmx_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
-}
-
-static void vmx_fpu_dirty_intercept(void)
+void vmx_fpu_dirty_intercept(void)
 {
     struct vcpu *curr = current;
 
@@ -1500,6 +1486,7 @@ static void vmx_fpu_dirty_intercept(void
     if ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) )
     {
         curr->arch.hvm_vcpu.hw_cr[0] &= ~X86_CR0_TS;
+KASSERT( (vmr(GUEST_CR0)) != 0x8);
         __vmwrite(GUEST_CR0, curr->arch.hvm_vcpu.hw_cr[0]);
     }
 }
@@ -1531,7 +1518,7 @@ static void vmx_cpuid_intercept(
     HVMTRACE_5D (CPUID, input, *eax, *ebx, *ecx, *edx);
 }
 
-static void vmx_do_cpuid(struct cpu_user_regs *regs)
+void vmx_do_cpuid(struct cpu_user_regs *regs)
 {
     unsigned int eax, ebx, ecx, edx;
 
@@ -1548,7 +1535,7 @@ static void vmx_do_cpuid(struct cpu_user
     regs->edx = edx;
 }
 
-static void vmx_dr_access(unsigned long exit_qualification,
+void vmx_dr_access(unsigned long exit_qualification,
                           struct cpu_user_regs *regs)
 {
     struct vcpu *v = current;
@@ -2037,7 +2024,7 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
-static void vmx_do_extint(struct cpu_user_regs *regs)
+void vmx_do_extint(struct cpu_user_regs *regs)
 {
     unsigned int vector;
 
@@ -2182,9 +2169,16 @@ static void vmx_failed_vmentry(unsigned 
         break;
     }
 
+#if defined(XEN_KDB_CONFIG)
+    { extern void kdb_dump_vmcs(domid_t did, int vid);
+      printk("\n************* VMCS Area **************\n");
+      kdb_dump_vmcs(curr->domain->domain_id, (curr)->vcpu_id);
+    }
+#else
     printk("************* VMCS Area **************\n");
     vmcs_dump_vcpu(curr);
     printk("**************************************\n");
+#endif
 
     domain_crash(curr->domain);
 }
@@ -2268,6 +2262,8 @@ err:
     return -1;
 }
 
+extern void hybrid_vmx_vmexit_handler(struct cpu_user_regs *regs);
+
 asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs)
 {
     unsigned int exit_reason, idtv_info, intr_info = 0, vector = 0;
@@ -2278,6 +2274,11 @@ asmlinkage void vmx_vmexit_handler(struc
         v->arch.hvm_vcpu.guest_cr[3] = v->arch.hvm_vcpu.hw_cr[3] =
             __vmread(GUEST_CR3);
 
+    if ( is_hybrid_vcpu(v)) {
+        hybrid_vmx_vmexit_handler(regs);
+        return;
+    }
+
     exit_reason = __vmread(VM_EXIT_REASON);
 
     if ( hvm_long_mode_enabled(v) )
@@ -2632,13 +2633,13 @@ asmlinkage void vmx_vmexit_handler(struc
     case EXIT_REASON_MONITOR_TRAP_FLAG:
         v->arch.hvm_vmx.exec_control &= ~CPU_BASED_MONITOR_TRAP_FLAG;
         __vmwrite(CPU_BASED_VM_EXEC_CONTROL, v->arch.hvm_vmx.exec_control);
-        v->arch.hvm_vcpu.single_step = 0;
 #if defined(XEN_KDB_CONFIG)
         if (kdb_handle_trap_entry(TRAP_debug, regs))
             break;
 #endif
         if ( v->domain->debugger_attached && v->arch.hvm_vcpu.single_step )
             domain_pause_for_debugger();
+        v->arch.hvm_vcpu.single_step = 0;
         break;
 
     case EXIT_REASON_PAUSE_INSTRUCTION:
diff -r f2cf898c7ff8 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/hvm/vpt.c	Thu Nov 17 15:37:30 2011 -0800
@@ -289,6 +289,7 @@ void pt_intr_post(struct vcpu *v, struct
     if ( intack.source == hvm_intsrc_vector )
         return;
 
+    KASSERT(!is_hybrid_vcpu(current));
     spin_lock(&v->arch.hvm_vcpu.tm_lock);
 
     pt = is_pt_irq(v, intack);
diff -r f2cf898c7ff8 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm.c	Thu Nov 17 15:37:30 2011 -0800
@@ -490,9 +490,12 @@ void make_cr3(struct vcpu *v, unsigned l
 
 #endif /* !defined(__i386__) */
 
+/* calling hybrid_update_cr3 doesnt work because during context switch
+ * vmcs is not completely setup? */
 void write_ptbase(struct vcpu *v)
 {
-    write_cr3(v->arch.cr3);
+    if (!is_hybrid_vcpu(v))
+        write_cr3(v->arch.cr3);
 }
 
 /*
@@ -2482,6 +2485,7 @@ int get_page_type_preemptible(struct pag
 }
 
 
+extern void hybrid_update_cr3(struct vcpu *v);
 int new_guest_cr3(unsigned long mfn)
 {
     struct vcpu *curr = current;
@@ -2530,6 +2534,9 @@ int new_guest_cr3(unsigned long mfn)
 
     write_ptbase(curr);
 
+    if (is_hybrid_vcpu(curr))
+        hybrid_update_cr3(curr);
+
     if ( likely(old_base_mfn != 0) )
     {
         if ( paging_mode_refcounts(d) )
@@ -2863,10 +2870,23 @@ int do_mmuext_op(
 #endif
         
         case MMUEXT_TLB_FLUSH_LOCAL:
+            /* do this for both, flush_tlb_user and flush_tlb_kernel, for now.
+             * To debug: hvm_asid_flush_vcpu for flush_tlb_user, and
+             * vpid_sync_all for flush_tlb_kernel */
+            if (is_hybrid_domain(d)) {
+                extern void hybrid_flush_tlb(void);
+                hybrid_flush_tlb();
+                break;
+            }
             flush_tlb_local();
             break;
     
         case MMUEXT_INVLPG_LOCAL:
+            if (is_hybrid_domain(d)) {
+                extern void hybrid_do_invlpg(ulong);
+                hybrid_do_invlpg(op.arg1.linear_addr);
+                break;
+            }
             if ( !paging_mode_enabled(d) 
                  || paging_invlpg(curr, op.arg1.linear_addr) != 0 )
                 flush_tlb_one_local(op.arg1.linear_addr);
@@ -2877,6 +2897,10 @@ int do_mmuext_op(
         {
             cpumask_t pmask;
 
+            if (is_hybrid_domain(d)) {
+                printk("MUK:FIX: MMUEXT_TLB_FLUSH_MULTI/MMUEXT_INVLPG_MULTI\n");
+                break;
+            }
             if ( unlikely(vcpumask_to_pcpumask(d, op.arg2.vcpumask, &pmask)) )
             {
                 okay = 0;
@@ -4181,7 +4205,7 @@ long do_update_descriptor(u64 pa, u64 de
     mfn = gmfn_to_mfn(dom, gmfn);
     if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
          !mfn_valid(mfn) ||
-         !check_descriptor(dom, &d) )
+         (!is_hybrid_domain(dom) && !check_descriptor(dom, &d)) )
         return -EINVAL;
 
     page = mfn_to_page(mfn);
diff -r f2cf898c7ff8 xen/arch/x86/mm/hap/hap.c
--- a/xen/arch/x86/mm/hap/hap.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm/hap/hap.c	Thu Nov 17 15:37:30 2011 -0800
@@ -705,8 +705,10 @@ void hap_vcpu_init(struct vcpu *v)
 static int hap_page_fault(struct vcpu *v, unsigned long va,
                           struct cpu_user_regs *regs)
 {
-    HAP_ERROR("Intercepted a guest #PF (%u:%u) with HAP enabled.\n",
-              v->domain->domain_id, v->vcpu_id);
+    HAP_ERROR("Intercepted a guest #PF (%u:%u:VA %016lx IP:%016lx) with "
+              "HAP enabled.\n", v->domain->domain_id, v->vcpu_id,va, regs->rip);
+
+    kdb_trap_immed(KDB_TRAP_NONFATAL);
     domain_crash(v->domain);
     return 0;
 }
diff -r f2cf898c7ff8 xen/arch/x86/mm/mem_event.c
--- a/xen/arch/x86/mm/mem_event.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm/mem_event.c	Thu Nov 17 15:37:30 2011 -0800
@@ -216,7 +216,7 @@ int mem_event_domctl(struct domain *d, x
 
             /* Currently only EPT is supported */
             rc = -ENODEV;
-            if ( !(is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled &&
+            if ( !(is_hvm_or_hyb_domain(d) && d->arch.hvm_domain.hap_enabled &&
                   (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)) )
                 break;
 
diff -r f2cf898c7ff8 xen/arch/x86/mm/mem_sharing.c
--- a/xen/arch/x86/mm/mem_sharing.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm/mem_sharing.c	Thu Nov 17 15:37:30 2011 -0800
@@ -42,9 +42,6 @@ static void mem_sharing_audit(void);
 # define mem_sharing_audit() do {} while(0)
 #endif /* MEM_SHARING_AUDIT */
 
-
-#define hap_enabled(d) \
-    (is_hvm_domain(d) && (d)->arch.hvm_domain.hap_enabled)
 #define mem_sharing_enabled(d) \
     (is_hvm_domain(d) && (d)->arch.hvm_domain.mem_sharing_enabled)
  
diff -r f2cf898c7ff8 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm/p2m.c	Thu Nov 17 15:37:30 2011 -0800
@@ -1569,7 +1569,7 @@ int p2m_init(struct domain *d)
     p2m->get_entry_current = p2m_gfn_to_mfn_current;
     p2m->change_entry_type_global = p2m_change_type_global;
 
-    if ( is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled &&
+    if ( is_hvm_or_hyb_domain(d) && d->arch.hvm_domain.hap_enabled &&
          (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) )
         ept_p2m_init(d);
 
@@ -1596,7 +1596,7 @@ int set_p2m_entry(struct domain *d, unsi
 
     while ( todo )
     {
-        if ( is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled )
+        if ( is_hvm_or_hyb_domain(d) && d->arch.hvm_domain.hap_enabled )
             order = ((((gfn | mfn_x(mfn) | todo) & (SUPERPAGE_PAGES - 1)) == 0)
                     && hvm_hap_has_2mb(d)) ? 9 : 0;
         else
diff -r f2cf898c7ff8 xen/arch/x86/mm/paging.c
--- a/xen/arch/x86/mm/paging.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/mm/paging.c	Thu Nov 17 15:37:30 2011 -0800
@@ -29,8 +29,6 @@
 #include <xen/numa.h>
 #include <xsm/xsm.h>
 
-#define hap_enabled(d) (is_hvm_domain(d) && (d)->arch.hvm_domain.hap_enabled)
-
 /* Printouts */
 #define PAGING_PRINTK(_f, _a...)                                     \
     debugtrace_printk("pg: %s(): " _f, __func__, ##_a)
diff -r f2cf898c7ff8 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/time.c	Thu Nov 17 15:37:30 2011 -0800
@@ -879,7 +879,7 @@ static void __update_vcpu_system_time(st
         _u.tsc_to_system_mul = t->tsc_scale.mul_frac;
         _u.tsc_shift         = (s8)t->tsc_scale.shift;
     }
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         _u.tsc_timestamp += v->arch.hvm_vcpu.cache_tsc_offset;
 
     /* Don't bother unless timestamp record has changed or we are forced. */
@@ -947,7 +947,7 @@ static void update_domain_rtc(void)
     rcu_read_lock(&domlist_read_lock);
 
     for_each_domain ( d )
-        if ( is_hvm_domain(d) )
+        if ( is_hvm_or_hyb_domain(d) )
             rtc_update_clock(d);
 
     rcu_read_unlock(&domlist_read_lock);
@@ -956,7 +956,7 @@ static void update_domain_rtc(void)
 void domain_set_time_offset(struct domain *d, int32_t time_offset_seconds)
 {
     d->time_offset_seconds = time_offset_seconds;
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         rtc_update_clock(d);
 }
 
@@ -1856,7 +1856,6 @@ void tsc_set_info(struct domain *d,
         d->arch.vtsc = 0;
         return;
     }
-
     switch ( d->arch.tsc_mode = tsc_mode )
     {
     case TSC_MODE_NEVER_EMULATE:
@@ -1901,7 +1900,7 @@ void tsc_set_info(struct domain *d,
         break;
     }
     d->arch.incarnation = incarnation + 1;
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         hvm_set_rdtsc_exiting(d, d->arch.vtsc);
 }
 
diff -r f2cf898c7ff8 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/traps.c	Thu Nov 17 15:37:30 2011 -0800
@@ -1217,7 +1217,7 @@ static int spurious_page_fault(
     return is_spurious;
 }
 
-static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
+int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
 {
     struct vcpu   *v = current;
     struct domain *d = v->domain;
@@ -3228,7 +3228,6 @@ void load_TR(void)
         .base = (long)(this_cpu(gdt_table) - FIRST_RESERVED_GDT_ENTRY),
         .limit = LAST_RESERVED_GDT_BYTE
     };
-
     _set_tssldt_desc(
         this_cpu(gdt_table) + TSS_ENTRY - FIRST_RESERVED_GDT_ENTRY,
         (unsigned long)tss,
diff -r f2cf898c7ff8 xen/arch/x86/x86_64/traps.c
--- a/xen/arch/x86/x86_64/traps.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/arch/x86/x86_64/traps.c	Thu Nov 17 15:37:30 2011 -0800
@@ -617,7 +617,7 @@ static void hypercall_page_initialise_ri
 void hypercall_page_initialise(struct domain *d, void *hypercall_page)
 {
     memset(hypercall_page, 0xCC, PAGE_SIZE);
-    if ( is_hvm_domain(d) )
+    if ( is_hvm_or_hyb_domain(d) )
         hvm_hypercall_page_initialise(d, hypercall_page);
     else if ( !is_pv_32bit_domain(d) )
         hypercall_page_initialise_ring3_kernel(hypercall_page);
diff -r f2cf898c7ff8 xen/common/domain.c
--- a/xen/common/domain.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/common/domain.c	Thu Nov 17 15:37:30 2011 -0800
@@ -238,8 +238,13 @@ struct domain *domain_create(
     spin_lock_init(&d->shutdown_lock);
     d->shutdown_code = -1;
 
-    if ( domcr_flags & DOMCRF_hvm )
+    if ( domcr_flags & DOMCRF_hybrid ) {
+        d->is_hybrid = 1;
+        printk("Hybrid guest with%s ept. Domid:%d\n", 
+               (domcr_flags&DOMCRF_hap) ? "" : " no", domid);
+    } else if ( domcr_flags & DOMCRF_hvm ) {
         d->is_hvm = 1;
+    }
 
     if ( domid == 0 )
     {
@@ -588,7 +593,8 @@ void domain_pause_for_debugger(void)
     for_each_vcpu ( d, v )
         vcpu_sleep_nosync(v);
 
-    send_guest_global_virq(dom0, VIRQ_DEBUGGER);
+    if (current->arch.gdbsx_vcpu_event == 0)
+        send_guest_global_virq(dom0, VIRQ_DEBUGGER);
 }
 
 /* Complete domain destroy after RCU readers are not holding old references. */
diff -r f2cf898c7ff8 xen/common/domctl.c
--- a/xen/common/domctl.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/common/domctl.c	Thu Nov 17 15:37:30 2011 -0800
@@ -132,6 +132,8 @@ void getdomaininfo(struct domain *d, str
 
     if ( is_hvm_domain(d) )
         info->flags |= XEN_DOMINF_hvm_guest;
+    else if ( is_hybrid_domain(d) )
+        info->flags |= XEN_DOMINF_hybrid_guest;
 
     xsm_security_domaininfo(d, info);
 
@@ -394,7 +396,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
         if ( supervisor_mode_kernel ||
              (op->u.createdomain.flags &
              ~(XEN_DOMCTL_CDF_hvm_guest | XEN_DOMCTL_CDF_hap |
-               XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off)) )
+               XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
+               XEN_DOMCTL_CDF_hybrid_guest)) )
             break;
 
         dom = op->domain;
@@ -430,6 +433,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
             domcr_flags |= DOMCRF_s3_integrity;
         if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_oos_off )
             domcr_flags |= DOMCRF_oos_off;
+        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_hybrid_guest )
+            domcr_flags |= DOMCRF_hybrid;
 
         ret = -ENOMEM;
         d = domain_create(dom, domcr_flags, op->u.createdomain.ssidref);
diff -r f2cf898c7ff8 xen/common/kernel.c
--- a/xen/common/kernel.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/common/kernel.c	Thu Nov 17 15:37:30 2011 -0800
@@ -239,13 +239,16 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDL
             if ( supervisor_mode_kernel )
                 fi.submap |= 1U << XENFEAT_supervisor_mode_kernel;
 #ifdef CONFIG_X86
-            if ( !is_hvm_vcpu(current) )
+            if ( !is_hvm_vcpu(current) && 
+                 !paging_mode_translate(current->domain) )  /* hybrid */
                 fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
                              (1U << XENFEAT_highmem_assist) |
                              (1U << XENFEAT_gnttab_map_avail_bits);
             else
                 fi.submap |= (1U << XENFEAT_hvm_safe_pvclock) |
                              (1U << XENFEAT_hvm_callback_vector);
+            if ( is_hybrid_vcpu(current) )
+                fi.submap |= (1U << XENFEAT_hvm_callback_vector);
 #endif
             break;
         default:
diff -r f2cf898c7ff8 xen/common/memory.c
--- a/xen/common/memory.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/common/memory.c	Thu Nov 17 15:37:30 2011 -0800
@@ -89,7 +89,7 @@ static void increase_reservation(struct 
     a->nr_done = i;
 }
 
-static void populate_physmap(struct memop_args *a)
+static noinline void populate_physmap(struct memop_args *a)
 {
     struct page_info *page;
     unsigned long i, j;
@@ -134,6 +134,7 @@ static void populate_physmap(struct memo
             }
 
             mfn = page_to_mfn(page);
+
             guest_physmap_add_page(d, gpfn, mfn, a->extent_order);
 
             if ( !paging_mode_translate(d) )
diff -r f2cf898c7ff8 xen/common/timer.c
--- a/xen/common/timer.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/common/timer.c	Thu Nov 17 15:37:30 2011 -0800
@@ -546,13 +546,20 @@ void kdb_dump_timer_queues(void)
     struct timers *ts;
     unsigned long sz, offs;
     char buf[KSYM_NAME_LEN+1];
-    int            cpu, j;
-    s_time_t       now = NOW();
+    int cpu, j;
+    u64 tsc;
 
     for_each_online_cpu( cpu )
     {
         ts = &per_cpu(timers, cpu);
-        kdbp("CPU[%02d]: NOW:0x%08x%08x\n", cpu, (u32)(now>>32), (u32)now);
+        kdbp("CPU[%02d]:", cpu);
+
+        if (cpu == smp_processor_id()) {
+            s_time_t now = NOW();
+            rdtscll(tsc);
+            kdbp("NOW:0x%08x%08x TSC:0x%016lx\n", (u32)(now>>32),(u32)now, tsc);
+        } else
+            kdbp("\n");
 
         /* timers in the heap */
         for ( j = 1; j <= GET_HEAP_SIZE(ts->heap); j++ ) {
diff -r f2cf898c7ff8 xen/include/asm-x86/desc.h
--- a/xen/include/asm-x86/desc.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/desc.h	Thu Nov 17 15:37:30 2011 -0800
@@ -58,7 +58,8 @@
 #ifndef __ASSEMBLY__
 
 #if defined(__x86_64__)
-#define GUEST_KERNEL_RPL(d) (is_pv_32bit_domain(d) ? 1 : 3)
+#define GUEST_KERNEL_RPL(d) (is_hybrid_domain(d) ? 0 : \
+                      is_pv_32bit_domain(d) ? 1 : 3)
 #elif defined(__i386__)
 #define GUEST_KERNEL_RPL(d) ((void)(d), 1)
 #endif
@@ -67,6 +68,9 @@
 #define __fixup_guest_selector(d, sel)                             \
 ({                                                                 \
     uint16_t _rpl = GUEST_KERNEL_RPL(d);                           \
+    if (d->is_hybrid) {                                      \
+        printk("MUK: hybrid domain fixing up selector\n");          \
+    }                                                              \
     (sel) = (((sel) & 3) >= _rpl) ? (sel) : (((sel) & ~3) | _rpl); \
 })
 
diff -r f2cf898c7ff8 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/domain.h	Thu Nov 17 15:37:30 2011 -0800
@@ -18,7 +18,7 @@
 #endif
 #define is_pv_32on64_vcpu(v)   (is_pv_32on64_domain((v)->domain))
 
-#define is_hvm_pv_evtchn_domain(d) (is_hvm_domain(d) && \
+#define is_hvm_pv_evtchn_domain(d) (is_hvm_or_hyb_domain(d) && \
         d->arch.hvm_domain.irq.callback_via_type == HVMIRQ_callback_vector)
 #define is_hvm_pv_evtchn_vcpu(v) (is_hvm_pv_evtchn_domain(v->domain))
 
diff -r f2cf898c7ff8 xen/include/asm-x86/event.h
--- a/xen/include/asm-x86/event.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/event.h	Thu Nov 17 15:37:30 2011 -0800
@@ -18,7 +18,7 @@ int hvm_local_events_need_delivery(struc
 static inline int local_events_need_delivery(void)
 {
     struct vcpu *v = current;
-    return (is_hvm_vcpu(v) ? hvm_local_events_need_delivery(v) :
+    return ( is_hvm_or_hyb_vcpu(v) ? hvm_local_events_need_delivery(v) :
             (vcpu_info(v, evtchn_upcall_pending) &&
              !vcpu_info(v, evtchn_upcall_mask)));
 }
diff -r f2cf898c7ff8 xen/include/asm-x86/guest_access.h
--- a/xen/include/asm-x86/guest_access.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/guest_access.h	Thu Nov 17 15:37:30 2011 -0800
@@ -14,19 +14,19 @@
 
 /* Raw access functions: no type checking. */
 #define raw_copy_to_guest(dst, src, len)        \
-    (is_hvm_vcpu(current) ?                     \
+    ((is_hvm_vcpu(current) || is_hyb_hap_vcpu(current)) ?  \
      copy_to_user_hvm((dst), (src), (len)) :    \
      copy_to_user((dst), (src), (len)))
 #define raw_copy_from_guest(dst, src, len)      \
-    (is_hvm_vcpu(current) ?                     \
+    ((is_hvm_vcpu(current) || is_hyb_hap_vcpu(current)) ?  \
      copy_from_user_hvm((dst), (src), (len)) :  \
      copy_from_user((dst), (src), (len)))
 #define __raw_copy_to_guest(dst, src, len)      \
-    (is_hvm_vcpu(current) ?                     \
+    ((is_hvm_vcpu(current) || is_hyb_hap_vcpu(current)) ?  \
      copy_to_user_hvm((dst), (src), (len)) :    \
      __copy_to_user((dst), (src), (len)))
 #define __raw_copy_from_guest(dst, src, len)    \
-    (is_hvm_vcpu(current) ?                     \
+    ((is_hvm_vcpu(current) || is_hyb_hap_vcpu(current)) ?  \
      copy_from_user_hvm((dst), (src), (len)) :  \
      __copy_from_user((dst), (src), (len)))
 
diff -r f2cf898c7ff8 xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/hvm/domain.h	Thu Nov 17 15:37:30 2011 -0800
@@ -98,5 +98,8 @@ struct hvm_domain {
     };
 };
 
+#define hap_enabled(d)    \
+    (is_hvm_or_hyb_domain(d) && (d)->arch.hvm_domain.hap_enabled)
+
 #endif /* __ASM_X86_HVM_DOMAIN_H__ */
 
diff -r f2cf898c7ff8 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h	Thu Nov 17 15:37:30 2011 -0800
@@ -144,10 +144,12 @@ struct hvm_function_table {
 extern struct hvm_function_table hvm_funcs;
 extern int hvm_enabled;
 
+int hybrid_domain_initialise(struct domain *d);
 int hvm_domain_initialise(struct domain *d);
 void hvm_domain_relinquish_resources(struct domain *d);
 void hvm_domain_destroy(struct domain *d);
 
+int hybrid_vcpu_initialise(struct vcpu *v);
 int hvm_vcpu_initialise(struct vcpu *v);
 void hvm_vcpu_destroy(struct vcpu *v);
 void hvm_vcpu_down(struct vcpu *v);
diff -r f2cf898c7ff8 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Thu Nov 17 15:37:30 2011 -0800
@@ -110,6 +110,7 @@ void vmx_update_debug_state(struct vcpu 
 #define EXIT_REASON_EPT_VIOLATION       48
 #define EXIT_REASON_EPT_MISCONFIG       49
 #define EXIT_REASON_RDTSCP              51
+#define EXIT_REASON_INVVPID             53
 #define EXIT_REASON_WBINVD              54
 #define EXIT_REASON_XSETBV              55
 
@@ -284,6 +285,14 @@ static inline unsigned long __vmread_saf
     return ecx;
 }
 
+static inline unsigned long vmr(unsigned long field)
+{
+    int rc;
+    unsigned long val;
+    val = __vmread_safe(field, &rc);
+    return rc ? 0 : val;
+}
+
 static inline void __vm_set_bit(unsigned long field, unsigned int bit)
 {
     __vmwrite(field, __vmread(field) | (1UL << bit));
@@ -410,6 +419,8 @@ void vmx_inject_nmi(void);
 void ept_p2m_init(struct domain *d);
 void ept_walk_table(struct domain *d, unsigned long gfn);
 
+void hybrid_vmx_vmexit_handler(struct cpu_user_regs *regs);
+
 /* EPT violation qualifications definitions */
 #define _EPT_READ_VIOLATION         0
 #define EPT_READ_VIOLATION          (1UL<<_EPT_READ_VIOLATION)
@@ -430,4 +441,39 @@ void ept_walk_table(struct domain *d, un
 
 #define EPT_PAGETABLE_ENTRIES       512
 
+/*  
+ * Not all cases receive valid value in the VM-exit instruction length field.
+ * Callers must know what they're doing!
+ */ 
+static inline int __get_instruction_length(void)
+{   
+    int len;
+    len = __vmread(VM_EXIT_INSTRUCTION_LEN); /* Safe: callers audited */
+    BUG_ON((len < 1) || (len > 15));
+    return len;
+}
+
+static inline void __update_guest_eip(unsigned long inst_len)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    unsigned long x;
+    
+    regs->eip += inst_len;
+    regs->eflags &= ~X86_EFLAGS_RF;
+    
+    x = __vmread(GUEST_INTERRUPTIBILITY_INFO);
+    if ( x & (VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS) )
+    {
+        x &= ~(VMX_INTR_SHADOW_STI | VMX_INTR_SHADOW_MOV_SS);
+        __vmwrite(GUEST_INTERRUPTIBILITY_INFO, x);
+    }
+    
+    if ( regs->eflags & X86_EFLAGS_TF )
+        vmx_inject_hw_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE);
+}   
+
+extern void vmx_dr_access(unsigned long, struct cpu_user_regs *);
+extern void vmx_fpu_enter(struct vcpu *v);
+extern void vmx_fpu_dirty_intercept(void);
+
 #endif /* __ASM_X86_HVM_VMX_VMX_H__ */
diff -r f2cf898c7ff8 xen/include/public/domctl.h
--- a/xen/include/public/domctl.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/public/domctl.h	Thu Nov 17 15:37:30 2011 -0800
@@ -64,6 +64,9 @@ struct xen_domctl_createdomain {
  /* Disable out-of-sync shadow page tables? */
 #define _XEN_DOMCTL_CDF_oos_off       3
 #define XEN_DOMCTL_CDF_oos_off        (1U<<_XEN_DOMCTL_CDF_oos_off)
+ /* Is this a hybrid guest? */
+#define _XEN_DOMCTL_CDF_hybrid_guest  4
+#define XEN_DOMCTL_CDF_hybrid_guest   (1U<<_XEN_DOMCTL_CDF_hybrid_guest)
 };
 typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_createdomain_t);
@@ -93,6 +96,9 @@ struct xen_domctl_getdomaininfo {
  /* Being debugged.  */
 #define _XEN_DOMINF_debugged  6
 #define XEN_DOMINF_debugged   (1U<<_XEN_DOMINF_debugged)
+ /* domain is hybrid */
+#define _XEN_DOMINF_hybrid_guest 7
+#define XEN_DOMINF_hybrid_guest   (1U<<_XEN_DOMINF_hybrid_guest)
  /* XEN_DOMINF_shutdown guest-supplied code.  */
 #define XEN_DOMINF_shutdownmask 255
 #define XEN_DOMINF_shutdownshift 16
diff -r f2cf898c7ff8 xen/include/public/xen.h
--- a/xen/include/public/xen.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/public/xen.h	Thu Nov 17 15:37:30 2011 -0800
@@ -594,6 +594,7 @@ typedef struct start_info start_info_t;
 #define SIF_PRIVILEGED    (1<<0)  /* Is the domain privileged? */
 #define SIF_INITDOMAIN    (1<<1)  /* Is this the initial control domain? */
 #define SIF_MULTIBOOT_MOD (1<<2)  /* Is mod_start a multiboot module? */
+#define SIF_IS_HYBRID     (1<<3)  /* Is it a PV running in HVM container? */
 #define SIF_PM_MASK       (0xFF<<8) /* reserve 1 byte for xen-pm options */
 
 /*
diff -r f2cf898c7ff8 xen/include/xen/lib.h
--- a/xen/include/xen/lib.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/xen/lib.h	Thu Nov 17 15:37:30 2011 -0800
@@ -39,6 +39,17 @@ do {                                    
 #else
 #define ASSERT(p) ((void)0)
 #endif
+#ifdef XEN_KDB_CONFIG
+    #define KASSERT(p)                                                \
+      do { if (!(p)) {                                                \
+               kdbp("KASSERT in %s at %d\n", __FUNCTION__, __LINE__); \
+               kdb_trap_immed(KDB_TRAP_NONFATAL);                     \
+           }                                                          \
+      } while (0)
+#else
+#define KASSERT(p) \
+    do { if ( unlikely(!(p)) ) assert_failed(#p); } while (0)
+#endif
 
 #define ABS(_x) ({                              \
     typeof(_x) __x = (_x);                      \
@@ -126,6 +137,8 @@ extern void add_taint(unsigned);
 extern void kdb_trap_immed(int);
 extern void kdbtrc(unsigned int, unsigned int, uint64_t, uint64_t, uint64_t);
 extern void kdbp(const char *fmt, ...);
+extern volatile int mukkdbdbg;
+#define mukkdbp(...) {(mukkdbdbg) ? kdbp(__VA_ARGS__):0;}
 #endif
 
 #endif /* __LIB_H__ */
diff -r f2cf898c7ff8 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/xen/sched.h	Thu Nov 17 15:37:30 2011 -0800
@@ -228,6 +228,7 @@ struct domain
 
     /* Is this an HVM guest? */
     bool_t           is_hvm;
+    bool_t           is_hybrid;
     /* Does this guest need iommu mappings? */
     bool_t           need_iommu;
     /* Is this guest fully privileged (aka dom0)? */
@@ -388,6 +389,9 @@ struct domain *domain_create(
  /* DOMCRF_oos_off: dont use out-of-sync optimization for shadow page tables */
 #define _DOMCRF_oos_off         4
 #define DOMCRF_oos_off          (1U<<_DOMCRF_oos_off)
+ /* DOMCRF_hybrid: Create PV domain in HVM container */
+#define _DOMCRF_hybrid          5
+#define DOMCRF_hybrid           (1U<<_DOMCRF_hybrid)
 
 /*
  * rcu_lock_domain_by_id() is more efficient than get_domain_by_id().
@@ -590,10 +594,17 @@ uint64_t get_cpu_idle_time(unsigned int 
 
 #define is_hvm_domain(d) ((d)->is_hvm)
 #define is_hvm_vcpu(v)   (is_hvm_domain(v->domain))
+#define is_hybrid_domain(d) ((d)->is_hybrid)
+#define is_hybrid_vcpu(v)   (is_hybrid_domain(v->domain))
+#define is_hvm_or_hyb_domain(d) (is_hvm_domain(d) || is_hybrid_domain(d))
+#define is_hvm_or_hyb_vcpu(v) (is_hvm_or_hyb_domain(v->domain))
 #define is_pinned_vcpu(v) ((v)->domain->is_pinned || \
                            cpus_weight((v)->cpu_affinity) == 1)
 #define need_iommu(d)    ((d)->need_iommu)
 
+#define is_hyb_hap_domain(d) (is_hybrid_domain(d) && hap_enabled(d))
+#define is_hyb_hap_vcpu(v) (is_hyb_hap_domain(v->domain))
+
 void set_vcpu_migration_delay(unsigned int delay);
 unsigned int get_vcpu_migration_delay(void);
 
diff -r f2cf898c7ff8 xen/include/xen/xencomm.h
--- a/xen/include/xen/xencomm.h	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/include/xen/xencomm.h	Thu Nov 17 15:37:30 2011 -0800
@@ -79,7 +79,7 @@ static inline unsigned long xencomm_inli
  * Copy an array of objects from guest context via a guest handle.
  * Optionally specify an offset into the guest array.
  */
-#define copy_from_guest_offset(ptr, hnd, idx, nr) \
+#define copy_from_guest_offset(ptr, hnd, idx, nr) \ JUNK
     __copy_from_guest_offset(ptr, hnd, idx, nr)
 
 /* Copy sub-field of a structure from guest context via a guest handle. */
diff -r f2cf898c7ff8 xen/kdb/kdb_cmds.c
--- a/xen/kdb/kdb_cmds.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/kdb/kdb_cmds.c	Thu Nov 17 15:37:30 2011 -0800
@@ -173,7 +173,7 @@ kdb_do_cmds(struct cpu_user_regs *regs)
 
 /* ===================== Util functions  ==================================== */
 
-static int
+int
 kdb_vcpu_valid(struct vcpu *in_vp)
 {
     struct domain *dp;
@@ -298,15 +298,13 @@ kdb_str2domid(const char *domstr, domid_
 }
 
 static struct domain *
-kdb_strdomid2ptr(const char *domstr)
+kdb_strdomid2ptr(const char *domstr, int perror)
 {
-    ulong l;
-    struct domain *dp;
-    if (!kdb_str2ulong(domstr, &l) || !(dp=kdb_domid2ptr((domid_t)l))) {
-        kdbp("Invalid domid:%s\n", domstr);
-        return NULL;
-    } else
-        return dp;
+    domid_t domid;
+    if (kdb_str2domid(domstr, &domid, perror)) {
+        return(kdb_domid2ptr(domid));
+    }
+    return NULL;
 }
 
 /* return a guest bitness: 32 or 64 */
@@ -319,7 +317,7 @@ kdb_guest_bitness(domid_t domid)
 
     if (is_idle_domain(dp))
         retval = HYPSZ;
-    else if (is_hvm_domain(dp))
+    else if (is_hvm_or_hyb_domain(dp))
         retval = (hvm_long_mode_enabled(dp->vcpu[0])) ? HYPSZ : 32;
     else 
         retval = is_pv_32bit_domain(dp) ? 32 : HYPSZ;
@@ -825,7 +823,7 @@ struct  Xgt_desc_struct {
     unsigned long address __attribute__((packed));
 };
 
-static void
+void
 kdb_show_special_regs(struct cpu_user_regs *regs)
 {
     struct Xgt_desc_struct desc;
@@ -958,7 +956,8 @@ kdb_cmdf_ss(int argc, const char **argv,
     #define KDB_HALT_INSTR 0xf4
 
     kdbbyt_t byte;
-    domid_t id = guest_mode(regs) ? current->domain->domain_id : DOMID_IDLE;
+    struct domain *dp = current->domain;
+    domid_t id = guest_mode(regs) ? dp->domain_id : DOMID_IDLE;
 
     if (argc > 1 && *argv[1] == '?')
         return kdb_usgf_ss();
@@ -977,16 +976,12 @@ kdb_cmdf_ss(int argc, const char **argv,
         kdbp("kdb: Failed to read byte at: %lx\n", regs->KDBIP);
         return KDB_CPU_MAIN_KDB;
     }
-    if (guest_mode(regs) && is_hvm_vcpu(current))
+    if (guest_mode(regs) && is_hvm_or_hyb_vcpu(current)) {
+        dp->debugger_attached = 1;  /* see svm_do_resume/vmx_do_ */
         current->arch.hvm_vcpu.single_step = 1;
-    else
+    } else
         regs->eflags |= X86_EFLAGS_TF;
-#if 0
-    if (guest_mode(regs) && is_hvm_vcpu(current)) {
-        struct domain *dp = current->domain;
-        dp->debugger_attached = 1;  /* see svm_do_resume/vmx_do_ */
-    }
-#endif
+
     return KDB_CPU_SS;
 }
 
@@ -1052,7 +1047,7 @@ kdb_cmdf_ssb(int argc, const char **argv
         kdbp("%s: regs not available\n", __FUNCTION__);
         return KDB_CPU_MAIN_KDB;
     }
-    if (is_hvm_vcpu(current)) 
+    if (is_hvm_or_hyb_vcpu(current)) 
         current->domain->debugger_attached = 1;        /* vmx/svm_do_resume()*/
 
     regs->eflags |= X86_EFLAGS_TF;
@@ -1640,7 +1635,7 @@ kdb_set_bp(domid_t domid, kdbva_t addr, 
         return KDBMAXSBP;
     }
     /* make sure swbp reporting is enabled in the vmcb/vmcs */
-    if (is_hvm_domain(kdb_domid2ptr(domid))) {
+    if (is_hvm_or_hyb_domain(kdb_domid2ptr(domid))) {
         struct domain *dp = kdb_domid2ptr(domid);
         dp->debugger_attached = 1;              /* see svm_do_resume/vmx_do_ */
         KDBGP("debugger_attached set. domid:%d\n", domid);
@@ -1693,7 +1688,7 @@ kdb_cmdf_bp(int argc, const char **argv,
     if (domidstrp && !kdb_str2domid(domidstrp, &domid, 1)) {
         return kdb_usgf_bp();
     }
-    if (argc > 3 && is_hvm_domain(kdb_domid2ptr(domid))) {
+    if (argc > 3 && is_hvm_or_hyb_domain(kdb_domid2ptr(domid))) {
         kdbp("HVM domain not supported yet for conditional bp\n");
         return KDB_CPU_MAIN_KDB;
     }
@@ -1741,7 +1736,7 @@ kdb_cmdf_btp(int argc, const char **argv
     argsidx = 2;                   /* assume 3rd arg is not domid */
     if (argc > 3 && kdb_str2domid(argv[2], &domid, 0)) {
 
-        if (is_hvm_domain(kdb_domid2ptr(domid))) {
+        if (is_hvm_or_hyb_domain(kdb_domid2ptr(domid))) {
             kdbp("HVM domains are not currently supprted\n");
             return KDB_CPU_MAIN_KDB;
         } else
@@ -1893,7 +1888,7 @@ kdb_cmdf_vcpuh(int argc, const char **ar
         return kdb_usgf_vcpuh();
 
     if (!kdb_str2ulong(argv[1], (ulong *)&vp) || !kdb_vcpu_valid(vp) ||
-        !is_hvm_vcpu(vp)) {
+        !is_hvm_or_hyb_vcpu(vp)) {
 
         kdbp("kdb: Bad VCPU: %s\n", argv[1]);
         return KDB_CPU_MAIN_KDB;
@@ -2042,11 +2037,12 @@ kdb_display_vcpu(struct vcpu *vp)
     kdbp("  cpu_affinity:0x%lx vcpu_dirty_cpumask:0x%lx sched_priv:0x%p\n",
          vp->cpu_affinity.bits[0], vp->vcpu_dirty_cpumask.bits[0],
          vp->sched_priv);
-    kdbp("  &runstate: %p state: %x\n", &vp->runstate, vp->runstate.state);
+    kdbp("  &runstate: %p state: %x guestptr:%p\n", &vp->runstate, 
+         vp->runstate.state, runstate_guest(vp));
     kdbp("\n");
     kdbp("  arch info: (%p)\n", &vp->arch);
     kdbp("    guest_context: VGCF_ flags:%lx", gp->flags); /* VGCF_in_kernel */
-    if (is_hvm_vcpu(vp))
+    if (is_hvm_or_hyb_vcpu(vp))
         kdbp("    (HVM guest: IP, SP, EFLAGS may be stale)");
     kdbp("\n");
     kdb_print_uregs(&gp->user_regs);
@@ -2146,7 +2142,7 @@ static void kdb_pr_dom_pg_modes(struct d
         if ( paging_mode_external(d) )
             kdbp(" external(PG_external) ");
     } else
-        kdbp("disabled");
+        kdbp(" disabled");
     kdbp("\n");
 }
 
@@ -2198,6 +2194,19 @@ static void noinline kdb_print_dom_event
 #endif
 }
 
+static void kdb_prnt_hvm_dom_info(struct domain *dp)
+{
+    kdbp("    HVM info: Hap is%s enabled\n", 
+         dp->arch.hvm_domain.hap_enabled ? "" : " not");
+
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+        struct vmx_domain *vdp = &dp->arch.hvm_domain.vmx;
+        kdbp("    EPT: ept_mt:%x ept_wl:%x asr:%013lx\n", 
+             vdp->ept_control.ept_mt, vdp->ept_control.ept_wl, 
+             vdp->ept_control.asr);
+    }
+}
+
 /* display one domain info */
 static void
 kdb_display_dom(struct domain *dp)
@@ -2240,9 +2249,9 @@ kdb_display_dom(struct domain *dp)
         kdbp("    mapcnt:");
         kdb_print_spin_lock("mapcnt: lk:", &gp->lock, "\n");
     }
-    kdbp("  hvm:%d priv:%d dbg:%d dying:%d paused:%d\n",
-         dp->is_hvm, dp->is_privileged, dp->debugger_attached,
-         dp->is_dying, dp->is_paused_by_controller);
+    kdbp("  hvm:%d hybrid:%d priv:%d dbg:%d dying:%d paused:%d\n",
+         dp->is_hvm, dp->is_hybrid, dp->is_privileged, 
+         dp->debugger_attached, dp->is_dying, dp->is_paused_by_controller);
     kdb_print_spin_lock("  shutdown: lk:", &dp->shutdown_lock, "\n");
     kdbp("  shutn:%d shut:%d code:%d \n", dp->is_shutting_down,
          dp->is_shut_down, dp->shutdown_code);
@@ -2266,7 +2275,10 @@ kdb_display_dom(struct domain *dp)
     kdbp("    &mapchache:0x%xp\n", &ap->mapcache);
 #endif
     kdbp("    ioport:0x%p &hvm_dom:0x%p\n", ap->ioport_caps, &ap->hvm_domain);
-    kdbp("    &pging_dom:%p mode:%lx", &ap->paging, ap->paging.mode); 
+    if (is_hvm_or_hyb_domain(dp))
+        kdb_prnt_hvm_dom_info(dp);
+
+    kdbp("    &pging_dom:%p mode: %lx", &ap->paging, ap->paging.mode); 
     kdb_pr_dom_pg_modes(dp);
     kdbp("    p2m ptr:%p  pages:{%p, %p}\n", ap->p2m, ap->p2m->pages.next,
          KDB_PGLLE(ap->p2m->pages));
@@ -2556,7 +2568,7 @@ kdb_cmdf_didt(int argc, const char **arg
 }
 #endif
 
-struct gdte {
+struct gdte {             /* same for TSS and LDT */
     ulong limit0:16;
     ulong base0:24;       /* linear address base, not pa */
     ulong acctype:4;      /* Type: access rights */
@@ -2576,15 +2588,23 @@ union gdte_u {
     u64 gval;
 };
 
-struct sgdte {           /* system gdte */
+struct call_gdte {
     unsigned short offs0:16;
     unsigned short sel:16;
     unsigned short misc0:16;
     unsigned short offs1:16;
 };
 
+struct idt_gdte {
+    unsigned long offs0:16;
+    unsigned long sel:16;
+    unsigned long ist:3;
+    unsigned long unused0:13;
+    unsigned long offs1:16;
+};
 union sgdte_u {
-    struct sgdte sgdte;
+    struct call_gdte cgdte;
+    struct idt_gdte igdte;
     u64 sgval;
 };
 
@@ -2611,7 +2631,7 @@ static char *kdb_ret_acctype(uint acctyp
 static kdb_cpu_cmd_t
 kdb_usgf_dgdt(void)
 {
-    kdbp("dgdt [gdt-ptr hex-gdt-size] dump GDT table on current cpu or for "
+    kdbp("dgdt [gdt-ptr decimal-byte-size] dump GDT table on current cpu or for"
          "given vcpu\n");
     return KDB_CPU_MAIN_KDB;
 }
@@ -2620,9 +2640,9 @@ kdb_cmdf_dgdt(int argc, const char **arg
 {
     struct Xgt_desc_struct desc;
     union gdte_u u1;
-    ulong addr, end;
+    ulong start_addr, end_addr, taddr=0;
     domid_t domid = DOMID_IDLE;
-    int i;
+    int idx;
 
     if (argc > 1 && *argv[1] == '?')
         return kdb_usgf_dgdt();
@@ -2631,62 +2651,62 @@ kdb_cmdf_dgdt(int argc, const char **arg
         if (argc != 3)
             return kdb_usgf_dgdt();
 
-        if (kdb_str2ulong(argv[1], (ulong *)&addr) && 
-            kdb_str2ulong(argv[2], (ulong *)&end)) {
-            end += addr;
+        if (kdb_str2ulong(argv[1], (ulong *)&start_addr) && 
+            kdb_str2deci(argv[2], (int *)&taddr)) {
+            end_addr = start_addr + taddr;
         } else {
             kdbp("dgdt: Bad arg:%s or %s\n", argv[1], argv[2]);
             return kdb_usgf_dgdt();
         }
     } else {
         __asm__ __volatile__ ("sgdt  (%0) \n" :: "a"(&desc) : "memory");
-        addr = (ulong)desc.address; 
-        end = (ulong)desc.address + desc.size;
+        start_addr = (ulong)desc.address; 
+        end_addr = (ulong)desc.address + desc.size;
     }
-    kdbp("GDT: Will skip null desc at 0, addr:%lx end:%lx\n", addr, end);
-    addr += 8;         /* skip null descriptor */
-
+    kdbp("GDT: Will skip null desc at 0, start:%lx end:%lx\n", start_addr, 
+         end_addr);
     kdbp("[idx]   sel --- val --------  Accs DPL P AVL L DB G "
          "--Base Addr ----  Limit\n");
     kdbp("                              Type\n");
 
-    for (i=1;  addr < end;  i++, addr += sizeof(ulong)) {
+    /* skip first 8 null bytes */
+    /* the cpu multiplies the index by 8 and adds to GDT.base */
+    for (taddr = start_addr+8; taddr < end_addr;  taddr += sizeof(ulong)) {
 
         /* not all entries are mapped. do this to avoid GP even if hyp */
-        if (!kdb_read_mem(addr, (kdbbyt_t *)&u1, sizeof(u1),domid) || !u1.gval)
+        if (!kdb_read_mem(taddr, (kdbbyt_t *)&u1, sizeof(u1),domid) || !u1.gval)
             continue;
 
         if (u1.gval == 0xffffffffffffffff || u1.gval == 0x5555555555555555)
             continue;               /* what an effin x86 mess */
 
+        idx = (taddr - start_addr) / 8;
         if (u1.gdte.S == 0) {       /* System Desc are 16 bytes in 64bit mode */
-            addr += sizeof(ulong);
-            i++;
+            taddr += sizeof(ulong);
             continue;
         }
+kdbp("ADDR: %lx\n", taddr);
         kdbp("[%04x] %04x %016lx  %4s  %x  %d  %d  %d  %d %d %016lx  %05x\n",
-             i, (i<<3), u1.gval, kdb_ret_acctype(u1.gdte.acctype), u1.gdte.DPL, 
+             idx, (idx<<3), u1.gval, kdb_ret_acctype(u1.gdte.acctype), 
+             u1.gdte.DPL, 
              u1.gdte.P, u1.gdte.AVL, u1.gdte.L, u1.gdte.DB, u1.gdte.G,  
              (u64)((u64)u1.gdte.base0 | (u64)((u64)u1.gdte.base1<<24)), 
              u1.gdte.limit0 | (u1.gdte.limit1<<16));
     }
 
-    kdbp("\nSystem descriptors (S=0) :\n");
-    addr = (ulong)desc.address + 8;         /* skip null descriptor */
-
-    for (i=1;  addr < end;  i++, addr += sizeof(ulong)) {
-        union sgdte_u u2;
+    kdbp("\nSystem descriptors (S=0) : (skipping 0th entry)\n");
+    for (taddr=start_addr+8;  taddr < end_addr;  taddr += sizeof(ulong)) {
         uint acctype;
-        u64 upper, offs0_64=0, offs32_63=0;
+        u64 upper, addr64=0;
 
         /* not all entries are mapped. do this to avoid GP even if hyp */
-        if (kdb_read_mem(addr, (kdbbyt_t *)&u1, sizeof(u1),domid)==0 || 
+        if (kdb_read_mem(taddr, (kdbbyt_t *)&u1, sizeof(u1), domid)==0 || 
             u1.gval == 0 || u1.gdte.S == 1) {
             continue;
         }
-
-        addr += sizeof(ulong);
-        if (kdb_read_mem(addr, (kdbbyt_t *)&upper, 8, domid) == 0) {
+        idx = (taddr - start_addr) / 8;
+        taddr += sizeof(ulong);
+        if (kdb_read_mem(taddr, (kdbbyt_t *)&upper, 8, domid) == 0) {
             kdbp("Could not read upper 8 bytes of system desc\n");
             upper = 0;
         }
@@ -2695,11 +2715,11 @@ kdb_cmdf_dgdt(int argc, const char **arg
             acctype != 14 && acctype != 15)
             continue;
 
-        kdbp("[%04x] %04x  val:%016lx DPL:%x P:%d acctype:%x ",
-             i, (i<<3), u1.gval, u1.gdte.DPL, u1.gdte.P, acctype); 
-
-        u2.sgval = u1.gval;
-        offs32_63 = (u64)((upper & 0xFFFFFFFF)) << 32;
+kdbp("ADDR: %lx\n", taddr);
+        kdbp("[%04x] %04x val:%016lx DPL:%x P:%d type:%x ",
+             idx, (idx<<3), u1.gval, u1.gdte.DPL, u1.gdte.P, acctype); 
+
+        upper = (u64)((u64)(upper & 0xFFFFFFFF) << 32);
 
         /* Vol 3A: table: 3-2  page: 3-19 */
         if (acctype == 2) {
@@ -2722,17 +2742,28 @@ kdb_cmdf_dgdt(int argc, const char **arg
         }
 
         if (acctype == 2 || acctype == 9 || acctype == 11) {
-            kdbp("        AVL:%d L:%d D/B:%d G:%d Base Addr:%016lx Limit:%x\n",
-                 u1.gdte.AVL, u1.gdte.L, u1.gdte.DB, u1.gdte.G,  
-                 u1.gdte.base0 | (u1.gdte.base1<<24) | offs32_63,
-                 u1.gdte.limit0 | (u1.gdte.limit1<<16));
-
-        } else if (acctype == 12 || acctype == 14 || acctype == 15) {
-            offs0_64 = u2.sgdte.offs0 | (u64)u2.sgdte.offs1<<48 | offs32_63;
-            kdbp("        Entry: %04x:%016lx\n", u2.sgdte.sel, offs0_64);
-        }
-
-        i++;
+            kdbp("        AVL:%d G:%d Base Addr:%016lx Limit:%x\n",
+                 u1.gdte.AVL, u1.gdte.G,  
+                 (u64)((u64)u1.gdte.base0 | ((u64)u1.gdte.base1<<24)| upper),
+                 (u32)u1.gdte.limit0 | (u32)((u32)u1.gdte.limit1<<16));
+
+        } else if (acctype == 12) {
+            union sgdte_u u2;
+            u2.sgval = u1.gval;
+
+            addr64 = (u64)((u64)u2.cgdte.offs0 | 
+                           (u64)((u64)u2.cgdte.offs1<<16) | upper);
+            kdbp("        Entry: %04x:%016lx\n", u2.cgdte.sel, addr64);
+        } else if (acctype == 14 || acctype == 15) {
+            union sgdte_u u2;
+            u2.sgval = u1.gval;
+
+            addr64 = (u64)((u64)u2.igdte.offs0 | 
+                           (u64)((u64)u2.igdte.offs1<<16) | upper);
+            kdbp("        Entry: %04x:%016lx ist:%03x\n", u2.igdte.sel, addr64,
+                 u2.igdte.ist);
+        } else 
+            kdbp(" Error: Unrecongized type:%lx\n", acctype);
     }
     return KDB_CPU_MAIN_KDB;
 }
@@ -2781,6 +2812,7 @@ kdb_cmdf_mmu(int argc, const char **argv
     kdbp("CONFIG_PAGING_LEVELS:%d\n", CONFIG_PAGING_LEVELS);
     kdbp("__HYPERVISOR_COMPAT_VIRT_START: %lx\n", 
          (ulong)__HYPERVISOR_COMPAT_VIRT_START);
+    kdbp("&MPT[0] == %016lx\n", &machine_to_phys_mapping[0]);
 
     kdbp("\nFIRST_RESERVED_GDT_PAGE: %x\n", FIRST_RESERVED_GDT_PAGE);
     kdbp("FIRST_RESERVED_GDT_ENTRY: %lx\n", (ulong)FIRST_RESERVED_GDT_ENTRY);
@@ -2794,11 +2826,17 @@ kdb_cmdf_mmu(int argc, const char **argv
         kdbp("\tcpu:%d  gdt_table:%p\n", cpu, per_cpu(compat_gdt_table, cpu));
     }
     kdbp("\n");
+    kdbp("  Per cpu tss:\n");
+    for_each_online_cpu(cpu) {
+        struct tss_struct *tssp = &per_cpu(init_tss, cpu);
+        kdbp("\tcpu:%d  tss:%p (rsp0:%016lx)\n", cpu, tssp, tssp->rsp0);
+    }
 #ifdef USER_MAPPINGS_ARE_GLOBAL
     kdbp("USER_MAPPINGS_ARE_GLOBAL is defined\n");
 #else
     kdbp("USER_MAPPINGS_ARE_GLOBAL is NOT defined\n");
 #endif
+    kdbp("\n");
     return KDB_CPU_MAIN_KDB;
 }
 
@@ -2873,8 +2911,8 @@ kdb_cmdf_p2m(int argc, const char **argv
     struct domain *dp;
     ulong gpfn;
 
-    if (argc < 3                                ||
-        (dp=kdb_strdomid2ptr(argv[1])) == NULL  ||
+    if (argc < 3                                   ||
+        (dp=kdb_strdomid2ptr(argv[1], 1)) == NULL  ||
         !kdb_str2ulong(argv[2], &gpfn)) {
 
         return kdb_usgf_p2m();
@@ -3408,6 +3446,7 @@ kdb_cmdf_info(int argc, const char **arg
         kdbp(" CONFIG_PAGING_ASSISTANCE");
 #endif
     kdbp("\n");
+    kdbp("MAX_VIRT_CPUS:$%d  MAX_HVM_VCPUS:$%d\n", MAX_VIRT_CPUS,MAX_HVM_VCPUS);
     kdbp("NR_EVENT_CHANNELS: $%d\n", NR_EVENT_CHANNELS);
     kdbp("NR_EVTCHN_BUCKETS: $%d\n", NR_EVTCHN_BUCKETS);
 
diff -r f2cf898c7ff8 xen/kdb/kdb_io.c
--- a/xen/kdb/kdb_io.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/kdb/kdb_io.c	Thu Nov 17 15:37:30 2011 -0800
@@ -39,7 +39,7 @@ kdb_key_valid(int key)
 {
     /* note: isspace() is more than ' ', hence we don't use it here */
     if (isalnum(key) || key == ' ' || key == K_BACKSPACE || key == '\n' ||
-        key == '?' || key == K_UNDERSCORE || key == '=')
+        key == '?' || key == K_UNDERSCORE || key == '=' || key == '!')
             return 1;
     return 0;
 }
diff -r f2cf898c7ff8 xen/kdb/kdbmain.c
--- a/xen/kdb/kdbmain.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/kdb/kdbmain.c	Thu Nov 17 15:37:30 2011 -0800
@@ -258,7 +258,7 @@ kdb_check_dbtrap(kdb_reason_t *reasp, in
                 KDBGP("ccpu:%d trapcpu:%d\n", ccpu, a_trap_cpu);
                 kdb_cpu_cmd[a_trap_cpu] = KDB_CPU_QUIT;
                 *reasp = KDB_REASON_PAUSE_IPI;
-                regs->eflags &= ~X86_EFLAGS_TF;
+                regs->eflags &= ~X86_EFLAGS_TF;  /* hvm: exit handler ss = 0 */
                 kdb_init_cpu = -1;
             } else {
                 kdb_end_session(ccpu, regs);
@@ -364,7 +364,10 @@ kdbmain(kdb_reason_t reason, struct cpu_
             }
         } else if (rc == 2) {        /* one of ours but condition not met */
                 kdb_begin_session();
-                regs->eflags |= X86_EFLAGS_TF;  
+                if (guest_mode(regs) && is_hvm_or_hyb_vcpu(current))
+                    current->arch.hvm_vcpu.single_step = 1;
+                else
+                    regs->eflags |= X86_EFLAGS_TF;  
                 kdb_cpu_cmd[ccpu] = KDB_CPU_INSTALL_BP;
                 goto out;
         }
@@ -401,7 +404,10 @@ kdbmain(kdb_reason_t reason, struct cpu_
             if (!cpus_empty(kdb_cpu_traps)) {
                 /* execute current instruction without 0xcc */
                 kdb_dbg_prnt_ctrps("nempty:", ccpu);
-                regs->eflags |= X86_EFLAGS_TF;  
+                if (guest_mode(regs) && is_hvm_or_hyb_vcpu(current))
+                    current->arch.hvm_vcpu.single_step = 1;
+                else
+                    regs->eflags |= X86_EFLAGS_TF;  
                 kdb_cpu_cmd[ccpu] = KDB_CPU_INSTALL_BP;
                 goto out;
             }
@@ -415,7 +421,10 @@ kdbmain(kdb_reason_t reason, struct cpu_
         if (kdb_swbp_exists()) {
             if (reason == KDB_REASON_BPEXCP) {
                 /* do delayed install */
-                regs->eflags |= X86_EFLAGS_TF;  
+                if (guest_mode(regs) && is_hvm_or_hyb_vcpu(current))
+                    current->arch.hvm_vcpu.single_step = 1;
+                else
+                    regs->eflags |= X86_EFLAGS_TF;  
                 kdb_cpu_cmd[ccpu] = KDB_CPU_INSTALL_BP;
                 goto out;
             } 
@@ -518,9 +527,7 @@ kdb_handle_trap_entry(int vector, struct
          * depending on the hardware. Also, for now assume it's fatal */
         KDBGP("kdbtrp:ccpu:%d vec:%d\n", ccpu, vector);
         rc = kdbmain_fatal(regs, TRAP_nmi);
-    } else {
-        KDBGP("kdbtrp: unhandled trap:ccpu:%d vec:%d\n", ccpu, vector);
-    }
+    } 
     return rc;
 }
 
@@ -659,7 +666,7 @@ kdb_gettrapname(int trapno)
 
 #define KDBTRCMAX 1       /* set this to max number of recs to trace. each rec 
                            * is 32 bytes */
-volatile int kdb_trcon=0; /* turn tracing ON: set here or via the trcon cmd */
+volatile int kdb_trcon=1; /* turn tracing ON: set here or via the trcon cmd */
 
 typedef struct {
     union {
diff -r f2cf898c7ff8 xen/kdb/x86/udis86-1.7/kdb_dis.c
--- a/xen/kdb/x86/udis86-1.7/kdb_dis.c	Fri Jul 15 23:21:24 2011 +0000
+++ b/xen/kdb/x86/udis86-1.7/kdb_dis.c	Thu Nov 17 15:37:30 2011 -0800
@@ -65,11 +65,13 @@ kdb_prnt_addr2sym(domid_t domid, kdbva_t
         p = kdb_guest_addr2sym(addr, domid, &offs);
     } else
         symbols_lookup(addr, &sz, &offs, buf);
+
     snprintf(pbuf, 150, "%s%s+%lx", prefix, p, offs);
     if (*nl != '\n')
         kdbp("%-30s%s", pbuf, nl);  /* prints more than 30 if needed */
     else
         kdbp("%s%s", pbuf, nl);
+
 }
 
 static int

--MP_/R.1sMt_LjPbCVVbgRW8Pwbf
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

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

--MP_/R.1sMt_LjPbCVVbgRW8Pwbf--


From xen-devel-bounces@lists.xensource.com Thu Nov 24 17:45:48 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Thu, 24 Nov 2011 17:45:48 +0000
Received: from localhost ([127.0.0.1] helo=lists.xen.org)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RTdMj-0003R0-ET; Thu, 24 Nov 2011 17:45:41 +0000
Received: from mail27.messagelabs.com ([193.109.254.147])
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <anthony.perard@citrix.com>) id 1RTdMh-0003NT-Fv
	for xen-devel@lists.xensource.com; Thu, 24 Nov 2011 17:45:40 +0000
X-Env-Sender: anthony.perard@citrix.com
X-Msg-Ref: server-7.tower-27.messagelabs.com!1322156652!58158209!5
X-Originating-IP: [66.165.176.89]
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 26361 invoked from network); 24 Nov 2011 17:44:25 -0000
Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89)
	by server-7.tower-27.messagelabs.com with RC4-SHA encrypted SMTP;
	24 Nov 2011 17:44:25 -0000
X-IronPort-AV: E=Sophos;i="4.69,566,1315195200"; d="scan'208";a="19391878"
Received: from ftlpmailmx01.citrite.net ([10.13.107.65])
	by FTLPIPO01.CITRIX.COM with ESMTP/TLS/RC4-MD5;
	24 Nov 2011 12:45:08 -0500
Received: from smtp01.ad.xensource.com (10.219.128.104) by
	smtprelay.citrix.com (10.13.107.65) with Microsoft SMTP Server id
	8.3.213.0; Thu, 24 Nov 2011 12:45:07 -0500
Received: from perard.uk.xensource.com (dhcp-3-28.uk.xensource.com
	[10.80.3.28] (may be forged))	by smtp01.ad.xensource.com
	(8.13.1/8.13.1) with
	ESMTP id pAOHiqJ9027444;	Thu, 24 Nov 2011 09:45:06 -0800
From: Anthony PERARD <anthony.perard@citrix.com>
To: QEMU-devel <qemu-devel@nongnu.org>
Date: Thu, 24 Nov 2011 17:44:37 +0000
Message-ID: <1322156679-9441-9-git-send-email-anthony.perard@citrix.com>
X-Mailer: git-send-email 1.7.2.5
In-Reply-To: <1322156679-9441-1-git-send-email-anthony.perard@citrix.com>
References: <1322156679-9441-1-git-send-email-anthony.perard@citrix.com>
MIME-Version: 1.0
Cc: Anthony PERARD <anthony.perard@citrix.com>, Guy Zana <guy@neocleus.com>,
	Xen Devel <xen-devel@lists.xensource.com>,
	Allen Kay <allen.m.kay@intel.com>,
	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Subject: [Xen-devel] [PATCH V5 08/10] Introduce Xen PCI Passthrough,
	PCI config space helpers (2/3)
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.13
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/options/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com

From: Allen Kay <allen.m.kay@intel.com>

A more complete history can be found here:
git://xenbits.xensource.com/qemu-xen-unstable.git

Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Guy Zana <guy@neocleus.com>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
---
 hw/xen_pci_passthrough.c             |   15 +
 hw/xen_pci_passthrough_config_init.c | 2131 ++++++++++++++++++++++++++++++++++
 2 files changed, 2146 insertions(+), 0 deletions(-)

diff --git a/hw/xen_pci_passthrough.c b/hw/xen_pci_passthrough.c
index 998470b..c816ed5 100644
--- a/hw/xen_pci_passthrough.c
+++ b/hw/xen_pci_passthrough.c
@@ -360,6 +360,11 @@ out:
             PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
         }
     }
+
+    if (s->pm_state != NULL && s->pm_state->flags & PT_FLAG_TRANSITING) {
+        qemu_mod_timer(s->pm_state->pm_timer,
+                       qemu_get_clock_ms(rt_clock) + s->pm_state->pm_delay);
+    }
 }
 
 /* ioport/iomem space*/
@@ -706,6 +711,13 @@ static int pt_initfn(PCIDevice *pcidev)
     /* Handle real device's MMIO/PIO BARs */
     pt_register_regions(s);
 
+    /* reinitialize each config register to be emulated */
+    if (pt_config_init(s)) {
+        PT_ERR(pcidev, "PCI Config space initialisation failed.\n");
+        host_pci_device_put(s->real_device);
+        return -1;
+    }
+
     /* Bind interrupt */
     if (!s->dev.config[PCI_INTERRUPT_PIN]) {
         PT_LOG(pcidev, "no pin interrupt\n");
@@ -798,6 +810,9 @@ static int pt_unregister_device(PCIDevice *pcidev)
         }
     }
 
+    /* delete all emulated config registers */
+    pt_config_delete(s);
+
     /* unregister real device's MMIO/PIO BARs */
     pt_unregister_regions(s);
 
diff --git a/hw/xen_pci_passthrough_config_init.c b/hw/xen_pci_passthrough_config_init.c
index 1e9de64..ae64544 100644
--- a/hw/xen_pci_passthrough_config_init.c
+++ b/hw/xen_pci_passthrough_config_init.c
@@ -1,11 +1,2142 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Alex Novik <alex@neocleus.com>
+ * Allen Kay <allen.m.kay@intel.com>
+ * Guy Zana <guy@neocleus.com>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ */
+
+#include "qemu-timer.h"
+#include "xen_backend.h"
 #include "xen_pci_passthrough.h"
 
+#define PT_MERGE_VALUE(value, data, val_mask) \
+    (((value) & (val_mask)) | ((data) & ~(val_mask)))
+
+#define PT_INVALID_REG          0xFFFFFFFF      /* invalid register value */
+
+/* prototype */
+
+static int pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                           uint32_t real_offset, uint32_t *data);
+static int pt_init_pci_config(XenPCIPassthroughState *s);
+
+
+/* helper */
+
+/* A return value of 1 means the capability should NOT be exposed to guest. */
+static int pt_hide_dev_cap(const HostPCIDevice *d, uint8_t grp_id)
+{
+    switch (grp_id) {
+    case PCI_CAP_ID_EXP:
+        /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0. We should not try to expose it to guest.
+         *
+         * The datasheet is available at
+         * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
+         *
+         * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
+         * PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0, so the Capability Version is 0 and
+         * pt_pcie_size_init() would fail.
+         */
+        if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
+            d->device_id == PCI_DEVICE_ID_INTEL_82599_VF) {
+            return 1;
+        }
+        break;
+    }
+    return 0;
+}
+
+/*   find emulate register group entry */
 XenPTRegGroup *pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
 {
+    XenPTRegGroup *entry = NULL;
+
+    /* find register group entry */
+    QLIST_FOREACH(entry, &s->reg_grp_tbl, entries) {
+        /* check address */
+        if ((entry->base_offset <= address)
+            && ((entry->base_offset + entry->size) > address)) {
+            return entry;
+        }
+    }
+
+    /* group entry not found */
     return NULL;
 }
 
+/* find emulate register entry */
 XenPTReg *pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
 {
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    uint32_t real_offset = 0;
+
+    /* find register entry */
+    QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
+        reg = reg_entry->reg;
+        real_offset = reg_grp->base_offset + reg->offset;
+        /* check address */
+        if ((real_offset <= address)
+            && ((real_offset + reg->size) > address)) {
+            return reg_entry;
+        }
+    }
+
     return NULL;
 }
+
+/* parse BAR */
+static PTBarFlag pt_bar_reg_parse(XenPCIPassthroughState *s, XenPTRegInfo *reg)
+{
+    PCIDevice *d = &s->dev;
+    XenPTRegion *region = NULL;
+    PCIIORegion *r;
+    int index = 0;
+
+    /* check 64bit BAR */
+    index = pt_bar_offset_to_index(reg->offset);
+    if ((0 < index) && (index < PCI_ROM_SLOT)) {
+        int flags = s->real_device->io_regions[index - 1].flags;
+
+        if ((flags & IORESOURCE_MEM) && (flags & IORESOURCE_MEM_64)) {
+            region = &s->bases[index - 1];
+            if (region->bar_flag != PT_BAR_FLAG_UPPER) {
+                return PT_BAR_FLAG_UPPER;
+            }
+        }
+    }
+
+    /* check unused BAR */
+    r = &d->io_regions[index];
+    if (r->size == 0) {
+        return PT_BAR_FLAG_UNUSED;
+    }
+
+    /* for ExpROM BAR */
+    if (index == PCI_ROM_SLOT) {
+        return PT_BAR_FLAG_MEM;
+    }
+
+    /* check BAR I/O indicator */
+    if (s->real_device->io_regions[index].flags & IORESOURCE_IO) {
+        return PT_BAR_FLAG_IO;
+    } else {
+        return PT_BAR_FLAG_MEM;
+    }
+}
+
+
+/****************
+ * general register functions
+ */
+
+/* register initialization function */
+
+static int pt_common_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = reg->init_val;
+    return 0;
+}
+
+/* Read register functions */
+
+static int pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint8_t *value, uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t valid_emu_mask = 0;
+
+    /* emulate byte register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+
+    /* emulate word register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+
+    /* emulate long register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+   return 0;
+}
+
+/* Write register functions */
+
+static int pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint8_t *value, uint8_t dev_value,
+                             uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t writable_mask = 0;
+    uint8_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+static int pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint16_t *value, uint16_t dev_value,
+                             uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+static int pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint32_t *value, uint32_t dev_value,
+                             uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* common restore register fonctions */
+static int pt_byte_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint32_t real_offset, uint8_t dev_value,
+                               uint8_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_byte(d->config + real_offset);
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, reg->emu_mask);
+
+    return 0;
+}
+static int pt_word_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint32_t real_offset, uint16_t dev_value,
+                               uint16_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_word(d->config + real_offset);
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, reg->emu_mask);
+
+    return 0;
+}
+
+
+/* XenPTRegInfo declaration
+ * - only for emulated register (either a part or whole bit).
+ * - for passthrough register that need special behavior (like interacting with
+ *   other component), set emu_mask to all 0 and specify r/w func properly.
+ * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
+ */
+
+/********************
+ * Header Type0
+ */
+
+static int pt_vendor_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = s->real_device->vendor_id;
+    return 0;
+}
+static int pt_device_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = s->real_device->device_id;
+    return 0;
+}
+static int pt_status_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    uint32_t reg_field = 0;
+
+    /* find Header register group */
+    reg_grp_entry = pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
+    if (reg_grp_entry) {
+        /* find Capabilities Pointer register */
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
+        if (reg_entry) {
+            /* check Capabilities Pointer register */
+            if (reg_entry->data) {
+                reg_field |= PCI_STATUS_CAP_LIST;
+            } else {
+                reg_field &= ~PCI_STATUS_CAP_LIST;
+            }
+        } else {
+            xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
+                                     " for Capabilities Pointer register."
+                                     " (%s)\n", __func__);
+            return -1;
+        }
+    } else {
+        xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
+                                 " for Header. (%s)\n", __func__);
+        return -1;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int pt_header_type_reg_init(XenPCIPassthroughState *s,
+                                   XenPTRegInfo *reg, uint32_t real_offset,
+                                   uint32_t *data)
+{
+    /* read PCI_HEADER_TYPE */
+    *data = reg->init_val | 0x80;
+    return 0;
+}
+
+/* initialize Interrupt Pin register */
+static int pt_irqpin_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegInfo *reg, uint32_t real_offset,
+                              uint32_t *data)
+{
+    *data = pci_read_intx(s);
+    return 0;
+}
+
+/* Command register */
+static int pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                           uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* emulate word register */
+    valid_emu_mask = emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint16_t *value, uint16_t dev_value,
+                            uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t wr_value = *value;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* modify emulate register */
+    writable_mask = ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+
+    if (*value & PCI_COMMAND_INTX_DISABLE) {
+        throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+    } else {
+        if (s->machine_irq) {
+            throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+        }
+    }
+
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* mapping BAR */
+    pt_bar_mapping(s, wr_value & PCI_COMMAND_IO,
+                   wr_value & PCI_COMMAND_MEMORY);
+
+    return 0;
+}
+static int pt_cmd_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint32_t real_offset, uint16_t dev_value,
+                              uint16_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+    uint16_t restorable_mask = 0;
+
+    /* use I/O device register's value as restore value */
+    *value = pci_get_word(d->config + real_offset);
+
+    /* create value for restoring to I/O device register
+     * but do not include Fast Back-to-Back Enable bit.
+     */
+    restorable_mask = reg->emu_mask & ~PCI_COMMAND_FAST_BACK;
+    *value = PT_MERGE_VALUE(*value, dev_value, restorable_mask);
+
+    if (!s->machine_irq) {
+        *value |= PCI_COMMAND_INTX_DISABLE;
+    } else {
+        *value &= ~PCI_COMMAND_INTX_DISABLE;
+    }
+
+    return 0;
+}
+
+/* BAR */
+#define PT_BAR_MEM_RO_MASK      0x0000000F      /* BAR ReadOnly mask(Memory) */
+#define PT_BAR_MEM_EMU_MASK     0xFFFFFFF0      /* BAR emul mask(Memory) */
+#define PT_BAR_IO_RO_MASK       0x00000003      /* BAR ReadOnly mask(I/O) */
+#define PT_BAR_IO_EMU_MASK      0xFFFFFFFC      /* BAR emul mask(I/O) */
+
+static inline uint32_t base_address_with_flags(HostPCIIORegion *hr)
+{
+    if ((hr->flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+        return hr->base_addr | (hr->flags & ~PCI_BASE_ADDRESS_IO_MASK);
+    } else {
+        return hr->base_addr | (hr->flags & ~PCI_BASE_ADDRESS_MEM_MASK);
+    }
+}
+
+static int pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                           uint32_t real_offset, uint32_t *data)
+{
+    uint32_t reg_field = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* set initial guest physical base address to -1 */
+    s->bases[index].e_physbase = -1;
+
+    /* set BAR flag */
+    s->bases[index].bar_flag = pt_bar_reg_parse(s, reg);
+    if (s->bases[index].bar_flag == PT_BAR_FLAG_UNUSED) {
+        reg_field = PT_INVALID_REG;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                           uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    int index;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* use fixed-up value from kernel sysfs */
+    *value = base_address_with_flags(&s->real_device->io_regions[index]);
+
+    /* set emulate mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        break;
+    default:
+        break;
+    }
+
+    /* emulate BAR */
+    valid_emu_mask = bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+   return 0;
+}
+static int pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                            uint32_t *value, uint32_t dev_value,
+                            uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = &s->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+    uint32_t new_addr, last_addr;
+    uint32_t prev_offset;
+    uint32_t r_size = 0;
+    int index = 0;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    r = &d->io_regions[index];
+    base = &s->bases[index];
+    r_size = pt_get_emul_size(base->bar_flag, r->size);
+
+    /* set emulate mask and read-only mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        bar_ro_mask = PT_BAR_MEM_RO_MASK | (r_size - 1);
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        bar_ro_mask = PT_BAR_IO_RO_MASK | (r_size - 1);
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        bar_ro_mask = 0;    /* all upper 32bit are R/W */
+        break;
+    default:
+        break;
+    }
+
+    /* modify emulate register */
+    writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* check whether we need to update the virtual region address or not */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        /* nothing to do */
+        break;
+    case PT_BAR_FLAG_IO:
+        new_addr = cfg_entry->data;
+        last_addr = new_addr + r_size - 1;
+        /* check invalid address */
+        if (last_addr <= new_addr || !new_addr || last_addr >= UINT16_MAX) {
+            /* check 64K range */
+            if ((last_addr >= UINT16_MAX) &&
+                (cfg_entry->data != (PT_BAR_ALLF & ~bar_ro_mask))) {
+                PT_WARN(d, "Guest attempt to set Base Address "
+                       "over the 64KB. (offset: 0x%02x,"
+                       " addr: 0x%08x, size: 0x%08x)\n",
+                       reg->offset, new_addr, r_size);
+            }
+            /* just remove mapping */
+            r->addr = PCI_BAR_UNMAPPED;
+            goto exit;
+        }
+        break;
+    case PT_BAR_FLAG_UPPER:
+        if (cfg_entry->data) {
+            if (cfg_entry->data != (PT_BAR_ALLF & ~bar_ro_mask)) {
+                PT_WARN(d, "Guest attempt to set high MMIO Base Address. "
+                        "Ignore mapping. "
+                        "(offset: 0x%02x, high address: 0x%08x)\n",
+                        reg->offset, cfg_entry->data);
+            }
+            /* clear lower address */
+            d->io_regions[index-1].addr = -1;
+        } else {
+            /* find lower 32bit BAR */
+            prev_offset = (reg->offset - 4);
+            reg_grp_entry = pt_find_reg_grp(s, prev_offset);
+            if (reg_grp_entry) {
+                reg_entry = pt_find_reg(reg_grp_entry, prev_offset);
+                if (reg_entry) {
+                    /* restore lower address */
+                    d->io_regions[index-1].addr = reg_entry->data;
+                } else {
+                    return -1;
+                }
+            } else {
+                return -1;
+            }
+        }
+
+        /* never mapping the 'empty' upper region,
+         * because we'll do it enough for the lower region.
+         */
+        r->addr = -1;
+        goto exit;
+    default:
+        break;
+    }
+
+    /* update the corresponding virtual region address */
+    /*
+     * When guest code tries to get block size of mmio, it will write all "1"s
+     * into pci bar register. In this case, cfg_entry->data == writable_mask.
+     * Especially for devices with large mmio, the value of writable_mask
+     * is likely to be a guest physical address that has been mapped to ram
+     * rather than mmio. Remapping this value to mmio should be prevented.
+     */
+
+    if (cfg_entry->data != writable_mask) {
+        r->addr = cfg_entry->data;
+    }
+
+exit:
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* After BAR reg update, we need to remap BAR */
+    reg_grp_entry = pt_find_reg_grp(s, PCI_COMMAND);
+    if (reg_grp_entry) {
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_COMMAND);
+        if (reg_entry) {
+            pt_bar_mapping_one(s, index, reg_entry->data & PCI_COMMAND_IO,
+                               reg_entry->data & PCI_COMMAND_MEMORY);
+        }
+    }
+
+    return 0;
+}
+static int pt_bar_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint32_t real_offset, uint32_t dev_value,
+                              uint32_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t bar_emu_mask = 0;
+    int index = 0;
+
+    /* get BAR index */
+    index = pt_bar_offset_to_index(reg->offset);
+    if (index < 0) {
+        PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* use value from kernel sysfs */
+    if (s->bases[index].bar_flag == PT_BAR_FLAG_UPPER) {
+        *value = s->real_device->io_regions[index - 1].base_addr >> 32;
+    } else {
+        *value = base_address_with_flags(&s->real_device->io_regions[index]);
+    }
+
+    /* set emulate mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case PT_BAR_FLAG_MEM:
+        bar_emu_mask = PT_BAR_MEM_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_IO:
+        bar_emu_mask = PT_BAR_IO_EMU_MASK;
+        break;
+    case PT_BAR_FLAG_UPPER:
+        bar_emu_mask = PT_BAR_ALLF;
+        break;
+    default:
+        break;
+    }
+
+    /* create value for restoring to I/O device register */
+    *value = PT_MERGE_VALUE(*value, dev_value, bar_emu_mask);
+
+    return 0;
+}
+
+/* write Exp ROM BAR */
+static int pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
+                                    XenPTReg *cfg_entry, uint32_t *value,
+                                    uint32_t dev_value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = (PCIDevice *)&s->dev;
+    PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    pcibus_t r_size = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+
+    r = &d->io_regions[PCI_ROM_SLOT];
+    r_size = r->size;
+    base = &s->bases[PCI_ROM_SLOT];
+    /* align memory type resource size */
+    pt_get_emul_size(base->bar_flag, r_size);
+
+    /* set emulate mask and read-only mask */
+    bar_emu_mask = reg->emu_mask;
+    bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
+
+    /* modify emulate register */
+    writable_mask = ~bar_ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* update the corresponding virtual region address */
+    /*
+     * When guest code tries to get block size of mmio, it will write all "1"s
+     * into pci bar register. In this case, cfg_entry->data == writable_mask.
+     * Especially for devices with large mmio, the value of writable_mask
+     * is likely to be a guest physical address that has been mapped to ram
+     * rather than mmio. Remapping this value to mmio should be prevented.
+     */
+
+    if (cfg_entry->data != writable_mask) {
+        r->addr = cfg_entry->data;
+    }
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    /* After BAR reg update, we need to remap BAR*/
+    reg_grp_entry = pt_find_reg_grp(s, PCI_COMMAND);
+    if (reg_grp_entry) {
+        reg_entry = pt_find_reg(reg_grp_entry, PCI_COMMAND);
+        if (reg_entry) {
+            pt_bar_mapping_one(s, PCI_ROM_SLOT,
+                               reg_entry->data & PCI_COMMAND_IO,
+                               reg_entry->data & PCI_COMMAND_MEMORY);
+        }
+    }
+
+    return 0;
+}
+/* restore ROM BAR */
+static int pt_exp_rom_bar_reg_restore(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry,
+                                      uint32_t real_offset,
+                                      uint32_t dev_value, uint32_t *value)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t v;
+
+    if (host_pci_get_long(s->real_device, PCI_ROM_ADDRESS, &v)) {
+        return -1;
+    }
+    /* use value from kernel sysfs */
+    *value = PT_MERGE_VALUE(v, dev_value, reg->emu_mask);
+    return 0;
+}
+
+/* Header Type0 reg static infomation table */
+static XenPTRegInfo pt_emu_reg_header0_tbl[] = {
+    /* Vendor ID reg */
+    {
+        .offset     = PCI_VENDOR_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_vendor_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Device ID reg */
+    {
+        .offset     = PCI_DEVICE_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_device_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Command reg */
+    {
+        .offset     = PCI_COMMAND,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xF880,
+        .emu_mask   = 0x0740,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_cmd_reg_read,
+        .u.w.write  = pt_cmd_reg_write,
+        .u.w.restore  = pt_cmd_reg_restore,
+    },
+    /* Capabilities Pointer reg */
+    {
+        .offset     = PCI_CAPABILITY_LIST,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Status reg */
+    /* use emulated Cap Ptr value to initialize,
+     * so need to be declared after Cap Ptr reg
+     */
+    {
+        .offset     = PCI_STATUS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x06FF,
+        .emu_mask   = 0x0010,
+        .init       = pt_status_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* Cache Line Size reg */
+    {
+        .offset     = PCI_CACHE_LINE_SIZE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = pt_byte_reg_restore,
+    },
+    /* Latency Timer reg */
+    {
+        .offset     = PCI_LATENCY_TIMER,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = pt_byte_reg_restore,
+    },
+    /* Header Type reg */
+    {
+        .offset     = PCI_HEADER_TYPE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0x00,
+        .init       = pt_header_type_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Interrupt Line reg */
+    {
+        .offset     = PCI_INTERRUPT_LINE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = pt_common_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Interrupt Pin reg */
+    {
+        .offset     = PCI_INTERRUPT_PIN,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_irqpin_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* BAR 0 reg */
+    /* mask of BAR need to be decided later, depends on IO/MEM type */
+    {
+        .offset     = PCI_BASE_ADDRESS_0,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 1 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_1,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 2 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_2,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 3 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_3,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 4 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_4,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* BAR 5 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_5,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_bar_reg_read,
+        .u.dw.write = pt_bar_reg_write,
+        .u.dw.restore = pt_bar_reg_restore,
+    },
+    /* Expansion ROM BAR reg */
+    {
+        .offset     = PCI_ROM_ADDRESS,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x000007FE,
+        .emu_mask   = 0xFFFFF800,
+        .init       = pt_bar_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_exp_rom_bar_reg_write,
+        .u.dw.restore = pt_exp_rom_bar_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Vital Product Data Capability
+ */
+
+/* Vital Product Data Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_vpd_tbl[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/**************************************
+ * Vendor Specific Capability
+ */
+
+/* Vendor Specific Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_vendor_tbl[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*****************************
+ * PCI Express Capability
+ */
+
+/* initialize Link Control register */
+static int pt_linkctrl_reg_init(XenPCIPassthroughState *s,
+                                XenPTRegInfo *reg, uint32_t real_offset,
+                                uint32_t *data)
+{
+    uint8_t cap_ver = 0;
+    uint8_t dev_type = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+    dev_type = (pci_get_byte(s->dev.config + real_offset - reg->offset
+                             + PCI_EXP_FLAGS)
+                & PCI_EXP_FLAGS_TYPE) >> 4;
+
+    /* no need to initialize in case of Root Complex Integrated Endpoint
+     * with cap_ver 1.x
+     */
+    if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
+        *data = PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Device Control 2 register */
+static int pt_devctrl2_reg_init(XenPCIPassthroughState *s,
+                                XenPTRegInfo *reg, uint32_t real_offset,
+                                uint32_t *data)
+{
+    uint8_t cap_ver = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        *data = PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Link Control 2 register */
+static int pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
+                                 XenPTRegInfo *reg, uint32_t real_offset,
+                                 uint32_t *data)
+{
+    uint32_t reg_field = 0;
+    uint8_t cap_ver = 0;
+
+    cap_ver = pci_get_byte(s->dev.config + real_offset - reg->offset
+                           + PCI_EXP_FLAGS)
+        & PCI_EXP_FLAGS_VERS;
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        reg_field = PT_INVALID_REG;
+    } else {
+        /* set Supported Link Speed */
+        uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset
+                                      + PCI_EXP_LNKCAP);
+        reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+
+/* PCI Express Capability Structure reg static infomation table */
+static XenPTRegInfo pt_emu_reg_pcie_tbl[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Device Capabilities reg */
+    {
+        .offset     = PCI_EXP_DEVCAP,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x1FFCFFFF,
+        .emu_mask   = 0x10000000,
+        .init       = pt_common_reg_init,
+        .u.dw.read  = pt_long_reg_read,
+        .u.dw.write = pt_long_reg_write,
+        .u.dw.restore = NULL,
+    },
+    /* Device Control reg */
+    {
+        .offset     = PCI_EXP_DEVCTL,
+        .size       = 2,
+        .init_val   = 0x2810,
+        .ro_mask    = 0x8400,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_common_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Link Control reg */
+    {
+        .offset     = PCI_EXP_LNKCTL,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFC34,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_linkctrl_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Device Control 2 reg */
+    {
+        .offset     = 0x28,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFE0,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_devctrl2_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    /* Link Control 2 reg */
+    {
+        .offset     = 0x30,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xE040,
+        .emu_mask   = 0xFFFF,
+        .init       = pt_linkctrl2_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = pt_word_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Power Management Capability
+ */
+
+/* initialize Power Management Capabilities register */
+static int pt_pmc_reg_init(XenPCIPassthroughState *s,
+                           XenPTRegInfo *reg, uint32_t real_offset,
+                           uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+
+    if (s->power_mgmt) {
+        /* set Power Management Capabilities register */
+        s->pm_state->pmc_field = pci_get_word(d->config + real_offset);
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize PCI Power Management Control/Status register */
+static int pt_pmcsr_reg_init(XenPCIPassthroughState *s,
+                             XenPTRegInfo *reg, uint32_t real_offset,
+                             uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t cap_ver  = 0;
+    uint16_t v = 0;
+
+    if (!s->power_mgmt) {
+        *data = reg->init_val;
+        return 0;
+    }
+
+    /* check PCI Power Management support version */
+    cap_ver = s->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
+
+    if (cap_ver > 2) {
+        /* set No Soft Reset */
+        s->pm_state->no_soft_reset =
+            pci_get_byte(d->config + real_offset) & PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    host_pci_get_word(s->real_device, real_offset, &v);
+    /* wake up real physical device */
+    switch (v & PCI_PM_CTRL_STATE_MASK) {
+    case 0:
+        break;
+    case 1:
+        PT_LOG(d, "Power state transition D1 -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        break;
+    case 2:
+        PT_LOG(d, "Power state transition D2 -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        usleep(200);
+        break;
+    case 3:
+        PT_LOG(d, "Power state transition D3hot -> D0active\n");
+        host_pci_set_word(s->real_device, real_offset, 0);
+        usleep(10 * 1000);
+        if (pt_init_pci_config(s)) {
+            return -1;
+        }
+        break;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* read Power Management Control/Status register */
+static int pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                             uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = reg->emu_mask;
+
+    if (!s->power_mgmt) {
+        valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    valid_emu_mask = valid_emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+/* reset Interrupt and I/O resource  */
+static void pt_reset_interrupt_and_io_mapping(XenPCIPassthroughState *s)
+{
+    PCIDevice *d = &s->dev;
+    PCIIORegion *r;
+    int i = 0;
+    uint8_t e_device = 0;
+    uint8_t e_intx = 0;
+
+    /* unbind INTx */
+    e_device = PCI_SLOT(s->dev.devfn);
+    e_intx = pci_intx(s);
+
+    if (s->machine_irq) {
+        if (xc_domain_unbind_pt_irq(xen_xc, xen_domid, s->machine_irq,
+                                    PT_IRQ_TYPE_PCI, 0, e_device, e_intx, 0)) {
+            PT_ERR(d, "Unbinding of interrupt failed!\n");
+        }
+    }
+
+    /* clear all virtual region address */
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        r = &d->io_regions[i];
+        r->addr = -1;
+    }
+
+    /* unmapping BAR */
+    pt_bar_mapping(s, 0, 0);
+}
+/* check power state transition */
+static int check_power_state(XenPCIPassthroughState *s)
+{
+    XenPTPM *pm_state = s->pm_state;
+    PCIDevice *d = &s->dev;
+    uint16_t read_val = 0;
+    uint16_t cur_state = 0;
+
+    /* get current power state */
+    if (host_pci_get_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                          &read_val)) {
+        return -1;
+    }
+    cur_state = read_val & PCI_PM_CTRL_STATE_MASK;
+
+    if (pm_state->req_state != cur_state) {
+        PT_ERR(d, "Failed to change power state. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, cur_state);
+        return -1;
+    }
+    return 0;
+}
+/* write Power Management Control/Status register */
+static void pt_from_d3hot_to_d0_with_reset(void *opaque)
+{
+    XenPCIPassthroughState *s = opaque;
+    XenPTPM *pm_state = s->pm_state;
+    int ret = 0;
+
+    /* check power state */
+    ret = check_power_state(s);
+
+    if (ret < 0) {
+        goto out;
+    }
+
+    pt_init_pci_config(s);
+
+out:
+    /* power state transition flags off */
+    pm_state->flags &= ~PT_FLAG_TRANSITING;
+
+    qemu_free_timer(pm_state->pm_timer);
+    pm_state->pm_timer = NULL;
+}
+static void pt_default_power_transition(void *opaque)
+{
+    XenPCIPassthroughState *ptdev = opaque;
+    XenPTPM *pm_state = ptdev->pm_state;
+
+    /* check power state */
+    check_power_state(ptdev);
+
+    /* power state transition flags off */
+    pm_state->flags &= ~PT_FLAG_TRANSITING;
+
+    qemu_free_timer(pm_state->pm_timer);
+    pm_state->pm_timer = NULL;
+}
+static int pt_pmcsr_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                              uint16_t *value, uint16_t dev_value,
+                              uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    PCIDevice *d = &s->dev;
+    uint16_t emu_mask = reg->emu_mask;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    XenPTPM *pm_state = s->pm_state;
+
+    if (!s->power_mgmt) {
+        emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+    }
+
+    /* modify emulate register */
+    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+    *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+    if (!s->power_mgmt) {
+        return 0;
+    }
+
+    /* set I/O device power state */
+    pm_state->cur_state = dev_value & PCI_PM_CTRL_STATE_MASK;
+
+    /* set Guest requested PowerState */
+    pm_state->req_state = *value & PCI_PM_CTRL_STATE_MASK;
+
+    /* check power state transition or not */
+    if (pm_state->cur_state == pm_state->req_state) {
+        /* not power state transition */
+        return 0;
+    }
+
+    /* check enable power state transition */
+    if ((pm_state->req_state != 0) &&
+        (pm_state->cur_state > pm_state->req_state)) {
+        PT_ERR(d, "Invalid power transition. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, pm_state->cur_state);
+
+        return 0;
+    }
+
+    /* check if this device supports the requested power state */
+    if (((pm_state->req_state == 1) && !(pm_state->pmc_field & PCI_PM_CAP_D1))
+        || ((pm_state->req_state == 2) &&
+            !(pm_state->pmc_field & PCI_PM_CAP_D2))) {
+        PT_ERR(d, "Invalid power transition. "
+               "(requested state: %d, current state: %d)\n",
+               pm_state->req_state, pm_state->cur_state);
+
+        return 0;
+    }
+
+    /* in case of transition related to D3hot, it's necessary to wait 10 ms.
+     * But because writing to register will be performed later on actually,
+     * don't start QEMUTimer right now, just alloc and init QEMUTimer here.
+     */
+    if ((pm_state->cur_state == 3) || (pm_state->req_state == 3)) {
+        if (pm_state->req_state == 0) {
+            /* alloc and init QEMUTimer */
+            if (!pm_state->no_soft_reset) {
+                pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                    pt_from_d3hot_to_d0_with_reset, s);
+
+                /* reset Interrupt and I/O resource mapping */
+                pt_reset_interrupt_and_io_mapping(s);
+            } else {
+                pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                                        pt_default_power_transition, s);
+            }
+        } else {
+            /* alloc and init QEMUTimer */
+            pm_state->pm_timer = qemu_new_timer_ms(rt_clock,
+                pt_default_power_transition, s);
+        }
+
+        /* set power state transition delay */
+        pm_state->pm_delay = 10;
+
+        /* power state transition flags on */
+        pm_state->flags |= PT_FLAG_TRANSITING;
+    }
+    /* in case of transition related to D0, D1 and D2,
+     * no need to use QEMUTimer.
+     * So, we perfom writing to register here and then read it back.
+     */
+    else {
+        /* write power state to I/O device register */
+        host_pci_set_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                          *value);
+
+        /* in case of transition related to D2,
+         * it's necessary to wait 200 usec.
+         * But because QEMUTimer do not support microsec unit right now,
+         * so we do wait ourself here.
+         */
+        if ((pm_state->cur_state == 2) || (pm_state->req_state == 2)) {
+            usleep(200);
+        }
+
+        /* check power state */
+        check_power_state(s);
+
+        /* recreate value for writing to I/O device register */
+        if (host_pci_get_word(s->real_device, pm_state->pm_base + PCI_PM_CTRL,
+                              value)) {
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/* restore Power Management Control/Status register */
+static int pt_pmcsr_reg_restore(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint32_t real_offset, uint16_t dev_value,
+                                uint16_t *value)
+{
+    /* create value for restoring to I/O device register
+     * No need to restore, just clear PME Enable and PME Status bit
+     * Note: register type of PME Status bit is RW1C, so clear by writing 1b
+     */
+    *value = (dev_value & ~PCI_PM_CTRL_PME_ENABLE) | PCI_PM_CTRL_PME_STATUS;
+
+    return 0;
+}
+
+
+/* Power Management Capability reg static infomation table */
+static XenPTRegInfo pt_emu_reg_pm_tbl[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = pt_ptr_reg_init,
+        .u.b.read   = pt_byte_reg_read,
+        .u.b.write  = pt_byte_reg_write,
+        .u.b.restore  = NULL,
+    },
+    /* Power Management Capabilities reg */
+    {
+        .offset     = PCI_CAP_FLAGS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xF9C8,
+        .init       = pt_pmc_reg_init,
+        .u.w.read   = pt_word_reg_read,
+        .u.w.write  = pt_word_reg_write,
+        .u.w.restore  = NULL,
+    },
+    /* PCI Power Management Control/Status reg */
+    {
+        .offset     = PCI_PM_CTRL,
+        .size       = 2,
+        .init_val   = 0x0008,
+        .ro_mask    = 0xE1FC,
+        .emu_mask   = 0x8100,
+        .init       = pt_pmcsr_reg_init,
+        .u.w.read   = pt_pmcsr_reg_read,
+        .u.w.write  = pt_pmcsr_reg_write,
+        .u.w.restore  = pt_pmcsr_reg_restore,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/****************************
+ * Capabilities
+ */
+
+/* AER register operations */
+
+static void aer_save_one_register(XenPCIPassthroughState *s, int offset)
+{
+    PCIDevice *d = &s->dev;
+    uint32_t aer_base = s->pm_state->aer_base;
+    uint32_t val = 0;
+
+    if (host_pci_get_long(s->real_device, aer_base + offset, &val)) {
+        return;
+    }
+    pci_set_long(d->config + aer_base + offset, val);
+}
+static void pt_aer_reg_save(XenPCIPassthroughState *s)
+{
+    /* after reset, following register values should be restored.
+     * So, save them.
+     */
+    aer_save_one_register(s, PCI_ERR_UNCOR_MASK);
+    aer_save_one_register(s, PCI_ERR_UNCOR_SEVER);
+    aer_save_one_register(s, PCI_ERR_COR_MASK);
+    aer_save_one_register(s, PCI_ERR_CAP);
+}
+static void aer_restore_one_register(XenPCIPassthroughState *s, int offset)
+{
+    PCIDevice *d = &s->dev;
+    uint32_t aer_base = s->pm_state->aer_base;
+    uint32_t config = 0;
+
+    config = pci_get_long(d->config + aer_base + offset);
+    host_pci_set_long(s->real_device, aer_base + offset, config);
+}
+static void pt_aer_reg_restore(XenPCIPassthroughState *s)
+{
+    /* the following registers should be reconfigured to correct values
+     * after reset. restore them.
+     * other registers should not be reconfigured after reset
+     * if there is no reason
+     */
+    aer_restore_one_register(s, PCI_ERR_UNCOR_MASK);
+    aer_restore_one_register(s, PCI_ERR_UNCOR_SEVER);
+    aer_restore_one_register(s, PCI_ERR_COR_MASK);
+    aer_restore_one_register(s, PCI_ERR_CAP);
+}
+
+/* capability structure register group size functions */
+
+static int pt_reg_grp_size_init(XenPCIPassthroughState *s,
+                                const XenPTRegGroupInfo *grp_reg,
+                                uint32_t base_offset, uint8_t *size)
+{
+    *size = grp_reg->grp_size;
+    return 0;
+}
+/* get Power Management Capability Structure register group size */
+static int pt_pm_size_init(XenPCIPassthroughState *s,
+                           const XenPTRegGroupInfo *grp_reg,
+                           uint32_t base_offset, uint8_t *size)
+{
+    *size = grp_reg->grp_size;
+
+    if (!s->power_mgmt) {
+        return 0;
+    }
+
+    s->pm_state = g_new0(XenPTPM, 1);
+
+    /* set Power Management Capability base offset */
+    s->pm_state->pm_base = base_offset;
+
+    /* find AER register and set AER Capability base offset */
+    s->pm_state->aer_base = host_pci_find_ext_cap_offset(s->real_device,
+                                                         PCI_EXT_CAP_ID_ERR);
+
+    /* save AER register */
+    if (s->pm_state->aer_base) {
+        pt_aer_reg_save(s);
+    }
+
+    return 0;
+}
+/* get Vendor Specific Capability Structure register group size */
+static int pt_vendor_size_init(XenPCIPassthroughState *s,
+                               const XenPTRegGroupInfo *grp_reg,
+                               uint32_t base_offset, uint8_t *size)
+{
+    *size = pci_get_byte(s->dev.config + base_offset + 0x02);
+    return 0;
+}
+/* get PCI Express Capability Structure register group size */
+static int pt_pcie_size_init(XenPCIPassthroughState *s,
+                             const XenPTRegGroupInfo *grp_reg,
+                             uint32_t base_offset, uint8_t *size)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t exp_flag = 0;
+    uint16_t type = 0;
+    uint16_t version = 0;
+    uint8_t pcie_size = 0;
+
+    exp_flag = pci_get_word(d->config + base_offset + PCI_EXP_FLAGS);
+    type = (exp_flag & PCI_EXP_FLAGS_TYPE) >> 4;
+    version = exp_flag & PCI_EXP_FLAGS_VERS;
+
+    /* calculate size depend on capability version and device/port type */
+    /* in case of PCI Express Base Specification Rev 1.x */
+    if (version == 1) {
+        /* The PCI Express Capabilities, Device Capabilities, and Device
+         * Status/Control registers are required for all PCI Express devices.
+         * The Link Capabilities and Link Status/Control are required for all
+         * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
+         * are not required to implement registers other than those listed
+         * above and terminate the capability structure.
+         */
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+            pcie_size = 0x14;
+            break;
+        case PCI_EXP_TYPE_RC_END:
+            /* has no link */
+            pcie_size = 0x0C;
+            break;
+        /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            PT_ERR(d, "Internal error: Unsupported device/port type (%d).\n",
+                   type);
+            return -1;
+        }
+    }
+    /* in case of PCI Express Base Specification Rev 2.0 */
+    else if (version == 2) {
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+        case PCI_EXP_TYPE_RC_END:
+            /* For Functions that do not implement the registers,
+             * these spaces must be hardwired to 0b.
+             */
+            pcie_size = 0x3C;
+            break;
+        /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            PT_ERR(d, "Internal error: Unsupported device/port type (%d).\n",
+                   type);
+            return -1;
+        }
+    } else {
+        PT_ERR(d, "Internal error: Unsupported capability version (%d).\n",
+               version);
+        return -1;
+    }
+
+    *size = pcie_size;
+    return 0;
+}
+
+static const XenPTRegGroupInfo pt_emu_reg_grp_tbl[] = {
+    /* Header Type0 reg group */
+    {
+        .grp_id      = 0xFF,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0x40,
+        .size_init   = pt_reg_grp_size_init,
+        .emu_reg_tbl = pt_emu_reg_header0_tbl,
+    },
+    /* PCI PowerManagement Capability reg group */
+    {
+        .grp_id      = PCI_CAP_ID_PM,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = PCI_PM_SIZEOF,
+        .size_init   = pt_pm_size_init,
+        .emu_reg_tbl = pt_emu_reg_pm_tbl,
+    },
+    /* AGP Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vital Product Data Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VPD,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0x08,
+        .size_init   = pt_reg_grp_size_init,
+        .emu_reg_tbl = pt_emu_reg_vpd_tbl,
+    },
+    /* Slot Identification reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SLOTID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x04,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* PCI-X Capabilities List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_PCIX,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x18,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Vendor Specific Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VNDR,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = pt_vendor_size_init,
+        .emu_reg_tbl = pt_emu_reg_vendor_tbl,
+    },
+    /* SHPC Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SHPC,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SSVID,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* AGP 8x Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP3,
+        .grp_type   = GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = pt_reg_grp_size_init,
+    },
+    /* PCI Express Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_EXP,
+        .grp_type    = GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = pt_pcie_size_init,
+        .emu_reg_tbl = pt_emu_reg_pcie_tbl,
+    },
+    {
+        .grp_size = 0,
+    },
+};
+
+/* initialize Capabilities Pointer or Next Pointer register */
+static int pt_ptr_reg_init(XenPCIPassthroughState *s,
+                           XenPTRegInfo *reg, uint32_t real_offset,
+                           uint32_t *data)
+{
+    /* uint32_t reg_field = (uint32_t)s->dev.config[real_offset]; */
+    uint32_t reg_field = pci_get_byte(s->dev.config + real_offset);
+    int i;
+
+    /* find capability offset */
+    while (reg_field) {
+        for (i = 0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++) {
+            if (pt_hide_dev_cap(s->real_device,
+                                pt_emu_reg_grp_tbl[i].grp_id)) {
+                continue;
+            }
+            if (pt_emu_reg_grp_tbl[i].grp_id == s->dev.config[reg_field]) {
+                if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU) {
+                    goto out;
+                }
+                /* ignore the 0 hardwired capability, find next one */
+                break;
+            }
+        }
+        /* next capability */
+        /* reg_field = (uint32_t)s->dev.config[reg_field + 1]; */
+        reg_field = pci_get_byte(s->dev.config + reg_field + 1);
+    }
+
+out:
+    *data = reg_field;
+    return 0;
+}
+
+
+/*************
+ * Main
+ */
+
+/* restore a part of I/O device register */
+static int pt_config_restore(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    uint32_t real_offset = 0;
+    uint32_t read_val = 0;
+    uint32_t val = 0;
+    int rc = 0;
+
+    /* find emulate register group entry */
+    QLIST_FOREACH(reg_grp_entry, &s->reg_grp_tbl, entries) {
+        /* find emulate register entry */
+        QLIST_FOREACH(reg_entry, &reg_grp_entry->reg_tbl_list, entries) {
+            reg = reg_entry->reg;
+
+            /* check whether restoring is needed */
+            if (!reg->u.b.restore) {
+                continue;
+            }
+
+            real_offset = reg_grp_entry->base_offset + reg->offset;
+
+            /* read I/O device register value */
+            rc = host_pci_get_block(s->real_device, real_offset,
+                                    (uint8_t *)&read_val, reg->size);
+
+            if (rc < 0) {
+                PT_ERR(&s->dev, "pci_read_block failed. "
+                       "return value: %d.\n", rc);
+                memset(&read_val, 0xff, reg->size);
+            }
+
+            val = 0;
+
+            /* restore based on register size */
+            switch (reg->size) {
+            case 1:
+                /* byte register */
+                rc = reg->u.b.restore(s, reg_entry, real_offset,
+                                      (uint8_t)read_val, (uint8_t *)&val);
+                break;
+            case 2:
+                /* word register */
+                rc = reg->u.w.restore(s, reg_entry, real_offset,
+                                      (uint16_t)read_val, (uint16_t *)&val);
+                break;
+            case 4:
+                /* double word register */
+                rc = reg->u.dw.restore(s, reg_entry, real_offset,
+                                       (uint32_t)read_val, (uint32_t *)&val);
+                break;
+            }
+
+            /* restoring error */
+            if (rc < 0) {
+                xen_shutdown_fatal_error("Internal error: Invalid restoring."
+                                         " (%s, rc: %d)\n", __func__, rc);
+                return -1;
+            }
+
+            PT_LOG_CONFIG(&s->dev, real_offset, val, reg->size);
+
+            rc = host_pci_set_block(s->real_device, real_offset,
+                                    (uint8_t *)&val, reg->size);
+
+            if (rc < 0) {
+                PT_ERR(&s->dev, "pci_write_block failed. "
+                       "return value: %d.\n", rc);
+                return -1;
+            }
+        }
+    }
+
+    /* if AER supported, restore it */
+    if (s->pm_state->aer_base) {
+        pt_aer_reg_restore(s);
+    }
+    return 0;
+}
+/* reinitialize all emulate registers */
+static int pt_config_reinit(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    int rc = 0;
+
+    /* find emulate register group entry */
+    QLIST_FOREACH(reg_grp_entry, &s->reg_grp_tbl, entries) {
+        /* find emulate register entry */
+        QLIST_FOREACH(reg_entry, &reg_grp_entry->reg_tbl_list, entries) {
+            reg = reg_entry->reg;
+            if (reg->init) {
+                /* initialize emulate register */
+                rc = reg->init(s, reg_entry->reg,
+                               reg_grp_entry->base_offset + reg->offset,
+                               &reg_entry->data);
+                if (rc < 0) {
+                    return rc;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+static int pt_init_pci_config(XenPCIPassthroughState *s)
+{
+    PCIDevice *d = &s->dev;
+    int rc = 0;
+
+    PT_LOG(d, "Reinitialize PCI configuration registers due to power state"
+           " transition with internal reset.\n");
+
+    /* restore a part of I/O device register */
+    rc = pt_config_restore(s);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /* reinitialize all emulate register */
+    rc = pt_config_reinit(s);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /* rebind machine_irq to device */
+    if (s->machine_irq != 0) {
+        uint8_t e_device = PCI_SLOT(s->dev.devfn);
+        uint8_t e_intx = pci_intx(s);
+
+        rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, s->machine_irq, 0,
+                                       e_device, e_intx);
+        if (rc < 0) {
+            PT_ERR(d, "Rebinding of interrupt failed! rc=%d\n", rc);
+        }
+    }
+
+    return rc;
+}
+
+static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
+{
+    uint8_t id;
+    int max_cap = 48;
+    uint8_t pos = PCI_CAPABILITY_LIST;
+    uint8_t status = 0;
+
+    if (host_pci_get_byte(s->real_device, PCI_STATUS, &status)) {
+        return 0;
+    }
+    if ((status & PCI_STATUS_CAP_LIST) == 0) {
+        return 0;
+    }
+
+    while (max_cap--) {
+        if (host_pci_get_byte(s->real_device, pos, &pos)) {
+            break;
+        }
+        if (pos < 0x40) {
+            break;
+        }
+
+        pos &= ~3;
+        if (host_pci_get_byte(s->real_device, pos + PCI_CAP_LIST_ID, &id)) {
+            break;
+        }
+
+        if (id == 0xff) {
+            break;
+        }
+        if (id == cap) {
+            return pos;
+        }
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+static int pt_config_reg_init(XenPCIPassthroughState *s,
+                              XenPTRegGroup *reg_grp, XenPTRegInfo *reg)
+{
+    XenPTReg *reg_entry;
+    uint32_t data = 0;
+    int rc = 0;
+
+    reg_entry = g_new0(XenPTReg, 1);
+    reg_entry->reg = reg;
+
+    if (reg->init) {
+        /* initialize emulate register */
+        rc = reg->init(s, reg_entry->reg,
+                       reg_grp->base_offset + reg->offset, &data);
+        if (rc < 0) {
+            free(reg_entry);
+            return rc;
+        }
+        if (data == PT_INVALID_REG) {
+            /* free unused BAR register entry */
+            free(reg_entry);
+            return 0;
+        }
+        /* set register value */
+        reg_entry->data = data;
+    }
+    /* list add register entry */
+    QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
+
+    return 0;
+}
+
+int pt_config_init(XenPCIPassthroughState *s)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    uint32_t reg_grp_offset = 0;
+    XenPTRegInfo *reg_tbl = NULL;
+    int i, j, rc;
+
+    QLIST_INIT(&s->reg_grp_tbl);
+
+    for (i = 0; pt_emu_reg_grp_tbl[i].grp_size != 0; i++) {
+        if (pt_emu_reg_grp_tbl[i].grp_id != 0xFF) {
+            if (pt_hide_dev_cap(s->real_device,
+                                pt_emu_reg_grp_tbl[i].grp_id)) {
+                continue;
+            }
+
+            reg_grp_offset = find_cap_offset(s, pt_emu_reg_grp_tbl[i].grp_id);
+
+            if (!reg_grp_offset) {
+                continue;
+            }
+        }
+
+        reg_grp_entry = g_new0(XenPTRegGroup, 1);
+        QLIST_INIT(&reg_grp_entry->reg_tbl_list);
+        QLIST_INSERT_HEAD(&s->reg_grp_tbl, reg_grp_entry, entries);
+
+        reg_grp_entry->base_offset = reg_grp_offset;
+        reg_grp_entry->reg_grp = pt_emu_reg_grp_tbl + i;
+        if (pt_emu_reg_grp_tbl[i].size_init) {
+            /* get register group size */
+            rc = pt_emu_reg_grp_tbl[i].size_init(s, reg_grp_entry->reg_grp,
+                                                 reg_grp_offset,
+                                                 &reg_grp_entry->size);
+            if (rc < 0) {
+                pt_config_delete(s);
+                return rc;
+            }
+        }
+
+        if (pt_emu_reg_grp_tbl[i].grp_type == GRP_TYPE_EMU) {
+            if (pt_emu_reg_grp_tbl[i].emu_reg_tbl) {
+                reg_tbl = pt_emu_reg_grp_tbl[i].emu_reg_tbl;
+                /* initialize capability register */
+                for (j = 0; reg_tbl->size != 0; j++, reg_tbl++) {
+                    /* initialize capability register */
+                    rc = pt_config_reg_init(s, reg_grp_entry, reg_tbl);
+                    if (rc < 0) {
+                        pt_config_delete(s);
+                        return rc;
+                    }
+                }
+            }
+        }
+        reg_grp_offset = 0;
+    }
+
+    return 0;
+}
+
+/* delete all emulate register */
+void pt_config_delete(XenPCIPassthroughState *s)
+{
+    struct XenPTRegGroup *reg_group, *next_grp;
+    struct XenPTReg *reg, *next_reg;
+
+    /* free Power Management info table */
+    if (s->pm_state) {
+        if (s->pm_state->pm_timer) {
+            qemu_del_timer(s->pm_state->pm_timer);
+            qemu_free_timer(s->pm_state->pm_timer);
+            s->pm_state->pm_timer = NULL;
+        }
+
+        g_free(s->pm_state);
+    }
+
+    /* free all register group entry */
+    QLIST_FOREACH_SAFE(reg_group, &s->reg_grp_tbl, entries, next_grp) {
+        /* free all register entry */
+        QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
+            QLIST_REMOVE(reg, entries);
+            g_free(reg);
+        }
+
+        QLIST_REMOVE(reg_group, entries);
+        g_free(reg_group);
+    }
+}
-- 
Anthony PERARD


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

From xen-devel-bounces@lists.xensource.com Mon Nov 28 15:53:25 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 28 Nov 2011 15:53:25 +0000
Received: from localhost ([127.0.0.1] helo=lists.xen.org)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RV3W0-0005WP-7R; Mon, 28 Nov 2011 15:53:08 +0000
Received: from mail182.messagelabs.com ([85.158.139.83])
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <carsten@schiers.de>) id 1RV3Vx-0005W4-Tn
	for xen-devel@lists.xensource.com; Mon, 28 Nov 2011 15:53:06 +0000
X-Env-Sender: carsten@schiers.de
X-Msg-Ref: server-2.tower-182.messagelabs.com!1322495545!4996437!1
X-Originating-IP: [194.117.254.36]
X-SpamReason: No, hits=0.6 required=7.0 tests=FROM_EXCESS_QP,HTML_90_100,
	HTML_MESSAGE
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 30102 invoked from network); 28 Nov 2011 15:52:28 -0000
Received: from www.zeus06.de (HELO mail.zeus06.de) (194.117.254.36)
	by server-2.tower-182.messagelabs.com with DHE-RSA-AES256-SHA encrypted
	SMTP; 28 Nov 2011 15:52:28 -0000
DKIM-Signature: v=1; a=rsa-sha256; c=simple; d=mail.zeus06.de; h=subject
	:from:to:cc:date:mime-version:content-type:in-reply-to
	:references:message-id; s=beta; bh=E3ljJkY1nh6a1ekrDc6TFJ60ymTpH
	NVrjgfRw2789OE=; b=UpEHSBzzDUsgz60cY6cJ1ku1StCilIQXm6/PEJQ3g/lfF
	IUv7uvineNkOxxw/C/803urhp0ypeIUNDQvvLukGNjDEsyrd42h7D/ZPJJLzhQc/
	t/Cu8VObPs7a/yoMmHUKOZxjcuwlb8qZRMrRJxQR7dtC3Sq+6mB5CPW1M7XMM0=
Received: (qmail 8419 invoked from network); 28 Nov 2011 16:52:24 +0100
Received: from unknown (HELO uhura.zz) (l3s6271p1@84.46.8.102)
	by mail.zeus06.de with ESMTPA; 28 Nov 2011 16:52:24 +0100
Received: from localhost (localhost [127.0.0.1])
	by uhura.zz (Postfix) with ESMTP id 4A1922C51B;
	Mon, 28 Nov 2011 16:52:24 +0100 (CET)
X-Virus-Scanned: Debian amavisd-new at schiers.de
Received: from uhura.zz ([127.0.0.1])
	by localhost (uhura.space.zz [127.0.0.1]) (amavisd-new, port 10024)
	with LMTP id MOxy+90bRDZu; Mon, 28 Nov 2011 16:52:17 +0100 (CET)
Received: from uhura.space.zz (localhost [127.0.0.1])
	by uhura.zz (Postfix) with ESMTP id 99DAD2C51A;
	Mon, 28 Nov 2011 16:52:17 +0100 (CET)
From: =?utf-8?Q?Carsten_Schiers?= <carsten@schiers.de>
To: =?utf-8?Q?lersek=40redhat=2Ecom?= <lersek@redhat.com>, 
	=?utf-8?Q?zhenzhong=2Eduan=40oracle=2Ecom?= <zhenzhong.duan@oracle.com>,
	=?utf-8?Q?Konrad_Rzeszutek_Wilk?= <konrad@darnok.org>
Date: Mon, 28 Nov 2011 16:52:17 +0100
Mime-Version: 1.0
In-Reply-To: <20111128152829.GC9655@andromeda.dapyr.net>
References: <20111128152829.GC9655@andromeda.dapyr.net>
X-Priority: 3 (Normal)
X-Mailer: Zarafa 7.0.2-29470
Message-Id: <zarafa.4ed3ae31.27d6.75459bdc74d06555@uhura.space.zz>
Cc: =?utf-8?Q?xen-devel?= <xen-devel@lists.xensource.com>,
	=?utf-8?Q?konrad=2Ewilk?= <konrad.wilk@oracle.com>
Subject: Re: [Xen-devel] Load increase after memory upgrade (part2)
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.13
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/options/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Content-Type: multipart/mixed; boundary="===============7373466658977440381=="
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com

This is a multi-part message in MIME format. Your mail reader does not
understand MIME message format.
--===============7373466658977440381==
Content-Type: multipart/alternative; 
 boundary="=_NUWQF-8k01W10DsG1N5+EZa3ojZPE3HDoZ4sFFhq0eeh0y-I"

This is a multi-part message in MIME format. Your mail reader does not
understand MIME message format.
--=_NUWQF-8k01W10DsG1N5+EZa3ojZPE3HDoZ4sFFhq0eeh0y-I
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hi,=0D=0A=0D=0A=C2=A0=0D=0Alet me try to explain a bit more. Here you see=
 the output of my xentop munin graph for a=0D=0A=0D=0Aweek. Only take a l=
ook at the bluish buckle. Notice the small step in front=3F So it's the C=
PU=0D=0A=0D=0Apermille used by the DomU that owns the cards. The small bu=
ckle is when I only put in=20=0D=0A=0D=0Aone PCI card. Afterwards it's co=
nstantly noticable higher load. See that Dom0 (green) is=20=0D=0A=0D=0Ano=
t impacted. I am back to the Xenified kernel, as you can see.=0D=0A=0D=0A=
=C2=A0=0D=0A=0D=0A=C2=A0=0D=0AIn the next picture you see the output of x=
enpm visualized. So this might be an indicator that=0D=0A=0D=0Arealy some=
thing happens. It's only the core that I dedicated to that DomU. I have a=
 three-core=0D=0A=0D=0AAMD CPU by the way:=0D=0A=0D=0A=C2=A0=0D=0A=0D=0A=C2=
=A0=0D=0AIn CPU usage of the Dom0, there is nothing to see:=0D=0A=0D=0A=C2=
=A0=0D=0A=0D=0A=C2=A0=0D=0AIn CPU usage of the DomU, there is also not mu=
ch to see, eventually a very slight change of=0D=0A=0D=0Amix:=0D=0A=0D=0A=
=C2=A0=0D=0A=0D=0A=C2=A0=0D=0AThere is a slight increase in sleaping jobs=
 at the time slot in question, I guess nothing we ca=0D=0A=0D=0Adirectly =
map to the issue:=0D=0A=0D=0A=C2=A0=0D=0A=0D=0A=C2=A0=0D=0AIf you need ot=
her charts, I can try to produce them.=20=0D=0A=0D=0A=C2=A0=0D=0ABR,=0D=0A=
Carsten.=0D=0A=0D=0A=C2=A0=0D=0A-----Urspr=C3=BCngliche Nachricht-----=0D=
=0AAn:Carsten Schiers <carsten@schiers.de>; zhenzhong.duan@oracle.com; le=
rsek@redhat.com;=20=0D=0ACC:xen-devel <xen-devel@lists.xensource.com>; ko=
nrad.wilk <konrad.wilk@oracle.com>;=20=0D=0AVon:Konrad Rzeszutek Wilk <ko=
nrad@darnok.org>=0D=0AGesendet:Mo 28.11.2011 16:33=0D=0ABetreff:Re: [Xen-=
devel] Load increase after memory upgrade (part2)=0D=0AOn Fri, Nov 25, 20=
11 at 11:11:55PM +0100, Carsten Schiers wrote:=0D=0A> I got the values in=
 DomU. I will have=0D=0A>=20=0D=0A> =C2=A0 - aprox. 5% load in DomU with =
2.6.34 Xenified Kernel=0D=0A> =C2=A0 - aprox. 15% load in DomU with 2.6.3=
2.46 Jeremy or 3.1.2 Kernel with one card attached=0D=0A> =C2=A0 - aprox.=
 30% load in DomU with 2.6.32.46 Jeremy or 3.1.2 Kernel with two cards at=
tached=0D=0A=0D=0AHA!=0D=0A=0D=0AI just wonder if the issue is that the r=
eporting of CPU spent is wrong.=0D=0ALaszlo Ersek and Zhenzhong Duan have=
 both reported a bug in the pvops=0D=0Acode when it came to account of CP=
U time.=0D=0A=0D=0A>=20=0D=0A> I looked through my old mails from you and=
 you explained already the necessity of double=0D=0A> bounce buffering (P=
CI->below 4GB->above 4GB). What I don't understand is: why does the=0D=0A=
> Xenified kernel not have this kind of issue=3F=0D=0A=0D=0AThat is a puz=
zle. It should not. The code is very much the same - both=0D=0Ause the ge=
neric SWIOTLB which has not changed for years.=0D=0A>=20=0D=0A> The drive=
r in question is nearly identical between the two kernel versions. It is =
in=0D=0A> Drivers/media/dvb/ttpci by the way and when I understood the co=
de right, the allo in=20=0D=0A> question is:=0D=0A>=20=0D=0A> =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 /* allocate and init buffers */=0D=0A> =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 av7110->debi_virt =3D pci_alloc_consistent(pdev, 8192, &av7110->d=
ebi_bus);=0D=0A=0D=0AGood. So it allocates it during init and uses it.=0D=
=0A> =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!av7110->debi_virt)=0D=0A> =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto err_saa71466_vfree_4;=0D=
=0A>=20=0D=0A> isn't it=3F I think the cards are constantly transferring =
the stream received through DMA.=20=0D=0A=0D=0AYeah, and that memory is s=
et aside for the life of the driver. So there=0D=0Ashould be no bounce bu=
ffering happening (as it allocated the memory=0D=0Abelow the 4GB mark).=0D=
=0A>=20=0D=0A> I have set dom0_mem=3D512M by the way, shall I change that=
 in some way=3F=0D=0A=0D=0ADoes the reporting (CPU usage of DomU) change =
in any way with that=3F=0D=0A>=20=0D=0A> I can try out some things, if yo=
u want me to. But I have no idea what to do and where to=0D=0A> start, so=
 I rely on your help...=0D=0A>=20=0D=0A> Carsten.=0D=0A>=20=0D=0A> -----U=
rspr=3Fngliche Nachricht-----=0D=0A> Von: xen-devel-bounces@lists.xensour=
ce.com [mailto:xen-devel-bounces@lists.xensource.com] Im Auftrag von Konr=
ad Rzeszutek Wilk=0D=0A> Gesendet: Freitag, 25. November 2011 19:43=0D=0A=
> An: Carsten Schiers=0D=0A> Cc: xen-devel; konrad.wilk=0D=0A> Betreff: R=
e: [Xen-devel] Load increase after memory upgrade (part2)=0D=0A>=20=0D=0A=
> On Thu, Nov 24, 2011 at 01:28:44PM +0100, Carsten Schiers wrote:=0D=0A>=
 > Hello again, I would like to come back to that thing...sorry that I di=
d not have the time up to now.=0D=0A> >=20=0D=0A> > =3F=3F=0D=0A> > We (n=
ow) speak about=0D=0A> >=20=0D=0A> > =3F=3F=0D=0A> > *Xen 4.1.2=0D=0A> > =
*Dom0 is Jeremy's 2.6.32.46 64 bit=0D=0A> > *DomU in question is now 3.1.=
2 64 bit=0D=0A> > *Same thing if DomU is also 2.6.32.46=0D=0A> > *DomU ow=
ns two PCI cards (DVB-C) that o DMA=0D=0A> > *Machine has 8GB, Dom0 pinne=
d at 512MB=0D=0A> >=20=0D=0A> > =3F=3F=0D=0A> > As compared to 2.6.34 Ker=
nel with backported patches, the load on the DomU is at least twice as hi=
gh. It=0D=0A> >=20=0D=0A> > will be "close to normal" if I reduce the mem=
ory used to 4GB.=0D=0A>=20=0D=0A> That is in the dom0 or just in general =
on the machine=3F=0D=0A> >=20=0D=0A> > =3F=3F=0D=0A> > As you can see fro=
m the attachment, you once had an idea. So should we try to find somethin=
g...=3F=0D=0A>=20=0D=0A> I think that was to instrument swiotlb to give a=
n idea of how=0D=0A> often it is called and basically have a matrix of it=
s load. And=0D=0A> from there figure out if the issue is that:=0D=0A>=20=0D=
=0A> =C2=A01). The drivers allocoate/bounce/deallocate buffers on every i=
nterrupt=0D=0A> =C2=A0 =C2=A0 (bad, driver should be using some form of d=
ma pool and most of the=0D=0A> =C2=A0 =C2=A0 ivtv do that)=0D=0A>=20=0D=0A=
> =C2=A02). The buffers allocated to the drivers are above the 4GB and we=
 end=0D=0A> =C2=A0 =C2=A0 up bouncing it needlessly. That can happen if t=
he dom0 has most of=0D=0A> =C2=A0 =C2=A0 the precious memory under 4GB. H=
owever, that is usually not the case=0D=0A> =C2=A0 =C2=A0 as the domain i=
susually allocated from the top of the memory. The=0D=0A> =C2=A0 =C2=A0 f=
ix for that was to set dom0_mem=3Dmax:XX. .. but with Dom0 kernels=0D=0A>=
 =C2=A0 =C2=A0 before 3.1, the parameter would be ignored, so you had to =
use=0D=0A> =C2=A0 =C2=A0 'mem=3DXX' on the Linux command line as well.=0D=
=0A>=20=0D=0A> =C2=A03). Where did you get the load values=3F Was it dom0=
=3F or domU=3F=0D=0A>=20=0D=0A>=20=0D=0A>=20=0D=0A> >=20=0D=0A> > =3F=3F=0D=
=0A> > Carsten.=0D=0A> > =3F=3F=0D=0A> > -----Urspr=3F=3Fngliche Nachrich=
t-----=0D=0A> > An:konrad.wilk <konrad.wilk@oracle.com>;=20=0D=0A> > CC:l=
inux <linux@eikelenboom.it>; xen-devel <xen-devel@lists.xensource.com>;=20=
=0D=0A> > Von:Carsten Schiers <carsten@schiers.de>=0D=0A> > Gesendet:Mi 2=
9.06.2011 23:17=0D=0A> > Betreff:AW: Re: Re: Re: AW: Re: [Xen-devel] AW: =
Load increase after memory upgrade=3F=0D=0A> > > Lets first do the c) exp=
eriment as that will likely explain your load average increase.=0D=0A> > =
=2E..=0D=0A> > > >c). If you want to see if the fault here lies in the bo=
unce buffer=20=0D=0A> > > being used more=0D=0A> > > >often in the DomU b=
/c you have 8GB of memory now and you end up using=20=0D=0A> > > more pag=
es=0D=0A> > > >past 4GB (in DomU), I can cook up a patch to figure this o=
ut. But an=20=0D=0A> > > easier way is=0D=0A> > > >to just do (on the Xen=
 hypervisor line): mem=3D4G and that will make=20=0D=0A> > > think you on=
ly have=0D=0A> > > >4GB of physical RAM. =3F=3FIf the load comes back to =
the normal "amount"=20=0D=0A> > > then the likely=0D=0A> > > >culprit is =
that and we can think on how to fix this.=0D=0A> >=20=0D=0A> > You are on=
 the right track. Load was going down to "normal" 10% when reducing=0D=0A=
> > Xen to 4GB by the parameter. Load seems to be still a little, little =
bit lower=0D=0A> > with Xenified Kernel (8-9%), but this is drastically l=
ower than the 20% we had=0D=0A> > before.=0D=0A>=20=0D=0A> > ____________=
___________________________________=0D=0A> > Xen-devel mailing list=0D=0A=
> > Xen-devel@lists.xensource.com=0D=0A> > http://lists.xensource.com/xen=
-devel=0D=0A>=20=0D=0A>=20=0D=0A> _______________________________________=
________=0D=0A> Xen-devel mailing list=0D=0A> Xen-devel@lists.xensource.c=
om=0D=0A> http://lists.xensource.com/xen-devel=0D=0A>=20=0D=0A=0D=0A_____=
__________________________________________=0D=0AXen-devel mailing list=0D=
=0AXen-devel@lists.xensource.com=0D=0Ahttp://lists.xensource.com/xen-deve=
l=0D=0A
--=_NUWQF-8k01W10DsG1N5+EZa3ojZPE3HDoZ4sFFhq0eeh0y-I
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: base64

PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEgVHJhbnNpdGlv
bmFsLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL2h0bWw0L2xvb3NlLmR0ZCI+PGh0bWw+
CjxoZWFkPgogIDxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29udGVudD0iWmFyYWZhIFdlYkFj
Y2VzcyB2Ny4wLjItMjk0NzAiPgogIDxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4KICA8dGl0bGU+QVc6IFtYZW4t
ZGV2ZWxdIExvYWQgaW5jcmVhc2UgYWZ0ZXIgbWVtb3J5IHVwZ3JhZGUgKHBhcnQyKTwvdGl0
bGU+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICAgYm9keQ0KICAgICAgew0KICAg
ICAgICBmb250LWZhbWlseTogQXJpYWwsIFZlcmRhbmEsIFNhbnMtU2VyaWYgISBpbXBvcnRh
bnQ7DQogICAgICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgICAgICAgcGFkZGluZzogNXB4IDVw
eCA1cHggNXB4Ow0KICAgICAgICBtYXJnaW46IDBweDsNCiAgICAgICAgYm9yZGVyLXN0eWxl
OiBub25lOw0KICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOw0KICAgICAgfQ0K
DQogICAgICBwLCB1bCwgbGkNCiAgICAgIHsNCiAgICAgICAgbWFyZ2luLXRvcDogMHB4Ow0K
ICAgICAgICBtYXJnaW4tYm90dG9tOiAwcHg7DQogICAgICB9DQogIDwvc3R5bGU+CjwvaGVh
ZD4KPGJvZHk+CjxwPkhpLDwvcD48cD4mbmJzcDs8L3A+PHA+bGV0IG1lIHRyeSB0byBleHBs
YWluIGEgYml0IG1vcmUuIEhlcmUgeW91IHNlZSB0aGUgb3V0cHV0IG9mIG15IHhlbnRvcCBt
dW5pbiBncmFwaCBmb3IgYTwvcD48cD53ZWVrLiBPbmx5IHRha2UgYSBsb29rIGF0IHRoZSBi
bHVpc2ggYnVja2xlLiBOb3RpY2UgdGhlIHNtYWxsIHN0ZXAgaW4gZnJvbnQ/IFNvIGl0JiMz
OTtzIHRoZSBDUFU8L3A+PHA+cGVybWlsbGUgdXNlZCBieSB0aGUgRG9tVSB0aGF0IG93bnMg
dGhlIGNhcmRzLiBUaGUgc21hbGwgYnVja2xlIGlzIHdoZW4gSSBvbmx5IHB1dCBpbiA8L3A+
PHA+b25lIFBDSSBjYXJkLiBBZnRlcndhcmRzIGl0JiMzOTtzIGNvbnN0YW50bHkgbm90aWNh
YmxlIGhpZ2hlciBsb2FkLiBTZWUgdGhhdCBEb20wIChncmVlbikgaXMgPC9wPjxwPm5vdCBp
bXBhY3RlZC4gSSBhbSBiYWNrIHRvIHRoZSBYZW5pZmllZCBrZXJuZWwsIGFzIHlvdSBjYW4g
c2VlLjwvcD48cD4mbmJzcDs8L3A+PHA+PGltZyBhbHQ9IiIgc3JjPSJkYXRhOmltYWdlL3Bu
ZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWZFQUFBR0VDQUlBQUFDcHY0NVlB
QUFnQUVsRVFWUjRuTzI5ZjNSVTFiMzN2OE1rRUFKbVFpQ1dZRG9RTVNRd2t5QWRpajhlOWZI
YmRhdFdYYWdGTHZXcXZiMjFwYmY0STRCV3k3SUw1MUdxVDRVU2JUQmxsaFhTYUJETVRFS0NY
TFdJSkNwM0dSMm9UUUVSRTJoUmhKbE15SS85ejEzcitlTjgvOWpKenM3WjU1elpjMmJPelBu
eGVhMVpzMmJPZk00NW43Tm5uL2U4WjgrWnowWi9CUUFBQUd4QloyY255bllPQUFBQVFCcm83
T3pjdVhQbnFLWmpBQUFBd01yczNMa1ROQjBBQU1BbWdLWURBQURZQjlCMEFBQUErd0NhRGdB
QVlDVmFPTmhYUWRNQlFCbUVVTFpUU0FJelpHdUdISnpEeU1nSVVYUFFkTUFPR0NjZmRNdjhn
N1JzMWlETW9LZG15TUVoREEwTmZmcnBwNkZRNlB6NTg2MnRyZXhMb09uTzRyNzc3dnZwVDMv
S0x2bVAvL2lQKysrL1A1VnRJb1FRUWprNU9aZGRkbGxOVGMzNjlldlBuajJiV3BwcFJsRnJF
a3AyaWdxVllZRXpnNTZhSVFjbmNQTGt5WTZPanE2dXJ0T25UN2UydG43NjZhZnNxNkRwemlJ
YWpTNWF0R2puenAzazZhdXZ2dXIxZW1PeFdDcmJwR2R5TkJyOTZLT1Bmdm5MWDVhV2xwNDRj
U0xWWE5NSGFMcHpjbkFDNzcvLy92bno1OVZlQlUxM0hFZVBIdjNXdDc1MTdOaXhZOGVPelo0
OW03enZRME5ER3pac21EVnIxdFNwVTFlc1dISGh3Z1VTakJCNjhjVVhQUjVQWGw1ZVRVM05r
U05IK0EzeVovS1RUejc1b3gvOWlEenU3Ky8vOTMvLzk4c3V1K3l5eXk3N3lVOSswdC9mVDll
cXE2dWJPM2Z1NU1tVEZ5NWMrSmUvL0dYSGpoM3o1ODhuTy9yNDQ0OUoyTi8vL3ZjZi9PQUgw
NlpObXpKbHl2ZS8vLzB6Wjg3SWRxb3ZRN29RTWZCYjVoL3c4WW9aYW14V28wRVNIb2dHQ0tG
bm4zMjJwS1Nrb0tEZy92dnZqOGZqR09QcnI3OSsxNjVkTk9ia3laT3paODltNWFDOHZQeVRU
ejRoajNmczJFRWVmUExKSitYbDVWaTlWMmowRnZMZ2d3OCttRE5uenU5Kzk3dWtEZ0ZJQzZE
cFR1UlBmL3FUMSt2MWVyMk5qWTFreVc5Kzg1dnZmZTk3cDA2ZHVuRGh3bjMzM2Zlem4vMk1M
RWNJclZpeDRvc3Z2b2hHbzA4OTlaVGY3K2UzeGl2bXlaTW52L1d0YjVISGp6NzY2SzIzM25y
bXpKbSt2cjUvK1pkL3FhMnRwV3N0WDc3ODg4OC9qMGFqVHovOTlQVHAwKys1NXg3NjlMdmYv
UzRKcTZxcWV1dXR0Mkt4MlBuejU5ZXVYYnQ2OVdyWlR2VmxpTlY5dXNoNGVuMTkvVzIzM1Nh
WW9leXBSb01rUEJBTkVFSmtzMmZPbkxuMTFsdlhyVnVITVc1cmE2dXNyQndlSGlZeFAvN3hq
NTk1NWhsMnJaLy8vT2QxZFhVWTQxT25UazJmUHAybzg3WnQyOWFzV1lQVmU0VkdiOEVZdDdT
MHpKbzFhOCtlUFVubEQ0Z0QxNzBBQ2l4WnNtVHAwcVgwcWNmak9YYnNHSG5jMTlkMytlV1hr
OGNJb1hQbnpwSEgwV2cwTnplWDN4UXZlWmN1WGNyTHl5T1BTMHRMUC92c00vTDRyMy85NjV3
NWMraGEvL3puUCttV1pVOFZkeFNOUm1mTm1pWGJxYjRNY1FxYTN0SFJzWGp4WW1wT0UyWW9l
NnJSSUFrUFJBT0UwTi8rOWpmeStMUFBQcnZpaWl2SVk3L2YvK3FycjlLRjBXaVVYV3Z2M3Iw
clZxekFHRC96ekRPelpzM2F2bjA3eHZpSFAvemhtMisraWRWN2hVWnYrZjN2ZjE5YVd0cloy
WmxVOG9BTzRMb1hZSndkTzNaY2ZmWFZWMTk5OVovKzlDZXlKRGMzbHgwdXlNbkpJY3ZWaEVs
N0lmbU9UeDY3WEs2aG9TSHllSEJ3a0VxVjlwYnAwL2ZlZSsrNjY2NHJLQ2hRUzB3a3cwbVRK
dEVjQ0VORFE1TW1UZExlZ3VJdVB2MzAwL256NTdPL0ZpVE1VUFpVWDRQUWhleDRqdXdseGMz
dTJiT25vcUppYUdobzFhcFZXN1pza2ExMThlTEZiMy83MnhoanI5Y2JDb1d1dWVZYWpQRzN2
LzF0SXYxcXZVS2p0OHliTisreHh4N2owd1BTQzF6M0Fveno2YWVmbHBhVy92M3ZmKy9wNlNr
dExUMTY5Q2pHdUt5czdJc3Z2dUNEOVduNmswOCtlZSs5OTVMSHBhV2wxRC8rOWE5L0xTMHRG
ZGt5ZlRwbnpwekd4c2J6NTgrUGpJeDg4ODAzQ1UyMFlvWWVqK2UvLy91LzJTVWZmZlNSeCtQ
UjNnTC80TXlaTXhVVkZRY1BIbVRqRTJZb2U2cXZRUkxDK3ZTLy9lMXYxUDZQakl4NHZkN2Ey
bHFQeHpNd01NQ3ZlT09OTi83NXozOG1RejErdjMvUG5qMDMzWFFUZVVtdFYyajBsbE9uVGwx
NTVaV2JOMjlPS25rZ0tlQzZGMkNjYURTNmNPSENOOTU0Z3p4OS9mWFh5WFV2VHovOTlLMjMz
dHJUMHpNNE9Qanh4eCtUNytNNFNVMG4xNzJzWGJ1V3ZlN2w0WWNmcHVPODMvLys5eDk1NUJH
UkxkT25NMmJNMkxOblR6d2UvL3ZmLzc1aXhRcDltdjUvL3MvL1diSmt5ZnZ2dngrUHgrUHgr
S0ZEaHhZdlhreDF4KzEyMDVFRXhTM1RCOS85N25mcEQ0a1V0UXpWTnF1dlFSS0NFUHJCRDM1
dzl1elpzMmZQM25iYmJYU1lIbVBjMk5pSUVIcjU1WmNWVjN6bW1XZm16SmxETFB3TEw3eHd4
UlZYUFB2c3MrUWx0VjZoM1Z0T256NWRVVkVSQ0FTU3loOFFCNjU3QWNhNTc3NzdxSWdRZnZu
TFg5NTMzMzNEdzhPQlFJQmNkTEZvMFNMNjI2bjRnRUJPVHM2MGFkT3FxNnZYclZ0SHIwN0JH
TWRpc1FjZWVHRDY5T25UcDA5LzRJRUg2SFdUZ3ByK3hodHZ6SnMzeitWeWZmdmIzOTZ5Wllz
K1RSOFpHZG15Wll2WDY1MHlaY3FVS1ZPOFh1L3ZmLzk3K3VxbVRadW1UWnVtc1dYMkFZdDJo
bXFiMWRjZ0NVSE1kUy8zM1hjZnZad0dZL3phYTYvTm56OS9jSEJRY2NValI0N2s1dWFTdnhT
Y09YTW1OemVYZnFkUjZ4VUplMHR2YjI5bFplVnZmdk9icEE0QlNBdWc2UUJnYzI2Ly9YYjZq
d1RBQnNCMUx3RGdVSWFIaCt2cjY2dXFxdWpsaklBTmtJazRhRG9BT0FXRWtNZmpnU3NMYlVa
cmErdWxTNWZJNDB1WExzRjFMd0FBQUJhbXM3UHprMDgrR1J3Y0hCd2MvT1NUVDdxNnV0aFhR
ZE1CQUFDc1JIOS8vK0hEaDhQaGNEZ2M3dXpzWkg4UHg2RHBBQUFBbGdiRzB3RUFBT3dEYURv
QUFJQ0ZjZEMxakQwSER2UWNPSkR0TEFBQUFES0hiVFY5TUI3ZmR0MTEyNjY3YmpBZXozWXVB
QUFBR2NLMm12NlgzLzB1NFBFRVBKNi9RQ1YrQUFDY2lrMDAvZnlwVTVzcktvaW1iNjZvT0gv
cVZMWXpBZ0FBTUlSWUxOYloyVW12WlpUTlBaa2RUVzlxYXFxcXFzckx5NnV1cnU3bzZNQVlm
L0hGRjlkZWUrM2t5Wk92dmZaYVVzWlRaTW40Qmg5NGdBZzZ1VFU5OEVER2pnVUFBQ0NUSER4
NDhOaXhZNWN1WGJwMDZkTFJvMGRseForem8rbjMzSE5QZDNkM2YzLy85dTNiWjg2Y2lURmV1
WExsaGcwYit2djdOMnpZc0dyVktzRWxNcDU0NGdueTRQVHAweUpwWElwRVJNSkV0aWE0UjVF
d3lFbzhETElTRHpOblZsZ3NzVFR1MFp4WkpVVW9GS0lGZklhSGgwT2hFUHRxbHNkZVRwdzRR
YVltbURselpsOWZIOGE0cjYrUHFMeklFaGxVMHovODhFT1J2WCt6ZmJ0SW1NaldCUGNvRWda
WmlZZEJWdUpoNXN3S2l5V1d4ajJhTTZ1a01LTlBKL1QyOWk1WnNtVHYzcjBZNDBtVEpwRlBu
cUdoSVpmTEpiaUVNdlRQZjM3ejBrdVAvL3puK1BCaFNaSUdEeDZVSklrODFyai9mN0ZZd2hq
QnJRbnU4WC8rNTM4Z0s4Z0tzbUx2aHpvNk1ybEg4MlQxLytMeGIxNTZhYUM3TzFubGpFYWpw
aHRQeHhoM2RuWjZQSjVYWG5tRlBDMHVMcFo1Y0pFbE1wNTQ0Z2xKa2lSSjZ1M3RsUVRBWFYw
aVlTSmJFOXlqU0Joa0pSNEdXWW1IbVRNclNTeXhOTzdSVkZrWklhM1owZlQ2K3ZxU2twSjkr
L2JSSlN0V3JLQmo1V1FxTEpFbE1xaW1Bd0FBbUI5OSttbkc2MTVrYzRCZHZIang4ODgvWDda
c1dWNWUzalhYWEhQcTFDbU1zY2dTR2VEVGRjUUloa0ZXNG1HUVZWSmg0Tk9UeGJ6ajZXa0hm
RG9BQUJaQ245Q1orcnFYOUFJK1hVZU1ZQmhrSlI0R1dTVVZCajQ5V2NDbkF3QUFtQkY5UW1m
UzYxNk1BSHk2amhqQk1NaEtQQXl5U2lvTWZIcDZzYWVtQXdBQW1COTlRdWVJK3VtWExsMDZj
ZUxFVDMvNlUwbVMrdnI2ZW50NysvcjZ5R09OK3hNZEhRbGpCTGNtdU1jalI0NUFWcEFWWk1Y
ZTQ2NnVUTzdSUEZsOThjVVhKMDZjMEZFNVFDYmlNbXlpNlFUdzZRQUFXQWg5UXVkRVRZZnhk
UEVZd1RESVNqd01za29xRE1iVGs4V0ptZzRBQUdCK2pKQkJlMm82K0hUeEdNRXd5RW84RExK
S0tneDhlbnF4cDZZREFBQ1lIeDBxOTlaYmIzVjNkL2YxOVEwTkRTa0daTG5lQzEzUzNOeGNY
bDd1Y3JubXpadlgzTnlNazV6bmlBQStYVWVNWUZqR3NrSjF5SVJaSlJVR1dTVVZCajQ5S2I3
NTVwdWVucDVEaHc2MXRyWWVPblNvcDZmbm0yKytZUU95NmROWlRTOHNMQXlIdy9GNFBCUUt1
ZDF1ckhlZUk1RW1Cc3dNMVhRQXNEMnA2T2ZnNEdCZlgxOTNkL2RiYjczRkxqZUxwdnQ4dm5B
NFBEQXdFQXFGYW1wcXNONTVqa2hMZ1U4WGp4RU15MHhXcUE0RkFnR3paWlZzR0dTVlZCajQ5
UFJpRmswL2ZQaHdZV0VoUXFpd3NQRHc0Y000dFhtTzRONmk5NmdPZFpSdE1rTW1jQS8zUnQv
cm51ZElHN05vK3Z6NTgrbll5MVZYWFlWaG5xTjBiTXB5V2FFNkZFUkJzMldWYkJoa2xWUVkr
UFQwWWhaTkx5b3FvbU12TTJiTXdERFBrU01KQkFMK01VMEhBTnVURmlFMVJiMFgyVHhIR09P
bXBpYVB4K055dWViT25mdjY2NjlqbU9jb0hadXlYRlpCRlBTRFQwOHlSakRNbkZsSjROTlR4
aFNhYmhEZzA2MU9FQVdsQ0Z6M0FqZ0ZmVUxuaUxxTUJQRHBPbUlFd3pLVGxSOEZwUUJjbjU1
Y2pHQ1lPYk9Td0tlbmpDTTBIYkFvcktackE1ZXhBellnTGJybkNFMEhueTRlSXhobU5wOU9M
bzl4Y2xzbEcyYk9yQ1R3NmVuR0pwb3VteE1EN3ExNnY5a3JCWkJJNUYzZWh1eG5DL2R3bjhL
OTdqa3hZckVZekVlcWpEbWRpNk96Q2lCQm4rNEhuNTVrbURtemtzQ25KOC9CZ3dlUEhUdDI2
ZEtsUzVjdUhUMTY5T0RCZyt5cjl0UjB3S293bXE0TlhNWU8yQUI5UWhjS2hjZy82akhHdzhQ
RG9WQ0lmZFdlbWc0K1hUeEdNQ3hEL3lOZHMxLzB1cGNBeWxoV3lZWkJWa21GZ1U5UEZ2RHBn
R1ZnTlQwQmdtRUFZR0wwQ1YwMEdvWHhkSlVHTmFWemNYSlc0Tk4xeEFpR21UTXJDWHg2dWpI
TG5CakR3OE1iTjI0c0xTM055Y2toeTFPWkV3T3dLT0RUQVVlaFR6L04rejlTVnRNM2JkcTBZ
TUdDN3U3dWtaRVJzaVNWT1RIQXA0dkhDSWFCVHhjUGc2eVNDZ09mbml4RXhLbVVtMVRUUFI2
UDdOZmJWT2JFQUN3SytIVEFVZWhUem5BNGZPSENoVkFvOU0wMzMzenp6VGR0Ylczc3EyYlJk
SmZMOWRCREQwMmRPdFhqOGV6WnN3ZW5OaWRHMzk2OWtrQk5ldHpWSlZLOVhtUnJnbnZzN2Uy
RnJEUmkwSnI5K05FeW9hd0N5T0Z0Wlkrc0pFbnEvK01mTTdsSDgyU2xlMDZNVHo3NXBMVzE5
ZVRKazIrOTlWWTRIRDUrL0RqN3FsazBmZWJNbWFGUWlNeUpNV3ZXTEp6YW5CaUFSUUdmRGpn
S0kzVFZMSnErYXRXcVVDaEU1c1FvS1NuQnFjMkpBZVBwNGpHQ1lUQ2VMaDRHV1NVVkJ1UHB5
V0xHMzBqNU9URk9uejU5d3cwMzVPWGxsWmVYazRIMVZPYkVBQ3dLK0hUQVVSaWhybkI5ZW1M
QVQwbmcwNU1KZzZ5U0NnT2ZubDdzcWVtQVJRR2ZEamdLSTJUUW5wb09QbDA4UmpBTWZMcDRH
R1NWVkJqNDlQUmlUMDBITEFyNGRIRmdwaWNib0Uvb29INjZlb09hMHJrNE9Tdnc2ZUl4Z1VE
QWhGbnBDQU9mbml5T3FNc0k4eHpaNDk2N1lZL2dQRWQ5bTcxWnp6Ykw5MTdIdDRERjczWFBj
d1QxMDFVeHAzTnhjbGJnMDVPSVFVZ29MTU5aSlI4R1BqMVpIT0hUQ1RDZWJuVmdQRDBKa09O
YndQcm9FenFvbjY3ZW9LWjBMazdPQ254NkVqSGcwM1dGbVNvckkyVFFucG9PV0JUdzZVa0FQ
dDM2NkJNNk05WUdNQWp3NlRwaUJNUEFwNHVIZ1U5UEtneDhlcktZc1g0NlA4OFJZZVBHalhR
aHpIUGtRRmhOUjNWSTZ4SnM4T25nMDYyUFB2MDBvNllUWkpyZTFkVTFlL1pzdWhEbU9VcDlV
NWJMaXRYMGQzdDlhcHFPNmhENGRQRHArc0pNbFpVKzViU0dwdmYzOTN1OTNnTUhEdENGTU0r
UkEyRTEzWStDUVJSVURodlRkRWNEUHQzNnBFVklUYXJwYTlldWZmNzU1OW1GTU0rUkE3Tmk1
em02eTlld3ZteVRZbVRQNFRLWTUwaEN5SXhaSmRsV0VzeHpsUHc4UnpKTXF1azVPVG15aXVv
d3o1RURrZmwwdjRwUDk2TWcrSFR3NlRaQW4zS2E5N29YL2pkU2RpSE1jNVQ2cGl5WDFZVHJY
amI3Wk1KTmg5ZXBwanU1clNRMC9odXlpYkpLUGd6RzAxUEVGSnJPejNQRXZrUWV3RHhIRG1U
Qzlla0IrYUE1SFY0SG55NUpFelFkc0NocGtWTlRhTHBCZ0UvWEVTTVlaZ2FmUHY2VGFRQkpB
WVRxa0pQYlNrS0lEcitZS0t2a3c4Q25weGQ3YWpwZ1VSUjlPcjFRM1Q5UjA5V3VpbkVLaktZ
REZrV2YwSmwzUEQzdGdFL1hFU01ZbGtXZnJxYnBmaFIwY2x1QlQ5Y1hacXFzakpCQmUybzZZ
RkVVZlhwdzdFSjFYdE96azZWSkFKOXVmZlFKblNOOHVteE9qTjdlWHBHYTlDYzZPaExHQ0c1
TmNJOUhqaHlCckRSaTJEa3hqangvTzNuc1I4Rzd2QTJvRHQzbGJSaU5ES0MrelY0L0NqcTVy
ZnE4WGdraDAyV1ZaRnYxOWZYaHJpN2RlMFIxS05rOUNtYTFmR09aMGUyZ2UwNE1qUEhBd01B
Nzc3elQydHA2OXV4WjJVczIwWFFDK0hTcm8ralR5WVhxUWZaYUYvS1N3eTk5QVo4dUdYbVJm
a2JhVnAvUUVVRS9kdXpZVjE5OXRXL2Z2dlBuejdPdjJsUFQ2UUNXOXNWZTVoeGhkSEpXaXVQ
cDVNcEZ2NUttTzdtdFlEeGRrdVRLbTg3eDlMS3lkRzBxN2VQcGI3LzlOcFhyTDcvOHNxT2pn
MzNWbnBvK0RoZ1pTNkY4ZlRvZFBRZWZ6Z0krWFVyL0NUNWVEZFRFUGwybTFjZVBIMmVmSnRE
MGd3Y1BWbFJVNU9Ua1lJeFhyMTdkMk5pb0w0bk1vSERkaStZYlkwN240dVNzbEs5UG42anBv
d1c4d0tlRFQ1Y004T2tJa1Q5em1kbW5wL1FiNlZWWFhkWFcxa2IrMi9uNTU1L1BuVHRYWHhL
WkFYeTYxZEh3NmZScElCQUFueTVKNCtxVDdUeXlTdHBQY0lRa2hBS0JnSmw5ZWtxMWR2UHk4
dUx4T05IMGMrZk9GUlFVNkV0Q0JsOFZvS21wcWFxcUtpOHZyN3E2bWd3UHBUSW5ocS9PTi80
T2FUU29LWjJMazdOQ2EvYWpOZnRId3liNmRQYlNSdkRwa2pUbTB4RXlWMWJKaDVuUXAwdkk3
RDRkNjliMG0yKytlY2VPSFFpaDA2ZFByMTY5ZXZueTVmcVNVSVRWOUh2dXVhZTd1N3UvdjMv
Nzl1Mms1bUlxYzJLTXY5UGcweTBGcSttS1BoM1ZqUTNDZ0U5bk5OMjVHT1BUTTlhdytwUXpK
VTAvZmZyMG5YZmVXVkJRVUZCUXNIejU4bi84NHgvNmtsQkVzUzdqaVJNblBCNFBUbTFPakY2
ZmIvUzNEdkRwYWRxVVNYeTZUTk9kM0ZiZzB5WEpvVDVkRzNQVjJ1M3Q3VjJ5Wk1uZXZYdHhh
bk5pNExJeVZJZnVmcktNblRjQTdzMS9qOWJzdi91QmJhTkxBbWgwZm94SHkwWWZCMUJIMlNZ
L0NvNHZNVUhPV2JzbnV1UHdIbDZXN2o1QVd6WHRXK2J1ZGMrSllkNy9rY28wdmJPejArUHh2
UExLSytScEtuTmk5UHA4SWwrZ3pPbGNuSnhWUXA4K09sRUcrSFFKZkxva1NZNzI2U01qSTdK
QkdJS3lwaU4xVWtsQ0JydTErdnI2a3BLU2ZmdjIwU1dwekltUjRVRXhJRjBrSEUrZk1KZ080
K25RdzQwZlR6ZjB5aUxkNGprME5QVHBwNStHUXFIejU4KzN0cmF5TDVsbFRnelprb3NYTDZZ
eUp3YjRkUEVZd1REeitIVDJxWlBiQ255NkpHWEVwNnRyU0xaOCtzbVRKenM2T3JxNnVrNmZQ
dDNhMnZycHA1K3lyOXIwZjZUZzA2MEorUFFrZ0I0dVplUzZsNG03U0s5dDF5ZDA3Ny8vdnF6
R0MwczJ4MTdTRHZoMEhUR0NZU2J4NmJLYms5c0tmTG9rWmNPbk0wL2h1aGZEQVo5dWRYaWZ6
bFlDVUxnNUdlamhVaFo4ZW5yM2FJUU0ybFBUd2FlTHh3aUdaY3VuYTJ1Nms5c0tmTG9rWmMy
bmt4RVlpL2wweFo4dXJUTDJBajdkb2xCTnAxSWVsQTJnZzArblFBK1hzdWZUMDdSZkkyVFFK
ajVkUHMrUnp6YzZDNHpYSzFsdDVoY25aK1hkc0FldDJVL21yeUh6SE4zbGJaQUNxRyt6Vi9I
ZXlXM0Y5bkFUWlpWa1cvV2xOcytSaE5JOXo5RllxK0t5c3ZFbC9CNFJTcjBkVXBublNBT2Jh
RG9CZkxyVm9UNDlJcWxjNkFJK25RSTlYQUtmcmtBQ1RkKzllN2ZINDhuSnliSFcyQXVNcDR2
SENJWmxlRHc5aUlLajE3MUVZRHhkQlJoUGw3SjMzWXR3czJ1SEdTR0RDVFI5NXN5WnI3MzIy
dERRa0JIN1RqdmcwNjBPMWZRRTloeDh1Z1ErWFpLa1RQdjA4YktBMXZYcFJVVkYwV2pVaUIw
YkFmaDBIVEdDWVJuMjZYN3EwelZ2VG00cjhPbVNsSEdmanBEbGZmcFRUejIxY2VQRy92NStJ
L2FkZHNDbld4M3c2VWtBUFZ6SytIZzZHcHRieXJvK3ZibTVlY3FVS1dtL2xwSGZtc2lzUnVM
ekhJRlBGNDhSRE12MDlla0JCRDQ5UVF6NGRDbExQajJaWnRjT1M0dWN5a2lnNlNVbEpjM056
UWFOcDdPYUxqS3JVWEx6SEkzZG5ENWhvNlZnTlIxOGVnTEFwMHZaOGVscGJIWWpkRFdCcGhj
V0ZobzNuczVxdXNpc1Jrbk5jeVRTK3VaMExrN09Dbng2RWpIZzB5WHc2UXBrY3p5ZDFYU1JX
WTJTbXVkSXl1QjhKWENmcnZ2eGVZNll1WTIwN2syUWM5YnVZWjRqS1NQekhMRXRuRlpWMFQz
UGtUWUpORDFqYzJLSXpHcWtjNTRqOE9ucENBT2ZMaDRHUGoycE1QRHA2Y1VzYzllSnpHcWtj
NTRqaHc4NFdnb1lUMDhDNk40U2pLY3JrRURUYzNKeWpOZ3I3LzFGWmpYU09jOFIrUFIwaElG
UEZ3OERuNTVVR1BqMDlKSkEwK2ZNbVhQMjdGa2pkbXdFNE5PdER2aDBjWUlvQ04wNy9SZTIy
ZDZuUC8vODh3OCsrT0RGaXhlTjJIZmFBWit1STBZd0RIeTZlRmhtc21JMTNUeFo2UWhMMWFj
ekp6ajRkSnpkMzBqVER2aDBxd00rWFJ6dzZaSWsxL1MwYmRER1B0MWFnRS9YRVNNWUJqNWRQ
QXg4ZWxKaDROUFRpMDAwWFRZbmhrVG1DcUQzQW5YcjRkNE05M1JPREVsOUhvd0o5eWJJT1Z2
M0RkNEdLZEdzTC9hL1Qzc0w4THJCYmordHFwS2RPVEVPSGp4WVVWRkJybjVadlhwMVkyTmpl
bmVmWHNDbjY0Z1JEQU9mTGg0R1BqMnBNS3Y0OU5IU1hWYjM2VmRkZFZWYld4dTkzSER1M0xs
R0pKRXVZRHpkNnNCNHVqZ3duaTVKbVIxUE4wQlZqSkRCQkpxZWw1Y1hqOGVKcHA4N2Q2Nmdv
TUNJSk5JRitIUWRNWUpoNE5QRnc4Q25KeFZtRlovT2E3b2xmZnJOTjkrOFk4Y09oTkRwMDZk
WHIxNjlmUGx5STVKSUYrRFRyUTc0ZEhIQXAwdFM1bnk2Zk9ERnVqNzk5T25UZDk1NVowRkJR
VUZCd2ZMbHkvL3hqMzhZa1VTNkFKK3VJMFl3REh5NmVCajQ5S1RDVXZIcG80MlF6QjUxK25T
a29PbVc5T2tabzdtNXVieTgzT1Z5elpzM3I3bTVHYWMySjRaRmZib3pTNzJ6UncwK1had2dD
c29VellHa3Z3WFV4dE9WTkQxMWpOQlNzMmg2WVdGaE9CeU94K09oVU1qdGR1UFU1c1N3cWs5
SHlJeFpTWkprWkZacW1nNCtYVHVHMVhUelpLVWpESHg2ZWxIVjlQZmVlNitxcWlvM043ZXFx
dXI5OTk4M1l0OHNQcDh2SEE0UERBeUVRcUdhbWhxYzJwd1lGdlhwVmtvMWZZQlAxd2Y0ZE1s
SW54NUV3ZkVsa2kxOCtxSkZpMTU0NFlWb05QckNDeS80ZkQ0ajlzMXkrUERod3NKQ2hGQmhZ
ZUhodzRkeGFuTmk5RjE3clNSUXZSNTNkWWxVcisvYnV6Y3RNZmp3NGQ3ZTNnVDErRTJZbGNG
dGhlckc1eHhnNThUbzNleExPQ2VHMDlxS3ZRK2lZRWZaSnRKbnpKTlZzbTBsU1ZML0gvK29l
NCswQmNUM21QZ2NMQ3VURU9xcWVXUjhDYk9jVlpVVTJ5SFRjMks0WEs2QmdRR01jVHdlbHdt
b0VjeWZQNStPdlZ4MTFWVTR0VGt4d0tkYkNQRHArZ0NmTG9GUFYwSlYwOWx5WFJrbzNWVlVW
RVRIWG1iTW1JRlRteE1EeHRQVG1aVWtTVVptRlFnRTZHTVlUeGVQZ2ZGMHljang5UGF5cDhl
WFNMWVlUK2NyTWhwYWw3R3BxY25qOGJoY3JybHo1NzcrK3VzNHRUa3h3S2RiaUhGREJENDlH
Y0NuU3diNGROS3FvMjFMc0kxUHR5TGcwdzNKU3BJa0k3TUtvaUFkZmdHZkxoNERQbDB5d0tk
VFFiZWhUN2NpNE5PdGlGOUYwOEduYXdNK1hRS2Zyb1E5TlozNmRPMjMzSFRPeFpFK1hVM1R3
YWRyeDRCUGw4Q25LMkZQVFovdzQ3V0ZqSXlGVWswZmZoU2tQNU9DVHhkSGJpY2RDZmgwSG50
cU92ajBkR1lsU1pMQlBwMmVQK0RUeFdOWTZURlBWanJDd0tlbkY1dG91bXllbzRnME9oZko2
Rnd3V1orTlJYeU9sYXpua1BGNzc0WTlRUlNrajJHZUk4SDdCbTlERUFVYnZBMm96cm50RUVU
QjlKNDF0RlZwbnh6ZFBqdkRrYVhuT2JJVzFLYzMrQm9pRW9wSTROTXQ0RDNSbXYxKzhPbkp4
SkNmSDZpalJIWElERm5wRGdPZm5sN3NxZWtUQnNVc05FaHRvVlRUaDVxbXczaTZHakpOZDJh
M0ljQjRPbzhOTlIzVm9RWmZnMGlQTjUxekFaOE9QbDBnaHNnTjI4UE5rSlh1TVBEcDZjV0dt
azUrR3JXa2k3RlFxdWtEZkhxeThKcWU3WXl5aHRFK0hkV2hpQVErUFh0UVRRZWZuczZzSkVr
eTJLZExFYmcrUFlrWThPa1V3MzA2TGVZMUp1VmtqK0tYRzJtSEdTR0RadEgwNGVIaGpSczNs
cGFXNXVUa2tLb3krdWM1c3BwUEh5OU1hUHBValdCY3g4R25pd0UrbldMNGVMcW1wcWVPRVZw
cUZrM2Z0R25UZ2dVTHVydTdSMFpHeUJMOTh4eFp6YWZMTk4wa1dja3cxS2NyYWpyNGRMVVlj
cTBMK0hRSmZMb1NadEYwajhjVENvWFlKZnJuT2JLYVR4L1AwUHlwR2dENDlHU2hzbUtaSG00
WW1mSHBxQTZCVDA4YWw4djEwRU1QVFowNjFlUHg3Tm16QjZjeXp4RkMrNjc5VFJBRk84bzJC
VkhRQXZNYzBReWRPYzhSbmRzSTVqa1NpNkY5bS9ad00yU2xyNjJrbE9jNWlranBuT2VJdHVy
b1BFZGxaYU1hZ2hBdUs0dElpTXlzMUZHMktmVjJ5UFE4UnhsbTVzeVpvVkNJekhNMGE5WXNu
TW84UitEVExRWDQ5R1JodTdjMWVyaGhUTGlRUEgwYmxJK25NeVpkZnZWNmFoaWhwV2JSOUZX
clZvVkNJVExQVVVsSkNVNWxuaU9yamFmTE5OMHNXVTBFeHRQRnd6SXduaDVFUVQrTXAzT2Fi
dFI0dW9xbXczaTZGcWRQbjc3aGhodnk4dkxLeTh2SndMcitlWTdBcDFzSzhPbkp3bXQ2dGpQ
S0d1RFRlY3lpNldrQmZIbzZzNW9JK0hUeE1DZjRkRlNIMk1uQmRXOUtNREcxVGZuQnAzUFlV
OVBCcDFzSThPbkpRalhkbjZVZVBuNGRTTGJ4ajFVeFM5Y0d3YWViQ3pXZnJ2YVdtOFhsSVNU
Ujg4UThXVTBFZkRvZmxxMSt4V3Q2aHQvQnpaczNpMmg2NW56NldDWjZ1dC9FTjVIMTZlU1VI
TDk0Y2FLbUM1YkQxTTdLQ0JtMHA2YkxmSG9hUDhZTkFURUZKWnlIZFgxNnR2cFYxbjM2dUhY
Tk5tbG9BYVNzNmZRWTFUUTlMWWR2aEF6YVJOTW56SW5oOVRiNEdtaHRlNG5Vc0ZlcVNYK2lv
ME54dWV5K3Q3YzNMVEdTSkIwNWNrUmhPYW12UDVhbldiTEtWRnVOejRNeGNVNk1JOC9mTGlX
YUV5UHRXU1djWCtMSWtTTTBSbTArQ3FQZlFkSzM3L0kyK01kNmVJYmZ3UVpmZzhpOEVDSlo5
ZlgxNGE0dTNWblJGaERmb3p3R0lXL2R1RDVRM1dndmU1cWRWNGZlQittTUdWNXZpdWNYeklt
UkdFV2Zib0VoZGZEcHB2SHBkR1pVcllUSDdIbDZSM0xGWVgyNkgzeDZ5ajQ5RUFqUW4zekJw
NXNMeGZGMGpkWTN5OGoxUkUwM1MxWVRjY2g0ZXNMZnZzZ2xIK1N4V3RmSzVIaTZYKzk0dXRx
bmtjaW1HbndOdktiekd6UjZQQjNWb2RUSDAwbExCZ0lCVWxOM3duVXZpVFE5UWZrbXplUUpS
c2lnUFRVZGZMcUZNSlZQRjdtZUlUaFdXWnZ0V2dZWmRzWE4ramxOMTdIM1ZCSlc5dW1aNzcw
SXBmNU5oZjRzNFo5WTdWSy9UMDhtR1NOazBKNmFEajVkRnFOOUFvTlBwekYrQVovT2E3cnNZ
dTAwWnVXcjgvRUxlVTFYREpNaHkwcnQwNU5IZ2RFQUFDQUFTVVJCVkV2UXA4dXU1eHR0RFFi
eHkwTDBYL2ZDYWJxTzd1ZG5XeklkUHAxdldQRHArZ0dmcnJvSEUxLzVZeXFmcnEzcGRNaFZr
cVNJTlBiRmYwelJqR2prMFVsMnVDVDlFelZkNU91RkRCMnJzQWtrMUhReVNLMTdGMEtrejZm
em11N25mTHFncWlUVnNFYklvTGswZmVQR2pXUkNESnphbkJqZzArVXhtcDBlZkxxVXlLY1Rl
U0xlTXpoMjhzdUVnT3B2R3JOcThEWHdDM2xOVnd5VEpaOUduMzRYNTlObFQ4bVNkM3NUZjN2
Z0Uwc2lLd044T24xY3kvbDBYdFBCcHllZ3E2dHI5dXpaVk5OVG1STURmTHFNVkV5WjBWakNw
eE5acEQralNSTTFuUldGdE9mRHUxMlpwZ2VaLzFMeXdXcC80ayt2VDFmVWRIMjdFSGYzUWVa
VFRmZU8xRFFkZkhxcTlQZjNlNzNlQXdjT1VFMVBaVTRNNnRPMUwzVXltMDhudmNHSXJMVGxC
bnk2eFBsMG1SVFNVUmRGbnk3VDlEUm1kWmV2SWFHbSsxRndQSXpyNmhGSnVWOWx3S2VUYnc4
MGY5cWsyajgvS0Y1T3F1YUlkZnQwK3JkdE5VMWYvdU1Yd2FlbnhOcTFhNTkvL25tTU1kVjAz
WE5pQkZGdy9kaU1BWDRVSkRYc1JXcnpaKzJleklsQnF1OGJzeGUvWVZ0Ty9WNXRUZ3hKY3ph
TTBmdDA1N08rYkJPcVEzYy9PVG9IQWwxKzk1TmxxRzUwSm9TT3NrM2tzUjhGMTVkdEltdlJ4
OHJIV0tlbkI2STZ0TDVzazRRUTJmdmRUNWJSZDNOOTJTYTBaai9kNzJnL2w2U09zUnpJSHNr
Vy9DaEl0aUNiVFVKSCs1QWM2UGtsV3lKclNkTHJ4ak12SzR0STZPNG55NElvMkhONHdudEhz
eVhuTDk4T2ZQNzBUS2ZIcnRqbXNyVklKdVQ5N1pqNDNwRnM2ZU83ZDQ3MmdTQUtrbnQySGhJ
TlZSRS9pMjArSndhWldwcUNVNWdUSTRpQ2Qva2EyRyttNE5QQnB3dkdrTEdPUUNEQS93Wkkz
aURpMDhtVjBlSStYZkduVHUzQ0kyUUpjY1RFMk5JQXNpOFVHYytCaHZuSGd1bGFKQ0FpSVZ4
V3h1NUNyVXNrYUN1RUpNYW4wNTlHMlorTHBiRXJ4OG0zQjlxU05KUFIvTWNPYXZuR012cXZI
elp6OXVhcjg3RXhOSksyQUEzajEyVnY1Qm9oOHY3Nko3NlBwRUZRQkpIYjhzWXk0dFA5RTMy
NkgzeDZzbENmcm50T2pBbnY5SnI5YXBwdW9rdEJKbXE2RVJneDFKc3V6RGFlVGdZclpMcER0
WW1vQUJVbW1TNm9TUW5WS1lsUlBWNXUxRFNML0FBYmtSQXIwNnltKzVuY0FvRkFJQkR3andr
dUc4UEtvbUtYa09YR1A1WjluckZ0NGgrYnQ1UGMweVV5VFdkSHEwbFRreHZSV1hZSmVjd3Vv
ZG9ha2NaM1FUOHF5STJHMGUzVGw5aE55VDVnZUUxSEVhU2g2WDUxcHdqajZYS29wdXVlRTRQ
MTZTZ3kzcVc0L211YTZ0dmcwODNrMDNuM2grb1FGWHBmblU4V3crb0NVYlRsRzh1SS9sS1pE
azdVVTdMQnpaczNrekR5RXBHaFFDQWdqZjFiM2MvMFpLcWVyS1pMWTdKT3dsZ1hLVXZTajRL
MVpVOEh4MzczWXgyOW9vMmxXWkViWFVLMklNdUt5aXRwSmVxQzcySXVQNU01WWxsaWZMYXlH
L3ZOTzhVd2pSZ3BrVStuUiswSG41NFpxS1lUYVVCcjltdHJlc0x6UERQUTM5ekFwNXZCcDh2
TXI4elpLY3FsWXJ6SXphL3lPS2l5QzNZNWtSNFJwVlBjam81czFZNDlxUDQwcUJLVHJwdWt0
d1VTYWpyMTZWSUV5VFRkUDZicGlsMElmSG82b1pydWU5ZEgzeGp6KzNTWnBodmswelhHbXND
blM0eFAxNzZKT0VGaVBOT3lLWTBZVnRQTms1V09NSkhFMURZbCsxUXp3cWVqaVpwTzl3ZytQ
Uk9NKzNUbXc5WVBQajJScG1jWFh0TlJuWmhKTjhDblM0RjArajVEYjZuNGROdmMwdHNDa3BK
UEp3LzhFelY5OUZVbHdLZW5FMFdmN25lOFR4LzlRVXo5TXl4YlBuMzBsemNWVGMrd1R5Y2xV
OUNhL2RxbnZYa2NNZmgwZndaOXVwLzhLa0MwUGpDNlVOeW5xemtxSTJUUW5wb09QcDJGWEFW
aDNKY0EzWXhxZWdUSngxNVFGbnc2K2F0TFFrMDN6NDN0NFk2OXBmZndVUjNTOXVueVY1VlFQ
TkZBMDVPR25lZW93ZHZnZTlmbmZkZUxJc2o3cnRkUFprSlJtbDNJSkRNS0JWR1EzTi9sYlpB
TW1DVW5PRFluanRvOFB0bWE1K2pkUHE4a1NkNTN2Yko1amhxOERWSm01em55MW5rYmZBM2VP
aTlhczUrMGxkcjlUMi9mcnZFcXVmLzEvOTZjTU9ZdWI4TmR2b1pVWXRnZWJwNnNrbTJydTd3
TnRXVlA2OTRqaXFCazk2Z1JFd2dFYUtzdWJ5enI4M3FES09oOTF5c2hKR3R6RkVGcTh4enhh
blBreUJGeWpzdVd3enhIaVVuS3B5ditEU1FyVUovdU44WktCMWtib2xMOWd5VmpJKzlCK20x
M29rLzNvNkRSUGwxMmpPT1hrSU5QdDlRdHZZZlBPL0hnMlBYUXBHUG85dWxxMzVLTmtFRjdh
am83bms3ZWRYcnEwcE01aUlKbUcwLzNHek9lUG40QzFDSHloeFR0VFNscXVuRlh6YXRwdXNo
NCt2S05aZnF5a2wwdFRxNjVsbEJpVFRmUHlEWGJ2YzJUbFk0dzg0eW5zNjFLeHRQSE5YM3Nw
MUZXMHdYSDAzMTFQdEIwblJCTmx6VTkxWFEwOXZkdTJ2UW11UlRFei93anc2RHRqMjRjamY2
dFRqcytZeVB2ZmpxQ3FkZW42MDQxeVB3SmlQNUhodG94Uzl6QXAvdlQ3ZFA5R2o0OWdxU0px
cUxtMC8xY255UWRUTmtxR1lBOU5WM1pwelAvVnlabk5TblNsQkNqZmJwL29xWWI1OVBwUDBl
ME44VjNTaU95R3Y4cll3byt2YmJzYVgxWitibS8waEQ3Qmo0ZGZMcWFUMGVjcHF1ZHpySWxw
RXlzWXIxSkkyVFFicG8rcWhTY1QyZi9ta3ora0IzVVczWlpHeDNlM3ovMjcyb3BvbWRpU1pI
dHkyNko4ekVlV3B4RTRib1hza1RBcCt0T1ZmV1V0b0pQSndjT1BwMDJRdG8zU0ZYYnJ6VHFr
cXhQOTZ0NEtjbmVtdDdVMUZSVlZaV1hsMWRkWGQzUjBZSDF6bk5FUEJmdjArVUYyQkF5eUtk
cmk3THFCenVqNldtYzM1MWNHS3NnQ3BxYjRnT2tpVDQ5MmIra3l1TEhDMWhUQnlTN1BuM05m
clJtdnc2Zkx0NVdmSnRZeUtmTFZNWWtXZWtPUzlHbnM1cWVkcC9PdHphOVJTUUZueTRyamtZ
RzkvaHk4eFFqdE5Rc21uN1BQZmQwZDNmMzkvZHYzNzZkMU5IVk44OFJHUkxsZmJxc0FKdGYv
Wk16S2ZqTEovUjQvd0NpZjFFTG92RUNmb3E3U0RZOWNuRzY3S2E5bGovaEx3MUpIcVBpMXNp
b0M5WDAwWjhyR1UzWDQ5UEZFdE9vSjJVSm40N0cvdllDUHQxUW55Nzc0NmppcjNUOHFZRWk0
NTJRMW1MelQ2eEZUREZDUzgyaTZaUVRKMDU0UEI2c2Q1NGowdnE4VDFlOHRZKzVQRUZ6ellm
UkpkUjcwaDlENUJYdkpvYXg2NUxlSTQybDJ0TTFvYzYxMmdkUFFwK082aEQ1d1YyaDQzTEdl
VHlaT2tTK0xyQkhJVTMwNlJxZmhWcUZKeWZ1am1pNlgxM1RoZjVIV2p2aG01WmdXeWxxdXJW
OHVxeDdteUVyM1dIWjllbXlLbUNzVDZkTCtEWW5DL25lUHVwUm1Hckp0SXdsYTlmbzZXYUVo
SnBMMDN0N2U1Y3NXYkozNzE2c2Q1Nmo5V1diVUFUZHZiT012ZmVQelYwaXV3K2lJSm4zcE9m
dytDd3FkRFlaOWpHaWM5OXdzNmpRT1doUUhXcDY5RkUvQ2pZOStpaU5aMStWM1krL3VyUE1q
NEo0WnhtS0lEcHZDNDFrSDdQNXlPWndrVzJmTE9rNVhCWWs4KzhFME4wN3k2UUF1dnVCYldq
TmZqcURqMkp1ZUdkWlJFS3lvNUNZT1dLQ1NqUFJLTjdUZU9WMmlLRFI5K3VCYldST0dUTFAw
ZWhzUnlMekhBVW01Q1pySzlwaXNzZUJRRUN4UC9oUjhPNEh0cW4xRnZQY3kzcDQxdlBKNG4z
cUxZQW42b05NTjJSS0luK1ZPZGZvN0ZFb2drZ2ZhM3IwMFNDWkVTa3lQdHRVSUJDZ3ZkSG04
eHhoakRzN096MGV6eXV2dkVLZTZwdm55Sy9rMDlXc2VtM1owL1RqbEg2SzhqZGZuWStVbkth
VEV0RGI2T1hlRXlkUEdmMk5tNm5mVCtNM2I5NGNHQ000Tm4wQmF3VDhZN1lGTVdXNzJhdnU2
QU9hMVlSdkF4T1hzSFhrWlY4cVpRZEk4aHd0a0QzMlI2M2cySmlWaE5EeWpXV3MrMURiTHo4
ZnplakZBMlBKU3dqMStueWpqY240OU9EWXBZVEorblIyWDhHeCt1QWtINXFuckswVXY3dFkx
NmRMQVpUaHJIcmY5YVZyVTRLSlpjdW44L2FjbFJUYXIyaWY5NCtOb05McnFmd282QnRyTHFv
em8rWDE3ZTNUNit2clMwcEs5dTNiUjVmb20rZEk3VzFRZTRPRDNFMDJINHJzaWpmRjViSzMw
RC94cVVad2NPeXZhM3p2MU40Um43UGlFa1VKUUl4a0syYkYxNlRtTjB2M3FORmMydTNtWnc5
OFRFbVRIVThuUDBXSXZFSCtpWS9WYnBZWW5oYnYzc1lsa1BWR1lKc2lsUzJvYWJyYWtBdjdV
YXA0eHZINW9MSFpTMlQ5ME9hYWppWnk4ZUpGbmZNY1JaQ2dUMGNSWkpJUlJrV2Zuc2FzRWtx
QXRuTWhOeVBhYWp3bEpVMFg5T2xwYnl2eFRkR0dJai9MMDZjWjl1a29na1NNc3l3cnRka2tS
TEx5dmV1VG1PTk41UUFGbXlzclBsMUQwTWxONDNTV05aZGl2N0s1cHFjRnF1a2FLaWFORmNn
MnlHdEl5UmZnUnN4ZjFFUk9GUjNiVDhyV3BUMkJ4SWxSVFNlL2w0NzVJTUZMWDlMeU50R0NI
dlNwMmpqTTZHY3crU2JCZkI3clRpYjFONVNtTFhFUE5EYVNlZ0t5MXB2UXdobnBSYkwrbytN
MjJwRWlhTUlHeFc2Q0Rhc1dESnFlR0cyZlRpLy9rc1kwRkRlbTJlVWxQRlZVYlJjVnNnakNq
V1VpNTROZ1ZpSjlrWGN1ZkFJWjh1bXM5elRTcHl1YUtYOGlUU2NqMSt6M0t2NXhldHZLcDJU
QStUZVVobWxvdWl3cnRZNHFtSlZjMDdsK3hXWTEzb0I2dndJcVpzVmYwQ25lL1dnbmw1MFg5
SEhhZlRxL0hEUTlNVTg4OFlUR0o2cjRKNjN1MitoMzhNQzRMZ2l0eGVRanBkV3FxM1pIOWNR
a0pvZDBKYU80QmZrM3FySDVZOGViUWwzSzJkRjIzVytUU0VQeENmdTVpOXY4U3I1VjM1dVZv
SWtTZWNuUi85L0szcjZBOHR1dEwxdUpPMTZKK1ZNcjM2VCtNU01zNzFycCtFNlR5b21zcU9u
SjN0UlNva2V0b0VMTWV3R2FuaGlxNmJ4UFY3d3RieXdqNnFEMnV4eFowcnZaTnhvV0dWY1Qy
WW9rUmxtaG1FamZoajNzL05lOGtNbXlJanZsTTZSN2xBbmNlRXdFb1RYN05kcUJYY1czWVk4
OGJTWjVjc08xWmVPN1VCRmN4YXhvUE4zNGFDTWtlbmMwZkRyZE9LNHRZMXRHZmdoam1aQTlz
am53TjhXMll0K0YwVERhVnV4N1BmRjlKMWxOYUlUSWhMVDV0cHJRSDVqRGtXV2xxQlFLeVNz
ZDQvSWZ2OGkvS2RwWnlScWNKcW02dTRtZGh3MVRTSHZzTU1lYks4TDBGcjdQS0xXUGJHdnlO
M3JpYmJSSjJYZFF2UitLK1BUZXpUN1pPeXZTdGNhYkZEUmRBem9uQmhxcldBLzNWci9YbUEw
RHJkbFBIcHNoVDdpSGUzMzNNQ2RHWXZUNGRJRXdrYTBKN2xFa0RMSWlOK3JUa2FJL1hiTWZy
ZGtQYldYMXJBUVRTK01lelpNVitQVEVhSXlud3cxdWNJT2JxVzZnNllrQm53NVpRVmJXeWtv
d01mRHA0dGhUMCtFR043akJ6ZVEzMFBURWdFK0hyQ0FyYTJVbG1CajRkSEdzcE9raWMyS0lO
REhjNEFZM3VHWDlSalc5NmNjLy92cnp6OU9sazFiU2RKRTVNVWhqZ1UrSHJDQXJTMlFsbUpp
OWZYckE0OW04WU1GZmZ2ZTd3ZjcrMUhYU1Nwb3VNaWVHU0JQRERXNXdnMXZXYjZ5bWsxdmQv
L3BmZjN2cnJSUjEwa3Fhcmpnbnh0R2pSeDk3N0xFTkR6Lzg2SjEzL24vWFg3L3V2dnNlZSt5
eG45MTExMk9QUFVZZWE5elgvdkNIQ1dNRXR5YTR4NS84NUNlUUZXUUZXYkgzajl4eVN5YjNh
SjZzaUdxdC8rbFB4elg5K3V2L3RuOS9panBwSlUwWG1ST0RQRGgrL0xqSUJ2dmZmVmNrVEdS
cmduc1VDWU9zeE1NZ0svRXdjMmFGeFJKTDR4NU5tQlVaZTNuMy8vNWZ4NDI5aU15SlFSNE1E
QXlJYlBDYjdkdEZ3a1MySnJoSGtURElTandNc2hJUE0yZFdXQ3l4Tk83UmhGazFQZkRBMXlk
UGlteEtCQ3RwdXNpY0dFbHRjT2pzMlRTbGxrNGdLM0VnSzNITW1SVTJhMkxtekVvRUsybDZR
cnJUUFZzckFBQ0F0YkNWcGdNQUFEZ2MwSFQ5TkRVMVZWVlY1ZVhsVlZkWGQzUjBZR1pXVlZO
bHhTOHhRMWFOalkwVkZSVm15NHF3Y2VQR0xMNkpHdjNLVkZrTkR3OXYzTGl4dExRMEp5ZkhW
SW14elZWY1hHeVNySnFibTh2THkxMHUxN3g1ODVxYm00M2JOV2k2ZnU2NTU1N3U3dTcrL3Y3
dDI3ZXoxK0ZrVjlQNXJOVHl6RzVXOTk1Nzc0a1RKMkt4MkovLy9PZHNuWGlLTGRQVjFUVjc5
dXdzdm9sOFZ0bnRVUVErcTAyYk5pMVlzS0M3dTN0a1pNUlVpVkVPSFRyMHExLzl5aVJaRlJZ
V2hzUGhlRHdlQ29YY2JyZHh1d1pOVHdNblRwendlRHowcVJuT1FNeGxwYmdrODhoeWlNZmpy
Ny8rdXMvbnkySkttTW1xdjcvZjYvVWVPSERBREc4aXpRb2hkTmxsbHhVVUZOeDY2NjBuVHB3
d1NWWWVqeWNVQ21VM0dSYStlOTk2NjYxZmZ2bGx0dkloMEt4OFBsODRIQjRZR0FpRlFqVTFO
Y2J0RVRROVZYcDdlNWNzV2JKMzcxNjZ4QXh5d0dmRkw4bDZWdVRiY1ZGUjBmdnZ2MitTck5h
dVhmdjg4ODlqRTd5Si9QdDE1c3laMnRyYVpjdVdtU1FybDh2MTBFTVBUWjA2MWVQeDdObXpK
NHRaWWFYbU9uanc0TDMzM3B2RmxQREVyQTRmUGx4WVdJZ1FLaXdzUEh6NHNIRTdCVTFQaWM3
T1RvL0g4OG9ycjdBTHN5NEhmRmFLZVdZOUs0d3hHWHU1OHNvclRaSVZHUnJPK3VDMTJ2c1Zp
OFh5OHZLeWtoTG1zcG81YzJZb0ZDS0RDYk5temNwV1ZueGloSnR2dnZtamp6N0tWa3FZeTJy
Ky9QbDA3T1dxcTY0eWJyK2c2ZnFwcjY4dktTblp0MitmYkhsMk5aM1BTaTNQN0dhMWR1M2Fz
MmZQeG1LeDExNTc3ZkxMTHpkSlZwUXN2b2xxV1gzOTlkZFBQUEdFMysvUFJsSUtXYTFhdFNv
VUNwSEJoSktTa3F4a3BaZ1l4dmlkZDk2NTRZWWJzcFVTVnNxcXFLaUlqcjNNbURIRHVGMkRw
dXNIVGVUaXhZdXlKZWJNNnVMRmkyYklxcUdob2JTMGRQTGt5ZC81em5mKzY3LytLL01wS1di
RnZwU1ZsQlN6SWcveTgvTnZ2dm5teno3N3pDUlpuVDU5K29ZYmJzakx5eXN2TDgvaXdMcmlt
M2pqalRlKzhjWWIyVXBKTWF1bXBpYVB4K055dWViT25mdjY2NjhidDJ2UWRBQUFBUHNBbWc0
QUFHQWZRTk1CQUFEc0EyZzZBQUNBZlFCTkJ3QUFzQStnNlFBQUFQWUJOQjBBQU1BK2dLWURU
aWVMbDZJRFFOb0JUYmN3QXdNRER6Lzg4S3haczZaUG4vN01NODlrT3gyemd4QjY3cm5uTU1h
Ly9lMXZRY2NUMHQzZGpSQ0NlV1pFTUZYWEFrMjNNT3ZYcjcvenpqdS8vUExMcjcvKytwRkhI
c2wyT21ZSElWUlpXVGt5TXJKZ3dZS3NuM2ptWi9QbXpaTW1UZHE4ZVhPMkU3RUFwdXBhb09r
V1pzNmNPYklweWRuK1JCOGpoTmF2WDE5UVVFQXJmR2E5MjJVRmhOQjExMTIzYWRPbTY2Ky9u
bTBjV2FPOThNSUxNMmJNS0NvcTJqNDJ5N0F6bSt2bW0yLys4WTkvZlBQTk41T25OVFUxWkc2
SDl2YjJ4WXNYWTR5N3Vyb3FLeXZ6OC9NM2JOakF0bWUyRXM0aWZOY2kvU28zTjVmT2lmSHpu
Ly84My83dDN6REc5OTU3NzVvMWEraUthVThHTk4zQ3VGeXVvYUVoZG9tYXBqLzMzSFBSYVBU
QkJ4L01hSDRtQXlHMGMrZk9TWk1tN2RxMVM3R2h5T050MjdiRllySFcxdFpzelI5aUJxTFI2
TFJwMDc3ODhzdHAwNlpGbzFHTThaWXRXMWF0V29VeFhybHk1ZGF0V3pIR1BwL3Z4UmRmakVh
ajI3ZHZkNmFVVTlTNjF0RFEwTUdEQjJmUG5vMHhIaHdjL043M3Z2ZUxYL3ppZTkvNzN1RGdv
SEhKZ0taYkdBMmZQamc0eUdyNnBVdVhNcDJjK2REUWNmWXhQZCtjckZNdExTMjAvbFJMU3d2
RytOeTVjMjYzKy9qeDQyNjMrNnV2dnNJWTUrYm14bUl4akhFc0ZuTnlXMkdsN3JSdDJ6YVB4
ek5wMGlTRVVFNU9Ebm1wcTZzTElkVFYxV1ZvTXFEcEZxYTJ0dmJPTysvczdlMDlmLzU4Ylcw
dHhuam16Sm43OXUzcjcrK3ZxNnR6K05kaEhrRk5WM3pzTk5hc1dVTitkWC9tbVdmb1FNR0tG
U3V1dnZycWxTdFhrcWRlci9jUGYvaERMQmI3NHgvLzZPUzJ3a3JkSmo4L3Y3VzFOUmFMaFVJ
aHNpUVdpMVZYVjk5NjY2M1YxZFg5L2YzR0pRT2FibUhpOGZndmYvbkxtVE5uMHV0ZTZ1dnIz
VzczakJrenRtN2RxcUhwemp3RCtSTlBWaEJWTVFZN3Nybkt5OHMvL3ZoampQSEhIMzljWGw1
T0ZyYTN0eU9FMnR2YnlkUE96czZLaW9yOC9QeDE2OVpObWpTSkxIUmdXMkdsYnZQVVUwKzUz
VzYzMi8zc3M4K1NKZmZmZi8vcTFhc3h4di82ci8vNndBTVA4Q3VtQzlCMEFBRDBNenc4L01Z
YmJ5eFlzQ0RiaVFDamdLWURBS0FUTWxoY1hsNmVyVmxOQUI3UWRBQUFBUHNBbWc0QUFHQWZy
S0hwenZ6aEJRQUFJRm1TMDNTa2dtSmtUazdPdDc3MXJWLzg0aGZrSXRaTWN2TGt5V1hMbGsy
ZVBIblpzbVdmZi81NWh2ZWVNZmoyNTVmRTQvR0hIbnFvcEtSRTdaM0NHRGMzTjNzOG5yeTh2
TzkrOTdzOVBUM1llUTJJRUNvdUxzWktUY0dqMWppQlFNQTI1b1B2U00zTnpRc1hMcHc4ZWZL
U0pVdmVlZWNkTE5aSitMV2FtNXZMeTh0ZExsZDVlZm51M2JzemN6aEd3NHNoZjk3eFRjSERO
Nm5JV2pLUzEvUUlkMVBSOUpHUmtWT25UcTFhdGVvLy8vTS9SVkpKSTNmZmZmZUdEUnY2Ky9z
M2JOaXdZc1dLRE84OXcyaGZxbGhiVzF0VFV4T0pSRVpHUnRTMlVGeGMzTkhSTVRBd0VBcUY3
cmpqRHV5d0JzUVlyMW16NXZISEg4ZEtUY0dqMkRoSGpod2hKM0RHY3M0QTdPR3NXTEVpRW9u
RTQvSGR1M2RmZnZubFdLeVQ4R3U1M2U2MnRyWjRQQjRPaDkxdWQwYU93M0Q0OTUwLzcvaW00
T0diVkdRdEdRWnFPbmx3NnRRcDh0Zlk5OTU3cjZxcUtqYzN0NnFxNnIzMzNpTXgzL25PZDFh
dVhEbHYzanp5UndieW1jWVdTYUFMMlMzekZUbGtGQmNYOS9YMVlZejcrdnBzL3c5dmJVMHZM
UzE5KysyM3RiZFFYRnk4Zi85K0ltUXpac3pBRG12QXI3Lyt1cWlvNlBUcDAxaXBLWGo0eG9u
SDQ0c1dMZnJUbi81a1kwMG54R0t4cHFZbWN1V2llQ2RoMTZxdXJtNXZieDhZR05pM2J4K3BH
Mk1ERUVKdXQ3dWdvT0NXVzI0NWNlSUVWai92MktiZ1VXdFM3YlZrR0s3cFEwTkR1Ym01R09Q
S3lzcVhYMzQ1Rm92VjE5ZFhWVldSR0ZyUGM5cTBhWFJkdGtpQ2JHdFlyQ0xIcEVtVGhvZUhy
N3Z1dXFHaElaZkxKZElRMWtWYjAxMHUxNFlOR3dvS0Nzckt5bDU3N1RYRkxUUTJObDV4eFJW
VHAwNWR0MjRkYVM1SE5lQ3p6ejVML2d5Q2xacUNoMitjUng5OTlJYy8vQ0cyM1E4L3NzT2hn
MVFmZnZnaEZ1NGtzclU2T3p1TGlvb1FRa1ZGUlViL1N6N0RuRDE3dHJhMmR0bXlaVmpsdkpN
MUJZOWlreVpjUzBibWZMckw1U0lENjlGb2xLZzhZdjY1aDlTTEpHQk8weE5XNUNndUxqNXo1
Z3gyaHMzVTF2U2lvcUpRS0RRd01ORFIwVUdHakRVNGNPREFuRGx6c0pNYWNIQndzS3lzakJj
WDJoUThmT09RSHN1UFFWc2QvbGlpMGVpdVhic1dMVnFFaytrazdGb1ZGUlhoY0RnZWo0ZENv
Y3JLU3FOU3p4TDkvZjE1ZVhsWS9ieGptNEpIclVtMTE1Smg3SGo2RjE5ODhhTWYvWWpVaTFE
MDZiSjd2a2dDM1ZyQ3h5eDMzWFhYNDQ4L0hvL0hIMy84Y1dLZ2JJeTJwdDkrKysyMGIybWNl
Q01qSTBlUEh2WDVmS1J1akhNYXNMR3g4ZHBycjJXWHlKcUNSNk54N0NUb2VPTGgzSC8vL1Nk
UG5vekg0MDFOVFdSVVNxU1Q4R3NWRmhhR3crR0JnWUcydGpiYmpLY1RMbHk0c0duVEpyL2Zq
NVhPTzc0cGVQZ21GVmxMaG9HYW5wT1RjL25sbC8vc1p6OGp0VG9QSGp4WVdWbnBjcmtxS3l2
cGVMcnNuaStTZ0NhQ3hUVDl4SWtUUzVjdUpWY3ZuRHg1VXFRaHJJaGk0OGlXOVBUMExGMjZO
RGMzMStQeE5EYzMweFg1N1pTVWxLeGR1elllajJQSE5DREdlT25TcGV5UUZOOFVtR3N1amNh
eGphYnpIU2tZRE02Yk55ODNOM2ZSb2tYaGNCaXJ0SU9zQmZpMUdoc2J5WGZ4dVhQbk5qVTFa
ZnpJRElHMDBwUXBVMjY2NmFiUFB2c01LNTEzZkZOZ2dhNmx1SlkyUmwzTENBQUFBR1FlYS96
blNBUDRnQUVBQUtCWVh0TUJBQUFBQ21nNkFBQ0FmY2ljcG91TWlzRElDUUFBUUNwazdqZlNO
R282U0w4SXI3enl5cFZYWHBtWGw3ZDQ4ZUlEQnc0b3h2RDFKUnhTNlVXR1NFOTJRcGtYR1h5
emlIUXFmV3RaQ1A0QStTSTJyRHlTNjlQNUpScGJwaHNYV1V0RzhwcStaci84QnBwdVN1Nisr
KzZQUC82NHY3Ly9sVmRlVWJzeW5hOHY0YlJLTHl6YS9jbzVaVjVrc0VjbjBxbFNXY3RDc0Fl
b1VjU0dsaExTV0tLNFRSa2FhOGt3U3RNLyt1aWp4WXNYdTF3dTlnTkhWcWZsNk5HajExeHpU
VjVlM3Z6NTgwbkpNUko4OXV6WkcyKzhjY2VPSFZpbFNvenNvNHpmenRLbFM4bXNpZncvU2h6
SXFWT244dkx5TGwyNnhML0UxNWR3VktVWEdkclM3Snd5THpJVWowNmpVNld5bG9WZ0QxQ3Rp
QTFiU2todGlXeWJzcm94SW12Sk1FclRmVDdmMXExYjZiODJzRktkbGlWTGxyejY2cXZ4ZUx5
dHJXMysvUGtrSmhLSjFOVFUwQUplL0w5UE1kZGQrTzNzMnJXTEZBVmJzbVRKM3IxN1JSckNy
dnpqSC8vdysvMlBQUEtJNHF0OGZRbEhWWHFSb1MzTnppbnpJb00vT3UxT2xjcGFGb0k5UUxV
aU5td3BJYlVsUEd6ZEdQRzFLRVpwZW01dUx2bjdLTHV1ckU1TGJtNHVkZHlrdWd0Q3FMcTZ1
cVNrcEx1N20wVHlWV0l3MTEzNDdRd09EbDU1NVpXdnZmWmFaV1dsUm8xWjIvUGhoeC9PbXpk
dnc0WU53OFBEaWdGOGZRbm5WSHJoU2VqVEhWTG1SWWJzMEJKMnFsVFdzaERzQVNvV3NlRkxD
YWtWRitLaGRXT1NXb3RnbEtaN3ZkNnRXN2NPREF5dzY4b2UrLzMrbHBhVy92NStkdm1aTTJm
MjdOa3piOTQ4OGoxWDBhZFBuanlaL1dMQ2J3ZGovTXd6enhRVUZLZ1Y0M1VDRFEwTmZyK2ZE
Rmlwd2RlWGNFNmxGeDV0WFhaT21SY1o3TkdKZEtwVTFySVE3QUVxRnJIaEIzNEZoNExadWpI
aWExR00wdlFQUHZpZ3VycWFHQm02THJzZGpQR3hZOGR1dXVtbS9QeDhhbk5vVEVORHc5S2xT
Mk94R0Y4bEJtUDg4TU1QazdYSVUzNDdHT04vL3ZPZnhjWEZtWjlpeVR5Z2lWeThlQkVMMUpk
d1RxVVhGbGxiMFlWc2pCUEt2TWpnbTBXa1V3bXVaVjM0QTFRc1lpTXJKYVM0UkxIcDJMb3hp
bXRwWTg5Nkw4UER3Ny8vL2U4ZmZ2amhiQ2NDQUFDUVVlejVQMUtFVUUxTkRSbTlBUUFBY0E3
MjFIUUFBQUJuQXBvT0FBQmdINkRlQ3dBQWdIMndaTDBYUUFSOXBUbll0MVd3dm9RTmdObzRH
ckFGYlpxYm14Y3VYRGg1OHVRbFM1YVEvMnp6OERFaWExa0kvcXhwYm03MmVEemttcWllbmg2
czFEZEUxSkp2S0IybGNwTFdkQ2tndjRHbW14TjlwVGtvNHZVbGJBRFV4bEZEVnRCbXhZb1Zr
VWdrSG8vdjNyMzc4c3N2VjF5Rmp4Rlp5M0t3WjAxeGNYRkhSOGZBd0VBb0ZMcmpqanV3ZXQv
UWxqaStvWFNVeWpGSzA0MnI5MElyQjdTM3Q3T2xGUUExZEpUbVNLcStoSjJBMmpnc2FnVnRZ
ckZZVTFQVGdnVUxOTmJsWTBUV3NoQXlUZCsvZnovUmRESVR0RnJmRUxHdGlnMGxYaXJIS0Uw
M3J0N0xsaTFiVnExYWhURmV1WExsMXExYkUrYnNjUFNWNWtpcXZvUnRnTm80TWhRTDJ0Qnh1
UTgvL0ZCdFJUNUdaQzFyd2JaSlkyUGpGVmRjTVhYcTFIWHIxbW4zallTYXJ0aFFTWlhLTVVy
VGphdjNjdTdjT2JmYmZmejRjYmZiL2RWWFg0a2NwR1BSVjVvajJmb1M5Z0JxNC9Db0ZiU0pS
cU83ZHUxYXRHaVJ4cnA4ak1oYUZrSlI5dzRjT0RCbnpoeXMzamRFZkxxc29aSXRsV09VcGh0
YTcyWEZpaFZYWDMwMXFid0lxS0d2TkFkMlpJRmlxSTJqRGUwaDk5OS8vOG1USitQeGVGTlRF
eGxrNE9GalJOYXlITEt6Wm1SazVPalJvejZmcjdhMkZxdjNEVzFONXh0S1I2a2NvelRkMEhv
djdlM3RDQ0ZTSVIxUUEwMUVzRFFIVHI2K2hBMFFhU3NuMThhaFRSRU1CdWZObTVlYm03dG8w
YUp3T0N4N1ZTMUdjUzNyd3A4MTVFRkpTY25hdFd2SmdEUGZOeFRQdFlSTnA5Z3p0YkZudlJj
QXQzYyt0UUFBRm1SSlJFRlVBQUJuQXY4akJRQUFzQStnNlFBQUFQWUJOQjBBQU1BK0dLWHBN
TWdPQUFDUWVZejZqUlEwM1NSQUpaT2tFUG5aWDYxeDJMb296a0g3cVBuMjFGSEF4UHp3QjhY
S0k2bWJKSExnZkwwWEhkZWhKSDh0WTBSK0EwMDNNMURKUkFmYXZWZXhjV1IxVVJ5QzRGR3pB
VG9LbUpnZmpZT2lkWk5FRGx5dE1JNkpOSjJ0M01KWGQ5bXlaWXZINHlFMVlaeDJNbVFlcUdR
aWpuWnY1QnRIclM2S3ZSRS9hc1VBOFFJbUZrSjJVSXAxa3hJZU9GL3Z4U3lhTHF2Y3dsZDNt
VFp0V2lBUWlFUWk3TjlOQVNPQVNpWkpvWDBLOFkyaldCZkY5b2dmTlIrUVZBRVRxOEFmRkY4
M0tlR0IwK0VhdHQ2TFdUUmRWcm1Gcis3eTVwdHYzbmJiYmZQbno1OCtmZnF2Zi8xcjhhU0Jw
SUJLSnNtUzBLZkxHa2V0TG9xOUVUOXEyYXZKRmpDeEJQeEI4WFdUQkErY0w0eGpGazJYVlc3
aHE3c1Fob2VIRHh3NFVGQlFJSjQwSUE1VU10R0I5aW1rMFRqT0VYU1dwSHk2amdJbTVrZnhv
R1IxazBRT1hLMHdqbGswblI0SnFkeWlXTjBGSVRScDBxUzVjK2UrK09LTDRra0Q0cUNKUUNV
VGJXVE5SUmV5TVJxTkE1b3Vhd0crUFJVN3BOVlJQQ2haM1NTUk16Rmh2UmVSWktEZUN3QUFn
SDJBLzVFQ0FBRFlCOUIwQUFBQSt3Q2FEZ0FBWUI4eXJla2FQNmNBQUFBQUtaTE4zMGhCMHcy
Q0xjSFIzTnhjWGw3dWNybkt5OHQzNzk2dEdNKy9sVkR2UlNPbXViblo0L0dRNjE1NmVucXdV
cGtPcThPM0EzK01JZ1ZNdEF1aFpPWllNb0JJNDRpY2lYd00zOWtTa3JTbSsxRlFkZ05OTnhX
eUVoeHV0N3V0clMwZWo0ZkRZYmZicmJnSy8wWkF2UmVOVjR1TGl6czZPZ1lHQmtLaDBCMTMz
SUhWeTNSWUhiWWQrR01VTENVa2k3SGxXUy9TT0NKbkloL0RkN2FFR0tqcENLSDE2OWNYRkJU
VTFOVFFKZnpZaTNaTkdNWHRBR3J3SlRpcXE2dmIyOXNIQmdiMjdkdTNlUEZpeGJVUVFtNjN1
NkNnNEpaYmJqbHg0Z1NHZWkrSk5IMy8vdjNrTkdQL0dNS1g2YkE2ZkRzb0hxTkk1UllhdzNj
MjI2RGRPQ0puSWgrajF0azBNRmJUbjN2dXVXZzArdUNERDdJTDJjY0phOEtvYlFkUWhDL0Iw
ZG5aV1ZSVWhCQXFLaXBpLzZiTWMvYnMyZHJhMm1YTGxtR285NktwNlkyTmpWZGNjY1hVcVZQ
WHJWdEhHNGY0RlZtWkRxdURsUDVBSkR0R2tjb3RmQXpiMmV4QndzWVJPUlA1R01YT3BvMnht
czUvZE1zMFBXRk5HTFh0QUlyd0pUZ3FLaXJDNFhBOEhnK0ZRcFdWbGRxcjkvZjM1K1hsWWFq
M0lqWStjT0RBZ1RsejV0Q25mSmtPcThPM2crd1lSUXFZcU1YUXptWWJ0QnRINUV6VWlKRjFO
ZzJNMVhUdGhVaXNKb3d0QitDTWhqWmFZV0ZoT0J3ZUdCaG9hMnRURzhValhMaHdZZE9tVFg2
L0gwTzlsMFJkYm1SazVPalJvejZmcjdhMkZxdVg2YkE2YkR2d3h5aFN3RVF0aHUxc05rQ2tj
VVRPUk1VWVdXZExTT1kwSFUyRURkQ29DY052QnhDQk5scGpZNlBINHlGRmRacWFtbVN2MHFj
SW9TbFRwdHgwMDAyZmZmWVpobm92RXkvTVVHeXVrcEtTdFd2WHh1TnhyRlNtdytydzdaQ3dG
SWxpQVJNK2h1OXNOa0NrY1VUT1JENkc3MndKZ1hvdkFBQUE5Z0grUndvQUFHQWZRTk1CQUFE
c0EyZzZBQUNBZmNpY3Bxc051MnNNeHljY3I0ZWhmQUFBQUpiTS9VYXFXMzlCMDhWUnJES1Jz
QlFKLzFiYXI0QkpVckFGYzNqNFlqaE9LSStqWGJtbHVMaFljUzIrSThYajhZY2Vlb2lVcjdE
WitTdXJzNlNqUEE3ZnBDSnJ5VWhhMDRNb0tMdUJwcHNIdnNxRVNDa1N2aG50V3NCRUJGbkJI
QjYrR0k0VHl1Tm9WSGRaczJiTjQ0OC9ycmdXMzVGcWEydHJhbW9pa2NqSXlFZ0cwczRZc202
anJ6d09oVFpwVW1zUmpOTDBMVnUyZUR3ZWw4dEZQNDBSUWkrODhNS01HVE9LaW9xMmI5OU9O
OGl1cmxidmhkMXlaMmRuWldWbGZuNStiVzB0ZVluZkZ5QXJ3YUZkaWdTcGxPQ3dYd0dUaFBB
RmMzajRZamlPS284ajYxcGZmLzExVVZIUjZkT25OVlpoTzFKcGFlbmJiNytkaVVRemlGcTMw
VmNlUjdGSlJZcnFFSXpTOUduVHBnVUNnVWdrTWpBd1FOZmR0bTFiTEJacmJXMWwrejI3dWxx
OUYzYkxDeGN1Ykdob2lNVmlMNzMwRW5tSjM1ZkRrWlhYb0YvbHRFdVJ5RXB3Q0s1bE0vaUNP
VHg4TVJ6bmxNZmhLN2M4Kyt5enExZXYxbGhGMXBGY0x0ZUdEUnNLQ2dyS3lzcllLWmd0aldL
M1VUeURSTXJqOEUwcXNoYkZLRTEvODgwM2I3dnR0dm56NTArZlB2M1h2LzQxV1hkd2NKQnVo
OTBtZmF4Vzc0WGRjbTV1Yml3V3d4aEhvMUh5RXI4dko2TllYa093Rkltc0JJZjlDcGdraEMr
WXc4TVh3M0ZJZVJ5K2F3ME9EcGFWbFduWGhzTVRPMUpSVVZFb0ZCb1lHT2pvNkZBYmhiY2Nh
dDFHUjNrY3ZrbEYxbUl4ZGp4OWVIajR3SUVEQlFVRldGM0gyY2VLOVY1bXo1N05mdEF0V3JT
SStQVDYrbnAyWFhaZmpvV3ZNaUZlaW9RdHdXSFhBaWJpYVBScXZoaU9FOHJqS0ZadWFXeHN2
UGJhYXpYVzRqdlM3YmZmVGpYZGZwOS90TnZvSzQrRHVTWVZYSXZGS0Uwbm4xZWtjTUdMTDc2
SWxYUWNUUVJqckZqdjVROS8rRU5CUVFGOWV1alFvWXFLaXZ6OC9QWHIxN1BiWWZmbFdHUk5l
dkhpUmNWU0pMSzNqQVN6SlRqc1Y4QWtXZFJzQjFZcWh1T0U4amg4MThJWUwxMjZWRForSW1z
cnZpUDE5UFFzWGJvME56Zlg0L0UwTnpkbjhoQXlBRDE4ZmVWeE1OZWtpbXRwQS9WZUFBQUE3
QVA4anhRQUFNQStnS1lEQUFEWUI5QjBBQUFBKzJCMlRZZkJlZ0FBQUhITS9oc3BhSHFLSkZW
bGdsK0MxRXQ1MkJLUkxxMVczVVc3U296OUVPbGFmRnZadU42TE5pS0MyZHpjWEY1ZTduSzV5
c3ZMZCsvZVRaY24xYldTMXZTSUpMK0JwcHNaOFhvUmlrMnRVY3JEeG1qM09zWHFMZ21yeE5n
UGthN0Z0NVZkNjcwa1JLUnZ1TjN1dHJhMmVEd2VEb2ZwZktUSmRpMmpORjJ4M2t0dGJXMStm
djZDQlFzNk96c3h4dSs5OTE1VlZWVnVibTVWVlJXNXFQNmpqejVhdkhneFdZdHRpTE5uejk1
NDQ0MDdkdXdRUENxQUoyRzlDUDU5RkNubFlVdTB6eCsrdW90SWxSZ2JvOUcxK0xheVpiMFhF
WkJLVlNXVzZ1cnE5dmIyZ1lHQmZmdjJMVjY4R092cVdrWnB1bUs5bC9yNitsZ3MxdERRNFBW
Nk1jYVZsWlV2di93eStVZG9WVlVWeHRqbjgyM2R1cFdkU2hVaEZJbEVhbXBxT2pvNkJBOEo0
QkdwRjhHL2p3bExlZGdWN2ZPSHIrNGlVaVhHcm1oM0xiNnRiRm52UlJ4WlZTVVpuWjJkUlVW
RkNLR2lvaUpTSGtCSDF6SksweFhydlpBNkxiRllqQlFWY2JsY3RISkxibTR1eGpnM056Y2Fq
Y3IyV0YxZFhWSlMwdDNkTFhoSWdBekJlaEd5OTFHd2xJY3RTZWpUWmRWZFJLckUySktFWFl0
dksxdldlMGtLV1ZVbGxvcUtpbkE0SEkvSFE2RlFaV1VsMXRXMWpCMVBsOVY3SWE2OG9hRmg0
Y0tGV01tbmU3M2VyVnUzc3VVVkVVSm56cHpaczJmUHZIbnp5SmM0SUNuRTYwWEkzc2VFcFR4
c2pQYkpvMUhkeFZHQ0x0SzErTGF5ZDcyWGhMQlZsWGdLQ3d2RDRmREF3RUJiV3hzZFR5ZGsz
NmVUVHhWWnZSY3lubDVSVVhIbzBDR004Y0dEQnlzcksxMHVWMlZsSmVrWkgzendRWFYxTmZs
b2toMUpRMFBEMHFWTGlhOEh4RUVUVWF3eUlZc2hDL2xTSGs1QXNTbGt6YVZSM2NWUm1pN1N0
Zmkyc25lOUZ3MUlLN0ZWbGJDU2tmSjRQRVEybTVxYVpLc0w3c2dDYzljQkFBQUFnbVIvam1r
QUFBQWdYWmo5ZjZRQUFBQ0FPS0RwQUFBQTlzR01tZzZqTkFBQUFQb3c4RGRTa0dZejBOemN2
SERod3NtVEp5OVpzdVNkZDk1UmpPSGZSOGNXNWRCWHcwU3RBb3lkVU90SUlxVkkyQmhiZGkx
V0RNbEY5L3c1SmRKSmVGRVZPWDlsSkszcEVuY0RUVGN6SzFhc2lFUWk4WGg4OSs3ZGwxOSt1
VVlrKzM0NXRpaUh2aG9taWhWZ2JJWmlSeElwUlNLTHNYZlhrdFZIWWx0R3BKUHdMU2wrL2xL
TTBuUkZGNDhRV3I5K2ZVRkJRVTFORFZhcTkwSlhGRWtkRUNjV2l6VTFOUzFZc0VBamhtMTJ4
eGJsb0NSVnc0UmZZbGZZamlSU2lvU1BzWEhYNHVzanNTMGowa21RU2swWWtmT1hrbEdmamhC
Njdybm5vdEhvZ3c4K2lKWCtSNnEySXBBSzlDdmhoeDkrcUIxR0h6dThLRWV5TlV6NEpiWkUx
cEZFU3BId01UYnVXbng5SkxabHhEdUpyQ2FNNFBsTHliU21zOGFIci9laXRpS1FJdEZvZE5l
dVhZc1dMZEtJWVp2ZHlVVTVkTlF3NFpmWUZiWWppWlFpNFdQczJyVVU2eVBKZkxwNEo1SFZo
QkU1ZnlrR2F2cmt5Wk5sSlNWbGtlRFRNOEQ5OTk5Lzh1VEplRHplMU5RMFk4WU1qVWkyMlIx
YmxFTmZEUk9OQ2pDMlFhTWppWnl3Tk1hdVhVdXhQaExiTXVLZGhLMEpJMzcrVWd6VTlJY2Zm
amcvUDE4Mm5zNEc4UFZlMEVSRURnRFFKaGdNenBzM0x6YzNkOUdpUmVGd21DeVV0UzNmN0E0
dnlrRVJyR0dpVVFIR05paDJKSUxHT2M0dnQydlhrdFZINHM4cHhVNmllQ2F5TldFMG1sME5z
ODlkQndBQUFJaGp4djhjQVFBQUFQb0FUUWNBQUxBUG9Pa0FBQUQyd2V5YURvUDFBQUFBNHBp
OTNndG9lb3FJRkRCSnBaU0h6UkQ1MmQrWjlWNTRSTnFLVlFtMVFpaTJoRDlNa2NvdHpjM05I
bytIWEJ2VDA5T0RkWlhIU1ZyVEF4eWc2V1pHcElDSjdsSWVka1g3cUoxWjcwVU53UjZpVVFq
RnhyQ0hLVks1cGJpNHVLT2pZMkJnSUJRSzNYSEhIVmhYZVJ5ak5KMTM4WWk3aUxXbXBxYWpv
d05qM043ZXZuanhZcXhVQVlaRW5qMTc5c1liYjl5eFk0ZmdVUUU4R2dWTUNNbVc4ckF4Mmtm
dDVIb3ZQQ0k5UkxzUWlvM2hEMU83Y2t0eGNmSCsvZnVKcHBOL0dPa29qNU01bjg1citwWXRX
MWF0V29VeFhybHk1ZGF0VzdIU1Awc1JRcEZJaEtvL29BL3RBaVpZVnlrUEc2TjkxSTZ0OTZL
SVNBL1JMb1JpWTNnTlJKcVZXeG9iRzYrNDRvcXBVNmV1VzdlT2RDUWQ1WEd5b09tRGc0UGs4
Ymx6NTl4dTkvSGp4OTF1OTFkZmZZV1ZLc0FnaEtxcnEwdEtTcnE3dTBXT0IrQkpXTUNFa0d3
cER4dVQwS2M3dHQ0TFQ4THVrYkFRaW8zaEQxT3djc3VCQXdmbXpKbURkWlhITVZEVFpmVmVa
czZjdVcvZnZ2NysvcnE2T3JyS2loVXJycjc2NnBVclY1S25pajc5ekpremUvYnNtVGR2SHZs
NkN5U0ZTQUdURkV0NTJBL3RvM1ptdlJjMUV2YVFoSVZRYkF4N21JS1ZXMFpHUm80ZVBlcnor
V3ByYTdHdThqZ0dhcnFzM2t0OWZiM2I3WjR4WThiV3JWdnB3dmIyZG9SUWUzczdlYXBZQVlh
ODFORFFzSFRwVXVMaUFYSFFSQlFMbUFpVzhuQUNzdWFpQzlrWVo5Wjc0UkZwS3l4UUNNV1c4
SWNwWG5tcHBLUms3ZHExOFhnYzZ5cVBBL1ZlQUFBQTdJUFovM01FQUFBQWlBT2FEZ0FBWUI5
QTB3RUFBT3hENWpRZGh0MEJBQUNNSm5PL2tZS21ad0QrSGRGWFpjS1pCVXl3MHYrZmVaeFo3
NFZ2RnZIVG43MDZ6cFlYVnZCbkdkOGwrTE5NWkRzaTlacGtKSy9wZGR3Tk5OMWtzRTJ0cjhx
RVl3dVlpUFJTSjlkNzRkc25ZWXNwRmc2eW1ScndaeG5mSmZpelRIQTdDZXMxeVRCSzAyV2Y1
K1QraFJkZW1ERmpSbEZSMGZidDJ4Vmp5SVAxNjljWEZCVFUxTlRnc1UvMTNOemM2dXBxS0E4
Z0NQK09KRnRsd3JFRlRCQkNicmU3b0tEZ2xsdHVrYzJRVG5GeXZaZGtOVjJ0Y0pETk5KM0Fu
bVdLblVSMmxvbHNoNUt3WGhNbG81cStiZHUyV0N6VzJ0cEtEbEpOMDU5NzdybG9OUHJnZ3cv
U1Y0ZUdoZzRlUERoNzl1eUVHUUk0SFZVbW5GekFCR044OXV6WjJ0cmFaY3VXS2I3cTVIb3Z5
V3E2V3VFZysybTY3Q3pqdXdSL2xvbHNoNUN3WGhPTDRacE9xN3NnaEFZSEI5bFgrUml5a1Aw
czJyWnRtOGZqSWVWSGNuSnlSQTRKNE4rUlpLdE1PTG1BQ2FHL3Z6OHZMMC94SlNmWGUwbFcw
OVVLQjlsUDAvSEVzMHlqUzlDelRHUTdXTGhlRThVb1RlZXJ1L0R2cUdJRkdOblc4dlB6VzF0
Ylk3RllLQlN5WlQ4d0FyYWg5RldaY0hJQkU0enhoUXNYTm0zYTVQZjdGVjkxY3IwWEhlUHBp
bUUyTzVmNXMweXhTOGpPTXBIdGlOUnJrbUdVcHZQVlhYaE5WNndBSTl2YVUwODk1WGE3M1c3
M3M4OCthN04rWUFSb0lsaHZsUWxuRmpEQlkwMHhaY3FVbTI2NjZiUFBQcU1MMlJobjFudmh1
eGEvQkt1TE5SdWc2Tnd0RFgrVzhWMkNQOHV3UU9VbFdYT1JlazNhUUwwWEFBQUErd0QvSXdV
QUFMQVBvT2tBQUFEMkFUUWRBQURBUG9DbUE0Q3BnZCtyZ0tRQVRRY0FCWFFyYWRvbFdHT0Rh
ZGtYUXVpNTU1N0RHUC8ydDc5TlpZTUlvYzJiTjZlZUdGL2hwTG01dWJ5ODNPVnlsWmVYNzk2
OVcyM3ZzdXMxNHZINFF3ODlSTW9TcU9YRFYyVVJ1ZlNEejFDazRJL0lXdnl1ZFZ5SEFwb09B
QW80U3RNckt5dEhSa1lXTEZpUW9xWlhWRlJjdUhBaHhjVDRDaWR1dDd1dHJTMGVqNGZEWWJm
YnJaMERmVnhiVzF0VFV4T0pSRVpHUmpUMkphdktJcEk1bjZGSXdSL3h0ZmdjUU5NQklGVVV6
eXMwc2ZUUWxpMWJQQjZQeStXaVRrckU1Y2xjR0xtdnJhM056ODlmc0dCQloyY254cml6czdP
eXNqSS9QNysydHBiZE1ydDNmbDlIang2OTVwcHI4dkx5NXMrZlQydHdKcFFEaE5CMTExMjNh
ZE9tNjYrL25nUy85OTU3VlZWVnVibTVWVlZWZEZwZ1diRW14ZTBFQW9IZi9PWTNkS2Y4ZG1w
cWFrank3ZTN0aXhjdjFrNk1WamlwcnE1dWIyOGZHQmpZdDIrZjlscnN3WmFXbHI3OTl0c2FB
VmlwS2d0U0t2aWoxb1kwdzZRSy9pUmNDelFkQU5LUDJsbkVsaDZhTm0xYUlCQ0lSQ0lEQXdN
SlYxUU1vSHBkWDE4Zmk4VWFHaHE4WGkvR2VPSENoUTBORGJGWTdLV1hYbUxqWllXUFpQdGFz
bVRKcTYrK0dvL0gyOXJhNXMrZkwzNmtPM2Z1bkRScDBxNWR1OGdHS3lzclgzNzU1VmdzVmw5
ZlgxVlZoWldLTlNsdTUrTEZpMWRlZWVYWFgzK3R0cDB0Vzdhc1dyVUtZN3h5NWNxdFc3ZHFa
TVZXT09uczdDd3FLa0lJRlJVVmRYVjFhUjhMZmV4eXVUWnMyRkJRVUZCV1ZzWk9jczJpVnFo
SHUrQVBuNkY0d1IrUnRVRFRBU0Q5OEdjUlgzcm96VGZmdk8yMjIrYlBuejk5K3ZSZi8vclhh
aXVxYlprdGhSU0x4VERHc1ZpTUZKbkp6YzBsUzZMUktJbFJMSHdrMjFkdWJpNTE3dUxGa2Zq
UEdKZkxSZmVlbTV1TGxZbzFxVzNubVdlZStkV3ZmcVcyblhQbnpybmQ3dVBIajd2ZDdxKysr
a290SlZtRms0cUtpbkE0SEkvSFE2RlFaV1dsNExFVUZSV0ZRcUdCZ1lHT2pvN2k0bUxGZUky
cUxCb0ZmL2dNQlF2K0NLNEZtZzRBNlljL2k5UktEdzBQRHg4NGNLQ2dvSUE4blR4NXNscVJY
b0ppS1NUaVp4c2FHaFl1WElneFhyUm9FZkhwOWZYMUpFWng3N0o5K2YzK2xwYVcvdjUrM1Vl
cTRkTTFXb1pkSG8xRzU4NmRxN1lkalBHS0ZTdXV2dnJxbFN0WHF1WERWemdwTEN3TWg4TURB
d050YlczaTQrbTMzMzQ3MVhRMW5WVXIxS05kOElmUFVLVGdqL2hhb09rQWtIN1FSTEJTNlNI
eTBxUkprK2JPbmZ2aWl5K1NGUjkrK09IOC9IeU5rMUN4RkJJWlQ2K29xRGgwNkJERytOQ2hR
eFVWRmZuNStldlhyMWZiTzcrdlk4ZU8zWFRUVFdRSlhhaGpMT2pnd1lPVmxaVXVsNnV5c3BL
T3B5dkdLMjVuOCtiTmF0dkJHTGUzdHlPRTJ0dmJOZkpodVhqeFltTmpJL21PTW5mdTNLYW1K
cEcxTU1ZOVBUMUxseTdOemMzMWVEek56YzJLeWF0VlpkRXUrTU5uS0ZMd1IyUXQvaWo0SlFr
QlRRZUFMSk9VQ3dNQWJVRFRBU0RMZ0tZRGFRUTBIUUFBd0Q2QXBnTUFBTmdIMEhRQUFBRDdB
Sm9PQUFCZ0gwRFRBV3ZRMHRMUzJ0bzZORFRVMnRyYTB0SWl1SXIycTJvQjBXZzBGQW9weG11
c0JRQm1BRFFkc0FZdExTM3Z2dnZ1WC8vNjE3Lzg1Uy9wVWxXMTdYejAwVWY4U3lEbGdDVUFU
UWVzUVV0THk3Rmp4OExoOExGang2aTh5aDYwdExSMGQzZUh3K0dqUjQrcUxaUnRrOS9SaFFz
WDJ0dmJGVFU5SEE3djM3Ky90N2MzclVjR0FPa0VOQjJ3QmkwdExlZk9uYVAzZENIN29LV2w1
YXV2dm9wR28yVE9kY1dGc20zeU8vcmdndzk2ZW5vVVh4b1pHZW50N2QyM2IxLzZEZ3NBMGd4
b09tQU5XbHBhUmtaRzNucnJyWkdSRVNxNDRYQTRHbzFTbGVjbG5sOG8yNmJpanRUR3pVZEdS
czZjT1FPYURwZ1owSFRBR3JBS1N4OGZQWG8wSEE1M2QzZnIwSFNaY1BPdjhnOWFXbHIyNzkv
LzVaZGZwdlBBQUNDdGdLWURBQURZQjlCMEFBQUErd0NhRGdBQVlCOUEwd0VBQU93RGFEb0FB
SUI5QUUwSEFBQ3dEK09hM3RuWnVSTUFBQUN3UGdnRUhRQUF3RGI4LzFETSs3NmVBZ3hWQUFB
QUFFbEZUa1N1UW1DQyIgLz48YnIgLz4mbmJzcDs8L3A+PHA+SW4gdGhlIG5leHQgcGljdHVy
ZSB5b3Ugc2VlIHRoZSBvdXRwdXQgb2YgeGVucG0gdmlzdWFsaXplZC4gU28gdGhpcyBtaWdo
dCBiZSBhbiBpbmRpY2F0b3IgdGhhdDwvcD48cD5yZWFseSBzb21ldGhpbmcgaGFwcGVucy4g
SXQmIzM5O3Mgb25seSB0aGUgY29yZSB0aGF0IEkgZGVkaWNhdGVkIHRvIHRoYXQgRG9tVS4g
SSBoYXZlIGEgdGhyZWUtY29yZTwvcD48cD5BTUQgQ1BVIGJ5IHRoZSB3YXk6PC9wPjxwPiZu
YnNwOzwvcD48cD48aW1nIGFsdD0iIiBzcmM9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJP
UncwS0dnb0FBQUFOU1VoRVVnQUFBZkVBQUFFa0NBSUFBQUN3bzUrMkFBQWdBRWxFUVZSNG5P
MmRhM1JVVlpyM043a1pBcWFTUUJpQ1VDRmdTSUNBWW1nRVdtM2FHVHM5UFRSZUFycG93T25W
MHpockFJMEdkSTJqaTZZQnRVVUgydVlpTFNPR1lCUk1WUzRJZ2tZa2FiVVg0U1pta1lBaEYw
RXVxVXV1Kzh1c05SL3EvYkRmUG4wNGw2cGRweTduOXYrdFo1MXpzcyt1dmYvbnFWTlBudXlx
UEVXK0FRQUFZQWthR3h1SjNob0FBQUJFZ2NiR3hyMTc5LzcvbUU0QkFBQ1ltYjE3OXlLbUF3
Q0FSVUJNQndBQTY0Q1lEZ0FBMWdFeEhRQUF6RVMxRFBGWnhIUVFWd2doa2dPRGMvVG8wZkhq
eHh0VHJSRlVHVUdEUFJrYUdtTFJIREVkeEFPMWwzcFVZbm84NDBoeGNmSEJnd2ZqTmwxWUdD
R2VHa0dERFJrWUdEaDkrclRMNWJwKy9YcE5UWTM0RkdJNm9HZlBubDIwYUZGbVptWktTc285
OTl5emYvLysyTTJsTGFickdEaFNVMVA3K3ZwaU5IaE5UYzFQZnZLVDFOVFV6TXpNSjU1NG9x
dXJLNnlIR3lHZUdrR0QzV2hyYXp0MDZGQlRVMU43ZTN0TlRjM3AwNmZGWnhIVDdjNzU4K2Yv
NFIvK1lkdTJiVmV1WFBINy9TZE9uSGo0NFlkak41M3BZbnBNcDM3d3dRZmRibmRQVDA5WFY5
ZktsU3QvOHBPZmhQVndJOFJUSTJpd0cxOTg4Y1gxNjlmVnppS20yNTNISDMvOEQzLzRnK0lw
UXNpbVRadXlzN1BUMHRLV0wxL3U5L3VGZGtrM3hjZXlBNy9mdjJ6WnNyUzB0REZqeG16ZXZG
a2Uwd2NHQnNyTHkwZVBIajE4K1BEUzB0S2JOMi9LaHhLUVBKWVFzbTNidHR6YzNKU1VsS2xU
cDM3MjJXZTdkKytlUEhseWNuTHl6Smt6VDU0OHlUa0ZwZFRuOC8zcnYvN3I3YmZmZnZ2dHQv
LzYxNy8yK1h5S1V3djA5Zld0V2JObTFLaFJEb2ZqbFZkZWlkeGpIby9udHR0dWs3Y0hRWEc2
K2ZQbnYvZmVlMEtmdHJhMnNXUEhpa05BWGw3ZXFWT24yUEh1M2J2WndhbFRwL0x5OHFpNnI5
VGFoV3Y1eTEvK01tN2N1TmRmZnoyc1N3QlJCekhkN293Wk0rYnk1Y3VLcHdnaEpTVWxYVjFk
WFYxZEpTVWx6ejc3ck5BdTZhYjRXSFpRVmxiR0J1bnM3SHpvb1lma2NmbmxsMTkrOE1FSEwx
MjZkUFBteldYTGx2MzJ0NzhOTXBya1IwTElva1dMTGw2ODZQRjRmdmU3MzQwY09mTFJSeDhW
ZnZ6UmozN0VQOFV6enp3ajZQeW5mL3Fuc3JLeUlGZEhLVjIzYnQwLy91TS9YcnAwNmRxMWE2
dFhyNDdjWXdjT0hMai8vdnNWNTFKRGNicmEydHFDZ29MQndVSFc1OGtubjl5NGNhUDRVU3RY
cnR5MmJSdWw5TktsU3lOSGptVFJlZXZXclU4OTlSUlY5NVZhTzd1VzZ1cnEwYU5ISHpod0lD
ejlRQnY0M0FzSVJsSlNVbjkvditJcFFzaTMzMzdManMrZlAzL0hIWGNJN1pKdWlvOWxCK1BH
alJNRytlYWJiK1F4M2VsMG5qdDNqaDEzZG5hT0dUTW15R2lTSHdraFY2NWNZY2NlajBmeVkx
SlNFdjhVT1RrNTU4K2ZGM1NPR3pjdXlOVlJTdSs0NHc3NVMwYXp4NzcrK3V2YzNOeHdYNE5x
MHhVWEY3Lzc3cnRDbzhmakVUL3E0TUdEcGFXbGxOS05HemVPSGoxNng0NGRsTkxISG52c280
OCtvdXErVW1zbmhQejNmLzkzVGs1T1kyTmpXT0pCaE9CekwwQ1o0SG42d01BQU8rN3Y3eGRD
WkZneFBURXhVVHlJUEtZbkpTV0psemlHRFJzV1pEVEpqOEdWaERXRlJLZmF4WXI3eTM4WGF2
UFlKNTk4TW1IQ0JMV1lxTGI0RTJTNkF3Y081T2ZuRHd3TUxGbXk1STAzM3BBOHFxZW5aOEtF
Q1pUUzZkT251MXl1ZSsrOWwxSTZZY0lFRnZyVmZLWFdUZ2laT0hIaTJyVnJGY1dER0lIUHZR
QlZIbi84OFMxYnRpaWVFcWVCMzM3N3JaQzZKaVVsQ2FuZmxTdFgrUFAwOCtmUHk4UHgrUEhq
di92dXUrQWlJNHpwUEZQazVPU0kvNTdJeWNsUkhGTWdaSjdPNmJHS2lvcWNuSnltcHFiZzho
UlJtMjVvYUdqNjlPbGxaV1ZPcDdPM3QxZit3UHZ2djMvZnZuM0Z4Y1dVMHVMaTRnTUhEanp3
d0FQc2xKcXYxTm9KSVpjdVhabzBhZExtelpzMVhBTFFBRDczQW9KeC92ejVzV1BIL3VsUGY3
cDY5YXJmNzI5c2JCUSs5MElJK2VkLy91ZnU3dTd1N3U2Zi8vem53aEx6ckZtelhucnBKWS9I
ODkxMzN6M3l5Q01oMTlQWklHek5WeDZPZi9lNzM1V1VsTFMwdFBUMzk1ODhlWkl0QzBod09C
ekNILzQwL0pqT004V2FOV3VFdGVtSEhucm82YWVmVmh4VDRQbm5uMWRjVHcvTFk2KysrdXFF
Q1JQT25EbWpPRVZJMUthamxGWlVWQkJDZHU3Y3FmakFqUnMzamhzM2pxWHdXN1pzdWVPT096
WnQyc1JPcWZsS3JaMWRTM3Q3ZTM1Ky9vWU5HN1JkQ0FnTGZPNEZoT0RNbVRPLy9PVXZIUTVI
U2twS2NYR3g4UGwwOGNjcWxpMWJ4ajRLUWluOTZxdXY3cnJycnFTa0pLZlR1VzNidHVBeDNl
ZnovZXBYdnhvK2ZIaDJkcmJpNTE0R0J3YzNiTmpnZERxVGs1T25UWnRXVVZFaEgyMzkrdlVq
Um95UVA1WXpwdk5NNGZWNlY2eFlNWExreUpFalI2NVlzY0xyOVNxT0tkRFgxN2RxMWFyTXpN
eU1qSXpYWG50Tm04ZUlqSjZlSHNYcEZGR2JqbEs2Zi8vK3laTW5xNzFUOHZYWFh5Y2xKWFYz
ZDFOS3U3cTZrcEtTL3ZyWHZ3YjNsVnE3Y0MwZEhSMEZCUVV2di93eXYzNFFDeERUZ1NwcTRR
eW9ZUnlQL2VJWHY5aTdkNi9lS2tCTXdPZGVnRWFNRTZITWdoRThOamc0dUgzNzlzTENRdUhq
ak1CaVNJSTRZanJneFFnUnlsd1l3V09FRUtmVGlVOFdXcGlhbWhxaFhrVmZYeDgrOXdJQUFD
YW1zYkh4MUtsVC9mMzkvZjM5cDA2ZGtueG9DakVkQUFETWhNL25PM0hpaE52dGRydmRqWTJO
NHZmR0tXSTZBQUNZR3F5bkF3Q0FkVUJNQndBQUUyT2p6eksySERuU2N1U0kzaW9BQUNCK1dE
YW05L3Y5VytmTjJ6cHZYdi9maWxZREFJRGxzV3hNLyt6MTF6YzRuUnVjenM5UWxSOEFZRmNz
RXRPdlg3cTBPVCtmeGZUTitmblhMMTNTV3hFQUFNUUVyOWZiMk5nb2ZKWlJxRTNFc0VoTXIx
eXhnZ1YwWnBVclZ1aXRDQUFBWWtKRFE4TzVjK2Y2K3ZyNit2ck9uajNiME5BZ1BtdVJtTTU0
NFlVWDJFRjdlenRQL3o2K0dxYzhvM0hPeU5NTnF2aTdRUlYvTjJPcW9uekNvamlqTVZXRmhj
dmxFb3I1REE0T3Vsd3U4VmxyeHZRdnYveVNwLytOSFR0NHV2R014amtqVHplbzR1OEdWZnpk
akttSzhnbUw0b3pHVkJVV3RzalQrL3I2V2x0YmYvT2Izd1FDZ2M3T3p2LzkzLy90N094a3gw
RzI3ZWZPaGV6RE9Scm5qSmN1WFlJcXFJSXE4ZmIvdk41NHptZ2NWZDk5OTExcmE2dUdMTjdq
OFZoL1BaM3h3Z3N2QkFLQlFDRFEwZEVSNElBMk5mRjA0eG1OYzBhZWJsREYzdzJxK0xzWlUx
V0FUMWdVWnpTVXFsaUVRV3ZHZEFBQU1EN2FBcDB0UHZmQ1FKNnVvUTluTjZqaTd3WlZZWFZE
bmg0dTVsaFBGNzZQVVdpcHJLd3NMQ3hNVGs2ZU1XUEdvVU9IS0tYZmZmZmQzTGx6VTFKUzVz
NmRxL2dWNXNqVEFRQW1RbHUwTk5QblhzUXgvZEZISDIxdWJ2YjVmRHQyN0JnMWFoU2xkUEhp
eGVYbDVUNmZyN3k4Zk1tU0pmS0hJMC9YMEllekcxVHhkNE9xc0xvaFR3OFhjK1RwRE1Xdi9t
cHRiWFU2blpUU1VhTkdkWFoyVWtvN096dFpsSmVBUEIwQVlDSzB4VWt6ZmU1Rkh0TTdPanBt
elpwMThPQkJTbWxDUWdMN2kyTmdZQ0F4TVZIY2JlREtsUnR2dmJWdTVVcDY0a1FnRU9nOGVE
QVFDTERqSUZ2YTFCU3lEK2RvbkROMmRIUkFGVlJCbFhqcmUvdnRlTTVvSEZYLzUvZmZlT3V0
M3VibTZFWlJROGYweHNaR3A5TzVaODhlOW1OV1ZoYnlkQUNBWmRBV0o4MVVQMTBjMDdkdjM1
NmRuVjFYVnllMGxKYVdDdXZwcGFXbDhvZGpQVjFESDg1dVVNWGZEYXJDNm9iMTlIQ1JCSEVK
Um9ucDVGYmtMVDA5UFJjdlhwd3paMDV5Y3ZLOTk5NTdTYW55SXZKMEFJQ0owQll0elJIVG93
THlkQTE5T0x0QkZYODNxQXFyRy9MMGNMRmpUQWNBQU9NVGl6Qm96WmlPUEoyL0QyYzNxT0x2
QmxWaGRVT2VIbDBzRXRNbGRSbXh4UlpiYkEyKzFWYVg4ZkRodzgzTnpaMmRuUU1EQTRvZExC
TFRHY2pUTmZUaDdBWlYvTjJnS3F4dXlOUEQ0c2FOR3kwdExjZVBINitwcVRsKy9IaExTOHVO
R3pmRUhhd1owd0VBd1BoRUV1NzYrL3M3T3p1Ym01c1BIejRzYnJkbVRFZWV6dCtIc3h0VThY
ZURxckM2SVUrUExrYUo2Zks2alBJVzFHVUVBRmlKV01SU284UjBocnplaTdnRmRSbkRIUXFx
K0llQ0t2NmhrS2VITlpSTjgzUkc4SmlPdW93QUFDc1JsYkJwbW5vdjhoYlVaWVFxcUxLWXFn
RHFNa1pjbDlIRU1SMTFHUUVBVmtKYm5EUnJYVVo1QytveWhqc1VWUEVQQlZYOFEyRTlQYXlo
WXIyZWJ0Q1lIckl1STZVVWRSa0JBRllpS3NIVG9ERTlLaUJQMTlDSHN4dFU4WGVEcXJDNklV
K1BMdGFNNlFBQVlIeTBCVHF2MTJ1YTd5T05FT1RwR3Zwd2RvTXEvbTVRRlZZMzVPbmgwdERR
Y083Y3ViNit2cjYrdnJObnp6WTBOSWpQV2lTbW95NGp0dGhpYTY2dHRycU1sRktYeThVKzFV
MHBIUndjZExsYzRyTVdpZWtNNU9rYStuQjJneXIrYmxBVlZqZms2ZUZpaXp5ZGdmVjBBSUNK
MEJib1BCNFAxdE5WSEdySXpBV3ErTHRCRlg4M1k2b0tJRStQTmthSjZUeFZHRkdYRVFCZ0pi
UkZTN1ArSDZtOENpUHFNb1k3RkZUeER3VlYvRU1oVHc5cnFLam42U3lJQzZIY05ERmRYb1VS
ZFJrQkFGWkNXNXgwdTkwM2I5NTB1VnczYnR5NGNlTkdiVzJ0K0t4eFk3cThDaU5QWGNaSFRv
d25BYkxtNEZ3U0lPdzR5SFpSMC9pUWZUaEg0NXl4cUtNSXFxQUtxc1RialcvUGpPZU14bEds
dVM3anFWT25hbXBxMnRyYURoOCs3SGE3TDF5NElENXIzSmd1cjhMSVU1ZVJCQWdNQm9NWjN6
VG42Y0V4Ymt5WFYySGtxY3ZJbkZYVVVjVGowMFZONDNtNjhZekdPU05QTjZpQ0t2dW80aFFX
eFJtTm8wcHpURGZIZTZROFZSaDU2akx5dUJnR2c4RjBOMXZrNlJHQ1BCMnFvTXBjcWppRklV
L254NW94SFFhRHdReHVpT21oUVo0T1ZWQmxMbFdjd3BDbjgyT1JtQzdVWlNRQk1yMXpPcmJZ
WW91dHdiZWE2ekxhcTM0NmlmYXZZczdSTEo5UFFSVlV4VUlWcHpEazZXTHNWWmVSeDhVd0dB
eW11Mm1PNmZhcW44NmNoVHdkcXFES0ZLbzRoU0ZQRnhPRlBIMzM3dDJabVptWm1abnZ2UE9P
TmhFYWNMbGNreVpOU2tsSmVlQ0JCOWkvai9MVVplUnhNUXdHZytsdW1tTzZ4dnJwZnI5Zk9N
N0l5R2hxYW1wcWFzck16TlFtUWdQWjJka3VsOHZ2OTd0Y3JxVkxsMUsrdW96TVdjalRvUXFx
VEtHS1V4anlkSDVVWS9xRUNSTjI3ZG8xTURCQWRZcnBvMGFOY3JsY3ZiMjlMcGRyOU9qUmxL
OHVJNCtMWVRBWVRIZUxkMjJBaG9hRytmUG41K2ZuNzl1M2IrZk9uUmtaR1JrWkdidDM3OVlt
UWdOVlZWVVRKa3dZUG56NHFsV3JrcEtTS09veVFoVlVXVTRWUVYzRzhPc3lSbFEvM2UxMjMz
MzMzVE5uenBTOHRScFBYQzZYMCtta3FNc0lnOEVzWkpIazZWUkRUQmZlRi8zem4vKzhiOSsr
L1B6OHVYUG5IanQyVEpzSWJRd05EWjArZmJxd3NQRDN2Lzg5UlYxR3FJSXF5Nm5pRkliMWRE
RWFZM3BtWm1aalk2T3doajR3TUxCejU4NEpFeVpvRTZFQlZxQng3Tml4Ly9WZi84V1dYRkNY
RVFhRFdjYWk5UjRwYjB4WGZGOVUvR0VZQTRJOEhhcWd5bHlxT0lVaFR3OENiMHpmdFd0WC9O
OFhqUkRrNlRBWXpDeG04ZS9FaUFySTA2RUtxc3lsaWxNWTh2UWdXRE9tb3k2ajNiYWQwL1hY
Z0MyMmtXdzExMldVWU0yWXprQ2ViaDlWQVdKRVZjYjBsWkZWY1FwRG5zNlBOV002ektURzlw
dzlkVmNMZzBWaVdFOFBEZkowczZ0aWU1NmhBc2pUTGFHS1V4anlkSDVDeFBTR2hvYjgvUHho
dzRaUlNwOTQ0b21LaW9wWWlGQ2txcW9xTHk4dk1URng0c1NKVlZWVkZIVVpiV0JzejlsVGQ3
VXdXQ1NtVDU1KzU1MTMxdGJXRWtJb3BSY3ZYc3pOemRVbVFnUHA2ZWx1dDV2VlpYUTRIQlIx
R1cyZ2l1MTVoZ29nVDdlRUtrNWh5Tk1sOVBiMkhqdDJyS2FtcHJ1N1czSXFSRXhQVGs3Misv
MHNwbCs5ZWpVdExVMnppSEFwS2lweXU5MnNMdVBNbVRNcDZqTGF3TmllczZmdWFtR3dTRXh6
VEdjQi9keTVjei84OEVOZFhkMzE2OWZGWjBQRTlBVUxGdXpldlpzUTB0N2Uvc1FUVHl4YXRF
aWJDQTJjT0hFaVBUMmRFSktlbm43aXhBbUt1b3cyVUJVZ2hJN25VaFVnZHZlVk5WUVIxR1VN
dnk3ajBhTkhoWEI5K2ZMbFE0Y09pYytHaU9udDdlMExGeTVNUzB0TFMwdGJ0R2pSOTk5L0gr
NzBtcGs4ZWJLdzluTG5uWGRTMUdXMGdiRTlaMC9kMWNKZ2taam1QRjBTcXk5Y3VDRCswYmlm
ZThuSXlCRFdYbGpOR2RSbHRMd3F0dWNaS29EMWRFdW80aFNHOVhReEViMUh5bGJTMVg2TUta
V1ZsVTZuTXpFeE1UYzM5LzMzMzZlb3kyZ0RZM3ZPbnJxcmhjRWlzWGpYMm1XSWcvaUZDeGZp
K1I2cEJwQ25tMTBWMi9NTUZVQ2ViZ2xWbk1LUXA0dlJHTk9KakxTMHRMVnIxMm9URVIrUXA1
dmQySjZ6cCs1cVliQklUUDg4M2ZnZ1R6ZTdLcmJuR1NxQVBOMFNxamlGSVUvbng3anZrWVlG
NmpKYVk5czVmWHFBOFBiVVhTMjIyRWF5MVZ5WE1hTDNTQThlUEppYm16dHMyREJoQlVaNzNJ
MDl5TlBOcm9ydGVZWUtJRSszaENwT1ljalQ1UXdORFVrV1lSZ2hZbnBPVHM3Um8wY0pJVGR2
M2x5OWV2WExMNzhjaVloWWcvVjBzeHZiYy9iVVhTME1Gb2xGRXRNSEJnWk9uejd0Y3JtdVg3
OWVVMU1qUGhWNlBYMXdjREFoSWFHdnI4L2o4V1JrWkdnV0VRZVFwNXRkRmR2ekRCVkFubTRK
Vlp6Q2tLZUxhV3RyTzNUb1VGTlRVM3Q3ZTAxTnplblRwOFZudWQ0am5UeDVzc3ZsT25yMGFE
eGp1dmdqTjFsWldSUjFHVzFnYksvWUhySUZCak9YYVk3cFgzenhoYVRHaXhpdTkwZ1BIRGlR
bloyZG5wNitjK2RPYlNJaTRmang0ODgvL3p4RlhVWWJxR0o3ZWJlQVNreTNzNitzb1lwVEdQ
SjBma3p3dVplU2twTExseTlUMUdXMGdiRzlZanU1TmJJcmRvUEJUR1Q2eEhRZGF3TXdHaG9h
bGk1ZHlvNVJsOUh5cWdJcWRSa0Q1TzliY1U4Nys4b2FxZ2pxTW9aZmx6RTRScThOc0dEQmdx
Kysrb29kb3k2ajVZM3RGZHNsWjlWNndtQm1zWGpuNlVhb0RYRHMyTEg3N3J0UCtCRjFHUzJ2
aXUzbDNjUzl4QzEyOXBVMVZIRUt3M282UDRhdURYRC8vZmQvK09HSHdvK295Mmg1WTN1MWR2
Rlp0WjR3bUZuTXZ1K1I4b004M2V5cTJGN2VUZHhMM0dKblgxbERGYWN3NU9uOHFNYjBqejc2
cUtTa2hCMnZXclVxTFMxdDBxUkpmLzNyWDJNaElsb2dUemU3c2IxYXUzQldmQXlEbWRUaUhk
UG56WnQzOU9oUlNxbkw1Wm8yYmRxVksxYzJiZHIwMDUvK05CWWlvZ1h5ZExPclludWhXK0RX
ckZ3NEt4emIyVmZXVU1VcERIazZQNm94L2JiYmJ2UDcvWlRTMWF0WC8vNzN2NmVVWHIxNmRl
VElrYkVRRVRtb3kyaU5yYVF1bzNETTJ1VmJJMmpHRmx0dFc4MTFHWU9qR3ROSGpoeDU1Y29W
U21sSlNRbDdvOUxuODkxMjIyM1JuVDY2SUU4M3V5cTJGN29GbFBKMHNkblpWOVpReFNrTWVU
by9xakg5b1ljZTJyUnAwOFdMRnpNek03dTd1eW1sbjN6eXlZOS8vT05ZaUlnV1dFODN1N0c5
K0VkeHU5eDBGd3lEYWJaNHgvVFRwMC9uNStlbnBhVnQzcnladFpTVWxMaGNybGlJaUJiSTA4
MnVpdTJGYmdIazZWWlh4U2tNZVRvL3h2MHM0K0RnNElzdnZwaVRrOE8ra1lPaUxxTU5qTzNW
anVXbXUyQVlUTFBwR2ROMStjK2o5ZXZYVDVreXBibTVlV2hvaUxXZ0xxUGxWYkU5MjNVVUlV
KzN2aXBPWWNqVCtURnVUSGM2blpLbEh0Umx0THl4dmRxeDNIUVhESU5wTnR2RjlNVEV4Tldy
Vnc4ZlB0enBkQjQ0Y0lDaUxxTU5WQVZFZFJrN2lvcUVZOVl1MzlyWlY5WlFSVkNYTWM1MUdY
VmsxS2hSTHBmTDcvZTdYSzdSbzBkVDFHVzBnYkc5MnJIY2RCY01nMmsyMjcxSHVtVEpFcGZM
MWR2YjYzSzVzck96S2VveTJrQVYyN01kMXRQdG9JcFRHTmJUK1ZHTjZXKy8vZmJ5NWN2Rkxj
dVdMZHU5ZTNjc1JDalMzdDUrMzMzM0pTY241K1hsc1lWMTFHVzB2TEc5MnJIY2RCY01nMm0y
ZU1mMHZMeThscFlXY1V0TFM4dWtTWk5pSVNKYUlFODN1eXEyWnp2azZYWlF4U2tNZVRvL3Fq
RTlPVG01cjY5UDNOTGIyNXVTa2hJTEVkRUNlYnJaamUzVmp1V211MkFZVExQRk82WVhGQlEw
TkRTSVd6Nzk5Tk9wVTZmR1FrUzBRSjV1ZGxWc3p3NlFwOXRCRmFjdzVPbjhxTWIwZDk1NVor
TEVpWFYxZFY2djErdjExdGJXNXVibXZ2dnV1N0VRRVRtb3kyaU5yVkJ0TVVBVWpsR1hFVnNy
YmVOZGw1RlN1bi8vL3VMaTR0VFUxTlRVMU5teloxZFZWVVYzN3FpRFBOM3NxdGllM0pxbkJ4
bk16cjZ5aGlwT1ljalQrVEh1WnhrMWdQVjBzeHZiRTFFY0owRmp1dTZDWVRETmhwZ2VHdVRw
WmxmRjlnUjV1bTFVY1FwRG5zNlBjV002RWNGYVVKZlI4c2IyQkhrNnpBWm14NWd1YVVGZFJz
dXJZbnVDUE4wMnFqaUZJVS9ueDlBeC9mYmJiMDlMU3lzcEtXbHRiYVdveTJnRFkzdUNQSjNQ
VjdwcmdFVml0b3Zwaks2dXJyS3lzamx6NWxEVVpiU0Jxc0RmNmpMUzhYK3Z5NmhZa1RGZys3
cU1BV0pFVmVINmlxQXVZOXpxTXBKYmNUZ2NpeGN2L3Y3Nzc2TTdQUTllcnpjNU9abWlMcU1O
ak8wSjhuUStYK211QVJhSjZaeW5kM1YxclZ5NThwZS8vR1VzUkFUaDJyVnJMN3p3UW5GeE1V
VmRSaHVvWW51QzlYUStYeGxRbFladVdFK1BMbUdzdmR5NGNTTXRMUzBXSWhSaGZ4K2twcVl1
V0xEZy9QbnpGSFVaYldCc1Q1Q244L2xLZHcyd1NNeDJNVjBEeU5QTnJvcnRDZkowUGw4WlVK
V0dicEZreEFFUzlvekkwLzgvM2QzZEsxZXVYTGh3WVN4RVJBdms2V1kzdGlmSTAvbDhwYnNH
M2MzVVRvaDNUSmU4UjVxZW52N1lZNDkxZDNmSFFrUzBRSjV1ZGxWc1Q1Q25oK01yUTZuUzBB
MTVlblF4K21jWk9VRmRSbXRzVVpkUmc2OTBWNkxqMXRRZTBLRXVvK2xBbm01MlZXeFBrS2VI
NHl0RHFkTFFEWGw2ZEZHTjZaOS8vbmxoWVdGU1VsSmhZZUVYWDN3Umk3bWpEdGJUelc1c1Q3
Q2VIbzZ2N0d5bTlrQzhZL3EwYWRPMmJObmk4WGkyYk5sU1ZGUVVpN21qRHZKMHM2dGllNEk4
UFJ4ZkdVcVZobTdJMDZPTGFreFBURXpzN2UybGxQcjlmc2svNHNlVEYxOThFWFVaN1dOc1Q1
Q25oK01yTzV1cFBhREQ1MTRVaitOSlUxUFQyTEZqaGRsUmw5SHlxdGllSUUvbjloVnprWEZV
YWVpR1BEMjY4SDZXVVZMS1BBNzRmTDdwMDZjZk9YSkVtQlIxR1MxdmJFK1FwM1A3Q2s3UVhZ
TjI4WGI3TE9PcVZhdGVlKzAxS3ZvckFYVVpMYThxZ0xxTVlmb3FRSXlsS2x4ZmtjZ3FJTEk3
Skt3WjQ2Q0tjOFo0MTJYVW5XSERoa24rUGtCZFJzc2IyeFBrNmR5K2doTjAxNkJkZkp6ejlM
ZmZmbnY1OHVYaWxtWExsdTNldlRzV0lvSWo1T21veTJoNVZXeFBzSjdPN2FzQTF0T2pLbDV3
S2ZzTElLWitpSGRNejh2TGEybHBFYmUwdExSTW1qUXBGaUtDSThSMDFHVzB2TEU5UVo3TzdT
czRJVVplallOajR4M1RrNU9UKy9yNnhDMjl2YjBwS1NteEVCRXRrS2ViWFJYYkUrVHAzTDRL
SUUrUHFuamgwSUo1ZWtGQlFVTkRnN2psMDA4L25UcDFhaXhFUkF0NW5oNndkeFpqT21ON2dq
eWQyMWR3UW95OEdnZkh4anVtdi9QT094TW5UcXlycS9ONnZWNnZ0N2EyTmpjMzk5MTMzNDJG
aUdnaHhQU09vaUtlcDl5WW1ZdWRWYkU5UVo3Tzdhc0E4dlNvaWhjT0xaaW5VMHIzNzk5ZlhG
eWNtcHFhbXBvNmUvYnNxcXFxV0NpSUNwSzZqSUcvVld2cm5LNS85VFZzK2Jlb3l4aXVyMngr
aDBmRkEySlB4dlB1UWwzRzBJanpkT0hYSVlrc1FTQVd6ZklNcFVwNG1vU25MSUE4UFZRZjRk
QlFxalIwaXpCUEQ0VDVmVStLdDU4d2puQnN6VHpkZEFneFhldzZIcWZEOUxXQVVreVhIOHRO
ZCtYNk9nMU9pSW9IeEo0VW40bTVlTVQwa0NCUE42bXFBUEwwOFBzSWg0WlNwYUdid2ZQMEFK
RjJqcFlmYkJmVEt5b3E4dlB6azVPVFo4eVljZWpRSVJwT1hVYXg2M2ljRHRQUjJGNXlMSndu
eU5PRCtnMU9pTndEWWsrS3p3aG5KWjJqSnQ1dU1YM3AwcVd0cmExZXIzZmZ2bjFaV1ZrMG5M
cU15Tk5OcEVyOE5BbkhBVFBrNlFHVnV5dUtxb1JQY01sTk9BdzVGT3RqelB1S1U1alI4blFl
dDRjV2I3ZVl6dkQ3L2UrLy96NzdVZzcrdW94aTEvRTRIYWFqc2Iza1dEaFBESnlueDBGRGtQ
SDVuUkIxa2JwN1h1S0VxQXdTQ0NkUGo0b0g3QmpUV2ZXdWpJd005dVY1L0hVWk8rZk9EWWlx
MWhGVFZhcXptNm9BK1h0MXZZQ3A2aktLbGNmSVY1MXpJNjNMS1BTSmo2cHc3eXNTY1YxRzhX
dWNaMFpKSC9FZEpmYXFiK1pNd2MrUy9zSVdkUm0xd05aZVdKMFovcnFNOGwrMk1NTWEyMHVP
aGZQRURIbDY3TVFFR1ZiaUloNlIwYjN3U0FhTWlwaklaUkJackpEOEtKRXFQeHZSMUhiTDAx
ZXRXdFhkM2UzMWV2ZnYzejltekJnYVRsMUdyS2ViU0pYNGFSS09BNFpmVHhmYWlDeTR4SG85
WFQ0cHo3STd6d2V1K1ZXSnI1Y28vVlpqejJBUTVVS2o0SzZBK3E5MjRXYVFkeE1QSlg1MlF2
YVJkSkRNcUxpZUx1bU05ZlR3MkxWclYwNU9Ua3BLeWozMzNQUEpKNS9RY09veVNyekg0M2VZ
WHNiMmttUGhQQWthMDNXWExWY2JveWtVMjBPNklrYnVrZzhvSDErdFJjMUNkcEJmU0ZTZHJh
QkJtRVh4RXFMZ1JydkZkQTBvNXVsQnZHK2ZqRGo0TFlnOFhkSkhhRmJzRmxEL3JST3VyeFNu
RUh0RDRnU0pQTUhVOG5UeFQyeVpXTzI2Skg0SXlNS3grRmd0VDVlSVpLcUN5SllMVXpQSkt6
cVNia0g2aUVVaVR6Y0V5TlBWek1oT1lIdkpNZWVqWTZkSFBFWGcxcWdhVXBKY0lYK2Y0Qk54
ZWthaW1jZDdJYWNJTWxySUMrUlhycThSbGVkRjdxVkFOTzQ5eFBUUUlFOVg2eFA4RmpSeW5o
N2NvcTRxNUdBOHFuZ1NUODZob3BpZkdsTVZwekRrNmZ4WUpLYkw2ektpZXArazhwenVHb0pY
eFpNY0I5UnJNY2IwbWVXY0YxdExib2xTWFVhaFhmRXM2akxHRnVUcGFuMkNPRUZIVllLMkFQ
TDBDUHFZV2hXbk1OM3o5SURTeWd6eTlKaUQ5WFExTTdJVDJGNXl6UG5vR0ltQjJkT0krbnE2
MnRsSURERTlOTWpUMWZvRXZ3V1JweFBrNlRxcDRoU0dQSjBmNDhiMHlzckt3c0xDeU9zeUJn
eWNva3FmNDVoSk5iSVQyRjV5elBub0dJbUIyZE5JMER4ZDNqbENzMTFNZi9UUlI1dWJtMzAr
MzQ0ZE8xZ2xBTTY2akFIWnIySTFueG90VDJkU2thY1Q1T25oOURHMUtrNWhSc2pUNVoyUnAy
dWt0YlhWNlhSUzdycU1pdDQzaGNWT3FwR2R3UGFTWTg1SHgwZ01EQlpBbmg0ak9qbzZaczJh
ZGZEZ1FjcGRsekZBYnFuTEdLUTZvOUVxSUFhaVhUK1A5UWxabjlMSWRSa0RzbHFNNG0yTWZC
Vmt5Nk9LV2ZBK2luZXB0ajZtVmhVZ3hEZHpaanhuNUZjbGZsWEsrMFQrcXJkalhjYkd4a2Fu
MDdsbnp4NzJJMmRkUnNWZmlwSC9VbzJEeFVpbndUMGdsaWNjY3o0NlJtSmdzQUR5OUtpemZm
djI3T3pzdXJvNm9ZV3pMbU5BYWNsTTBhYzJXVThQZVF0aVBaMWdQVjBuVlp6QzRyT2VMbEhG
amdKWVQ0OFc1Rlo2ZW5vNDZ6SXFPcGJIOVhwWmdFZ1BvajYra1QwZ2xpY2NjejQ2Um1KZ3NB
RHlkQ05nMGp4ZGZOUEVRbFhJV3hCNU92bGJDZktRZzVrM0l6YW1LazVoeU5QNXNXWk1WM3dD
REd1QlcyTjZMTVkzc2hQRTJvUmp6a2RIVndiL3ZEQTdHTnNGa0tmckNQSjB4VDRoNzBKNzV1
bVNTUzJmRVJ0VEZhY3c1T244V0NTbWkrc3lxbFZjTTBJTlFyVmFnRUpGd0JpTmIrVDZsTHJV
WmVRY0gxczdiOFd2eWlqZWU4SVdkUmxEZ3p4ZHNVOXdKM0FPWmJFOFhkN0w4aG14TVZWeEN0
TXJUdy9TZ1NCUGp5cTRXS2dBQUJWRVNVUkJWQVBCMTlQRng0YXlBTmJUNDc2ZXJ2ZEZ3MHhn
SkZSTWo5QVEwME1UUEUrWFBCa0JYYjkxL3BhbkZuazY4dlFJK3BoYUZhY3c1T244R0RlbUM1
OU1GMW80NnpMeVBHSEVTQ1ZRQXNqVHRlYnBtaTlLNzR1R21jQ0lwanc5eUNscFQ3dkZkSVk0
cG11dXk2aG15TlA1aDRwZHRVaXhObkZIenR4VG15cDVMOHRueE1aVXhTbk1SSGw2UVBaQ1E1
NStDK0tZcnJrdVk1Qm54UWdXaUZlZWJxaXJWcnh3RGNORXhTY3dtQVpUYkZWclYraUptQjVK
WFVhMVNuVkdxTXNvVkNJTXhMSXVvM2hya0xxTUFWSEZPNkVsM0ZxRDJsVFpzQUtpTVZVRkRG
eVhNV1FmeGJ0ZC92cnFLRUpkUmhIaW1CNUpYVVkxQzZzM1ovK0FiSFU0K0RpQitPYnBNWm9s
UW1GcVVrTmFFTWZ5T3dRRzAyRHlKbmw3a1A3STA3bnFNakozaGJ1UXAvamNDTnVpRHRWdlRS
SU8rYXY2aWJzcFBrUll1UlpyRUxld0E1NjF2T0JmNlNMcHB1WUJ3VmRxZDYyNG5mbEswazE4
SVlJVFNLaVl6cjlHTEg4NkpLNFRxMUo3bWl5L2NtMU1WWnpDZEZsUEQ5bEhIQm5ZTHVTTTRo
TzJpK25rVmlpbFBIVVplWjZ0V0pqYTB4bTcwWWdzVnZMY1hzYThYa2lGMmRIc0Z0TTFvRGxQ
RDI3SXA2QUtxbUtraWxPWU1mUDBTRlVocG9kRXh6d2RCb1BCd2pQRTlKQWdUNGNxcURLWEtr
NWh5TlA1c1VoTUYrb3lCdlN1NVlZdHR0aGl5N05GWGNiUUlFK0hLcWd5bHlwT1ljalQrYkZt
VElmQllEQ2pHMko2U0pDblF4VlVtVXNWcHpEazZmeVlLYWJ6MUdYa2NURU1Cb1BwYjMrTDZa
VlBQbm50NHNWb3hVa3p4WFNldW96TVdjalRvUXFxVEtHS1U1aTE4L1FOVHVmbUtWTStlLzMx
ZnA4djhqaHBwcGpPVTVlUng4VXdHQXltdjRsaU9yTnRQLzd4dDRjUFJ4Z256UlRURmVzeW5q
MTdkdTNhdGVWcjFqeXpjT0ZQNTg5L2R0bXl0V3ZYL3ZiaGg5ZXVYY3VPZzJ6TEhuc3NaQi9P
MFRobi9QV3ZmdzFWVUFWVjR1M1RQL3RaUEdjMGppb1d0Wjc3elcvK0h0UG56Ly8yNDQ4ampK
Tm1pdWs4ZFJuWndZVUxGM2dHOUgzNktVODNudEU0WitUcEJsWDgzYUNLdjVzeFZWRStZVkdj
MFlDcTJOckxwMy80ZyszV1huanFNcktEM3Q1ZW5nRnY3TmpCMDQxbk5NNFplYnBCRlg4M3FP
THZaa3hWbEU5WUZHYzBvS3JLRlN1dXRiWHhETVdEbVdJNlQxM0dzQVljNk82T2tyUm9BbFg4
UUJVL3hsUkZqU3JNbUtwNE1GTk1EMGx6dEw4eEJBQUF6SVdsWWpvQUFOZ2N4SFR0VkZaV0Zo
WVdKaWNuejVneDQ5Q2hRMVQwUFI2R1VpVnZNWUtxaW9xSy9QeDhvNmxpdlBqaWl6bytpVUh1
SzBPcEdod2NmUEhGRjNOeWNvWU5HMllvWVdKM1pXVmxHVVJWVlZWVlhsNWVZbUxpeElrVHE2
cXFZamMxWXJwMkhuMzAwZWJtWnAvUHQyUEhEdkhuY1BTTjZYSlZhanIxVmJWMDZkTFcxbGF2
MTd0djN6NjlYbmlLbm1scWFobzdkcXlPVDZKY2xiNTNGRU91YXYzNjlWT21UR2x1Ymg0YUdq
S1VNSUhqeDQ4Ly8venpCbEdWbnA3dWRydjlmci9MNVhJNEhMR2JHakU5Q3JTMnRqcWRUdUZI
STd3Q3FVeVZZa3Y4a1dqdysvM3Z2LzkrVVZHUmpwS29TSlhQNTVzK2ZmcVJJMGVNOENRS3Fn
Z2h0OTkrZTFwYVdrbEpTV3RycTBGVU9aMU9sOHVscnhneDh0dTdwS1RrOHVYTGV1bGhDS3FL
aW9yY2JuZHZiNi9MNVpvNWMyYnNaa1JNajVTT2pvNVpzMllkUEhoUWFERkNPSkNya3Jmb3Jv
cjlkWnlSa2ZIRkYxOFlSTldxVmF0ZWUrMDFhb0FuVWY1OGRYVjFsWldWelprenh5Q3FFaE1U
VjY5ZVBYejRjS2ZUZWVEQUFSMVZVU1YzTlRRMExGMjZWRWRKOUZaVkowNmNTRTlQSjRTa3A2
ZWZPSEVpZHBNaXBrZEVZMk9qMCtuY3MyZVB1RkgzY0NCWHBhaFRkMVdVVXJiMk1tblNKSU9v
WWt2RHVpOWVxejFmWHE4M09UbFpGMGxVcG1yVXFGRXVsNHN0Sm93ZVBWb3ZWWEpoakFVTEZu
ejExVmQ2U2FJeVZaTW5UeGJXWHU2ODg4N1l6WXVZcnAzdDI3ZG5aMmZYMWRWSjJ2V042WEpW
YWpyMVZiVnExYXJ1N202djE3dC8vLzR4WThZWVJKV0FqaytpbXFwcjE2Njk4TUlMeGNYRmVv
aFNVTFZreVJLWHk4VVdFN0t6czNWUnBTaU1VbnJzMkxINzdydFBMMGxVU1ZWR1JvYXc5cEta
bVJtN3FSSFR0VU51cGFlblI5SmlURlU5UFQxR1VMVnIxNjZjbkp5VWxKUjc3cm5uazA4K2li
OGtSVlhpVTdwSVVsVEZEbEpUVXhjc1dIRCsvSG1EcUdwdmI3L3Z2dnVTazVQejh2SjBYRmhY
ZkJMdnYvLytEei84VUM5Smlxb3FLeXVkVG1kaVltSnVidTc3Nzc4ZnU2a1Iwd0VBd0RvZ3Bn
TUFnSFZBVEFjQUFPdUFtQTRBQU5ZQk1SMEFBS3dEWWpvQUFGZ0h4SFFBQUxBT2lPbkFPdWo0
b1hJQURBSmlldnpvN2UxZHMyYk42TkdqUjQ0Y3VYSGpScjNsbUJoQ3lLdXZ2a29wZmVXVlZ4
REhJNkc1dVprUWdpK1RpUkJEM1pDSTZmSGp1ZWVlVzdodzRlWExsNjlkdS9iMDAwL3JMY2ZF
RUVJS0NncUdob2FtVEptaSswdkkxR3pldkRraElXSHo1czE2Q3pFM2hyb2hFZFBqeDdoeDR5
VGZJQzUrK29WalFzaHp6ejJYbHBZbUZPVFUvUzR4R29TUWVmUG1yVisvZnY3OCtXSy9TZnk1
WmN1V3pNek1qSXlNSFgvN3ZtQjRVc0tDQlF1ZWZQTEpCUXNXc0I5bnpwekp2c0NodnI3K3Jy
dnVvcFEyTlRVVkZCU2twcWFXbDVlTFhhMlhZR01pdnlIWjNaaVVsQ1I4SjhiS2xTdC85YXRm
VVVxWExsMzYxRk5QQ1ErTXVoakU5UGlSbUpnNE1EQWdibEdMNmErKytxckg0L20zZi91M3VP
b3pENFNRdlh2M0ppUWt2UGZlZTRvK1pNZGJ0MjcxZXIwMU5UVjZmUk9Jd2ZGNFBDTkdqTGg4
K2ZLSUVTTThIZytsOUkwMzNsaXlaQW1sZFBIaXhXKysrU2FsdEtpbzZJOS8vS1BINDlteFl3
ZEN1UnBxTitUQXdFQkRROFBZc1dNcHBmMzkvUTgrK09DLy8vdS9QL2pnZy8zOS9iRVRnNWdl
UDRMazZmMzkvZUtZM3RmWEYyOXhwaUpJSEJjZkM2OGNCQ05GcXF1cmhTSlQxZFhWbE5LclY2
ODZISTRMRnk0NEhJNGZmdmlCVXBxVWxPVDFlaW1sWHE4WGJsUkRmaE51M2JyVjZYUW1KQ1FR
UW9ZTkc4Wk9OVFUxRVVLYW1wcGlLZ1l4UFg2VWxaVXRYTGl3bzZQait2WHJaV1ZsbE5KUm8w
YlYxZFg1Zkw1dDI3YmhEMXQrT0dPNjRqRVFlT3FwcDloNzlSczNiaFJXQTBwTFMrKysrKzdG
aXhlekg2ZFBuLzZuUC8zSjYvVysvZmJiY0tNYThwc3ROVFcxcHFiRzYvVzZYQzdXNHZWNlo4
eVlVVkpTTW1QR0RKL1BGenN4aU9ueHcrLzMvOGQvL01lb1VhT0V6NzFzMzc3ZDRYQmtabWEr
K2VhYlFXSTZYa3NTNUM4aFNXbFR4VDRVbnJ5VnZMeThreWRQVWtwUG5qeVpsNWZIR3V2cjZ3
a2g5ZlgxN01mR3hzYjgvUHpVMU5Sbm4zMDJJU0dCTmNLTkV1UTMyMHN2dmVSd09Cd094NlpO
bTFqTDh1WExuM2ppQ1VycDQ0OC92bUxGQ3ZrRG93VmlPZ0FnQklPRGd4OSsrT0dVS1ZQMEZn
SkNnNWdPQUFnR1d4SE95OHZUNjZ0TFFGZ2dwZ01BZ0hWQVRBY0FBT3VBbUE0QUFOWWh2SmhP
VkpEM2xOYzJhV3RybXpOblRrcEt5cHc1Y3k1ZXZCajlTekVoVlZWVmVYbDVpWW1KZVhsNUgz
endnV0lmdjkrL2V2WHE3T3hzd2RYeUZzRGpFL0VkbTVXVkpXNkpyMWlqc0dmUG5rbVRKaVVu
Sjk5MTExMUhqaHloZkM5U3VhdXJxcXFjVG1keWN2S1BmdlNqbHBhV3VGNkRNWkI3Z01jbk1Y
cHBoeDNUQXpKVG5GdGUyK1NSUng0cEx5LzMrWHpsNWVXbHBhWGE1Rm9NaDhOUlcxdnI5L3Zk
YnJmRDRWRHNVMVpXTm5QbXpETm56Z3dORGFtMWdMQjg4dFJUVDYxYnQwNzQwYll4L1pGSEhq
bDU4cVRQNTl1elp3LzdWMXVlRjZuYzFWbFpXWWNPSGVydDdYVzVYUC95TC84U0wva0dRdTRC
SHAvRTZLVWRxNWd1LzUvSnJLeXN6czVPU21sblp5ZitWNXN4WThhTSt2cjYzdDdldXJvNlZs
NURUazVPenRHalI0TzNBSDZmWEx0MkxTTWpvNzI5WFdpeGJVd1h1SFRwVW5KeWNsOWZIOCtM
Vk83cXJLeXNqei8rbU1XdnpNek1PQWcyR25JUDhQZ2tSaS90V01WMGVXMlRoSVNFd2NIQmVm
UG1EUXdNSkNZbVJxamJHalEyTm1aa1pCQkNNakl5MVA1ak9ERXhzYnk4UEMwdGJmejQ4ZnYz
NzFkc0FmdysyYlJwRS92WER3R2J4L1R2di8rK3VMaVkvVEhOOHlLVnU3cWlvdUtPTys0WVBu
ejRzODgrYTgrWHR0d0RQRDZKMFVzN3JubDZWMWNYUlo0dUlqOC8zKzEyKy8xK2w4dFZVRkNn
MkNjakk4UGxjdlgyOWg0NmRJaXRBc3RiQUtkUCt2djd4NDhmTC9uMWFlZVkvdVdYWDA2Y09M
Rzh2SHh3Y0pEeXZVaUR1UHJJa1NQanhvMkx2V3JqSXZkQUVKL0U2S1VkcTVndXIyM3k4TU1Q
cjF1M3p1LzNyMXUzN3JISEh0TW0xMktrcDZlNzNlN2UzdDdhMmxxMTlmUmYvT0lYd3RQTVht
YnlGc0RwazRxS2lybHo1MG9hYlJ2VGQrM2FWVnhjL1Bubm53c3RQQzlTUlZjUERRMmRQWHUy
cUtpSXZkaHRpTndESVgwU281ZDJyR0s2dkxaSmEydnI3Tm16MlJ2QmJXMXQydVJhaklxS0Ns
YThMVGMzdDdLeWtqVksvTm5TMGpKNzl1eWtwQ1NuMDFsVlZhWFlBaFI5SXI4elo4K2VMZjZU
TnVUSHQ2eU41UEo3ZW5vVVg2UWhiMGoyOE96czdGV3JWdm45ZmgydVJHL2tIbEQwU1h4ZTJy
SDZMQ01BQUlENGcvODVBZ0FBNjRDWURnQUExZ0V4SFFBQXJBTmlPZ0FBV0lmNDFYdkJHNnJ5
RWhBOFBxbXFxcG82ZFdwS1NzcXNXYk9PSFRzbXRHL1lzTUVtenVUeGdGb2ZNZkppR3VKNzJJ
YWY5SmRmUGsrVkVybXI4ZEpXclBjUzhvYVUxOXVKU3VXYzhHTzYwb2NaNVQzbDlWNkVFYlFK
dFFCcUpTQ0MrNlMwdFBUTW1UTit2LytERHo0WU0yWU1hL3o2NjY5WmJJcXRZbVBBNHdIRlBo
S0NGTk9RVklDeEc4TGw4MVFwVVhPMVRlNUdSZVIrNDdraDVmVjJvbEk1SjFZeFhmNS9wTUlJ
Mm9SYUFMVVNFRHcrOFhxOWxaV1Y3TXZEL0g3L3RHblQvdWQvL3NkV3p1VHhnTGlQSExWaUd1
SUtNSVNRZSs2NVovSGl4Uk1uVGhTK1o5bmFpQytmdjNLTDNOVzJ1aHNscVBrdCtBMHBJSzYz
RTNubG5GakZkSG05RjJFRWJVSXRnRm9KaUpBK0VmNDYvdkxMTHltbHp6enpEUHNmUC9zNGs4
Y0RrajV5MUlwcGlDdkFFRUthbTV2WmRzU0lFVEc4Sk1NZ3Zuek95aTJLcnJiUDNTaEgwVzho
YjBpR3VONU9WQ3JuSUUvWEFVa0pDQjZmZUR5ZTk5NTdiOXEwYVpUU2hJU0U0RzltV0JJZUQ0
ajd5RkVzcGlHcEFDT3NzMU43M0t1S0JYQW9SK1VXdWF2dDRLNlFTUHdXL0lha3NubzdhdU9F
UmF4aXVyemVpekNDTnFIV1FMRUVSSENmTEYrK3ZLMnR6ZS8zVjFaV1N2NGNzNGt6ZVR3UXBJ
K0FZakVOU1FVWXU4VjBlUUdja0ZWSzFGeHRCM2NGUWVJM25odFNYbTlIUG80R1loWFQ1ZlZl
eUsxb2sydHEySVhMaTBKSWZDSnh6cC8vL09lSkV5Y21KU1ZObXpiTjdYWkxCb3liZUIzaDhZ
QmlINGwvRkl0cHlDdkFVRHZGZE1VQ09NR3JsTWhkalplMjNHODhONlRFYnowOVBZcitEeGZV
ZXdFQUFPdUEvemtDQUFEcmdKZ09BQURXQVRFZEFBQ3NBMkk2QUlZRzcxZUJzRUJNQjBBQnpa
RTA2aUU0eUlCUm1Zc1E4dXFycjFKS1gzbmxsVWdHSklSczNydzVjbUdLVlZEeTh2SVNFeFB6
OHZJKytPQUR0ZGtsbjllUWwvZVIwOWJXTm1mT25KU1VsRGx6NWx5OGVKSGUrakVRZm9YeUZw
NUhCWms5eUhXRkJERWRBQVZzRmRNTENncUdob2FtVEprU1lVelB6OCsvZWZObWhNTGtWVkFj
RGtkdGJhM2Y3M2U3M1dwZjJ5dG9FSTZEbFBjUnoxVmVYdTd6K2NyTHkwdExTem1WeXhYS1d6
Z2ZKWmxkZmhWcUxVRkFUQWRBQWNYWEZTRWtLU2xweG93Wmh3NGRvcFMrOGNZYlRxY3pNVEZS
eUtSNHNqeEpGc2EyWldWbHFhbXBVNlpNYVd4c3BKUTJOallXRkJTa3BxYVdsWldKUnhiUExw
L3I3Tm16OTk1N2IzSnk4dVRKazRWYWdDSERBU0ZrM3J4NTY5ZXZuejkvUHV2OCtlZWZGeFlX
SmlVbEZSWVdzditJSVlSczJiSWxNek16SXlOang0NGRhdU5zMkxEaDVaZGZGaWFWanpOejVr
d212cjYrL3E2Nzdnb3VUS2lDTW1QR2pQcjYrdDdlM3JxNnV1Q1BFbCtzWW5rZmlUZXlzckk2
T3pzcHBaMmRuU3pPRWtJY0RrZGFXdHJQZnZhejF0Wld4VWZKRlFacENmSW8rZXhxMHlHbUF4
QXBhcStpZ1lHQmhvYUdzV1BIVWtwSGpCaXhZY09HTTJmTzlQYjJobnlnWWdjaFhtL2Z2dDNy
OWU3YXRXdjY5T21VMHFsVHArN2F0Y3ZyOWI3MTFsdmkvdUxaNVhQTm1qWHIzWGZmOWZ2OXRi
VzFreWRQNXIvU3ZYdjNKaVFrdlBmZWUyekFnb0tDblR0M2VyM2U3ZHUzRnhZV3NqNWJ0Mjcx
ZXIwMU5UVnFlU2docEtlblo5S2tTZGV1WFZNYjU0MDMzbGl5WkFtbGRQSGl4VysrK1dZUVZl
SXFLSTJOalJrWkdZU1FqSXdNZVJrRGlRYmhXSzI4ajVpRWhJVEJ3Y0Y1OCtZTkRBeUk2NnQw
ZDNlWGxaWE5tVE9IVTZGYVMvQkhxYzJPbUE1QTlKRy9pclp1M2VwME9sbXBtV0hEaGxGS1Av
cm9vNS8vL09lVEowOGVPWExrZi83bmY2bzlVRzNrL3Y1K0lhWjd2VjVLcWRmclRVNU9wcFFt
SlNXeEZvL0h3L3JJWjVmUGxaU1VKR1R1UXArd3JwUWRKeVltQ3JNbkpTV3g5djcrL3VBWHlO
bzNidHo0L1BQUHE0MXo5ZXBWaDhOeDRjSUZoOFB4d3c4L3FFbVNWRUhKejg5M3U5MSt2OS9s
Y2hVVUZIQmVpMko1SHdsWldWbGRYVjFVbGlsVFNuMCtIM3N1ZUJRcXRvUjhsTnJzaU9rQVJC
LzVxeWcxTmJXbXBzYnI5YnBjTHZIWndjSEJJMGVPcEtXbHNSOVRVbEtFdjlrVkdUVnFWRjFk
bmMvbjI3WnRteERUV1Q2N2E5ZXVxVk9uVWtxblRadkc4dlR0MjdlelBvcXpTK1lxTGk2dXJx
NzIrWHlhcnpSSW5oN0VNK0oyajhlVG01dXJOZzZsdExTMDlPNjc3dzVTeDFoZUJTVTlQZDN0
ZHZmMjl0Ylcxdkt2cHl1Vzk1SHc4TU1QcjF1M3p1LzNyMXUzamxYNlpOeThlWFA5K3ZYRnhj
V2NDaFVydDRSOGxOcnNpT2tBUkI5eUs1VFNsMTU2eWVGd09CeU9UWnMyaWRlNEV4SVNjbk56
Ly9qSFA3SUhybG16SmpVMU5jaUxjUHYyN1E2SEl6TXo4ODAzMzVTc3ArZm41eDgvZnB4U2V2
ejQ4Zno4L05UVTFPZWVlMDV0ZHZsYzU4NmRlK0NCQjFpTDBLaGhMYWlob2FHZ29DQXhNYkdn
b0VCWVQxZnNyempPNXMyYjFjYWhsTmJYMXhOQzZ1dnJnK2dSMDlQVFUxRlJ3ZjVHeWMzTnJh
eXM1SGtVVlNudkl4SGYydG82ZS9aczlyMUNiVzF0d2ppMzNYYmJBdzg4Y1A3OGVjVkh5UlhL
VzNpdVMyMTI4VlhJVzBLQ21BNkF6bkMrVmdIZ0FURWRBSjFCVEFkUkJERWRBQUNzQTJJNkFB
QllCOFIwQUFDd0RvanBBQUJnSFJEVGdUbW9ycTZ1cWFrWkdCaW9xYW1wcnE3bWZFandzMm9k
UEI2UHkrVlM3Qi9rVVFBWUFjUjBZQTZxcTZzLy9mVFRiNzc1NXJQUFBvdFdWRlViNTZ1dnZw
S2ZRaWdIcGdBeEhaaUQ2dXJxYytmT3VkM3VjK2ZPQ2VGVmNsQmRYZDNjM094MnU4K2VQYXZX
S0JsVFB0SE5temZyNitzVlk3cmI3Zjc0NDQ4N09qcWllbVVBUkJQRWRHQU9xcXVycjE2OUtt
eUZSdkZCZFhYMUR6Lzg0UEY0MkRlMUt6Wkt4cFJQOUplLy9LV2xwVVh4MU5EUVVFZEhSMTFk
WGZRdUM0QW9nNWdPekVGMWRmWFEwTkRodzRlSGhvYUVnT3QydXowZWp4RGw1U0ZlM2lnWlUz
RWl0WFh6b2FHaHJxNHV4SFJnWkJEVGdUa1FSMWpoK096WnMyNjN1N201V1VOTWx3UnUrVm41
UVhWMTljY2ZmM3o1OHVWb1hoZ0FVUVV4SFFBQXJBTmlPZ0FBV0FmRWRBQUFzQTZJNlFBQVlC
MFEwd0VBd0RvZ3BnTUFnSFg0ZTB4dmJHemNDd0FBd1B3UUJIUUFBTEFNL3c4ekFuMmUwNzdS
bGdBQUFBQkpSVTVFcmtKZ2dnPT0iIC8+PC9wPjxwPiZuYnNwOzwvcD48cD5JbiBDUFUgdXNh
Z2Ugb2YgdGhlIERvbTAsIHRoZXJlIGlzIG5vdGhpbmcgdG8gc2VlOjwvcD48cD4mbmJzcDs8
L3A+PHA+PGltZyBhbHQ9IiIgc3JjPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtH
Z29BQUFBTlNVaEVVZ0FBQWZFQUFBRnNDQUlBQUFCVHFCZTNBQUFnQUVsRVFWUjRuTzJkZjNR
VGRici94eWFwSlNocEc4b0Mxa0JoUzB0cGk3WGNVcmk3WHI2ZTd4VkZkLzJSVnRjVlBmZXND
L2RjUUN1UjVld2VQVzR2b0xzS2dxWFFxeGVGV2l5aVRkcFNZTld0YUZHNWgyckx4VXAvUVZO
RWZqWEpoS2I5L1BNOVovL2crOGVzczhQOHlxZHAwc3hNM3Evem5EbnBKNStaZWMrVHlidFBK
NU9uelA4Q0FBQXdCRzF0YlV5OE5RQUFBSWdDYlcxdGUvZnUvYnVuRXdBQUFIcG03OTY5OEhR
QUFEQUk4SFFBQURBTzhIUUFBREFPOEhRQUFOQVREUktFejhMVEFZZ0pETVBFVzRJbU5JQVlN
VG82eXJrNVBCMkFpVUFMZnFvRkRTQVdoRUtoYjc3NXh1MTJYNzU4dWJHeFVmZ1VQQjNFbk03
T3psLys4cGRwYVduSnljbDMzbm5uL3YzN3VYSG1SNlpNbWZMd3d3K2ZQMytlSDVkdVJIZjJw
QVhCV3RBQW9rNVBUMDlMUzh2eDQ4ZlBuajNiMk5qNHpUZmZDSitGcDRQWWN2cjA2Wi84NUNj
N2R1eTRjT0VDeTdLZmYvNzVndzgreUQzRk84N2c0T0N2ZnZXclgvemlGNkp4SWJxekp5MEkx
b0lHRUhVKysreXp5NWN2S3owTFR3ZXg1ZEZISC8zem4vOHMrNVRRY1g3NDRRZXIxU29kbDUy
c05Nai82UEY0NXMrZmI3RllIQTdIcmwyN3VNSHZ2dnZ1dnZ2dW16eDU4czAzMy95di8vcXZn
NE9EM0xqZjcvLzFyMzl0dFZxblRadTJlZk5tZmlPaFVNamxjazJkT25YU3BFbE9wL1BxMWF2
MFI4MkoyYng1YzBaR2h0VnFYYmx5SmN1eWhKQ2xTNWZ1MjdlUG45UFQwek45K25UaCt6TXJL
K3ZycjcvbUhyLzU1cHZjZzYrLy9qb3JLMHRGa3RJNGZ5eGZmUEhGekprelgzMzExVEVkQXRB
ajhIUVFXNlpObTNidTNEblpwNFNPZlBIaXhTaDZ1dDF1ZisrOTkxaVc3ZW5wZWVxcHA3akIz
TnpjSTBlTytQMyt5NWN2cjFtejVySEhIdVBHbjMzMjJmdnZ2Ly84K2ZQbno1Ky83Nzc3K0ky
OCtPS0xkOTk5ZDE5ZjM5V3JWNTk0NG9uZi92YTM5RWZOaVZtK2ZQbmc0T0RnNE9EeTVjdWZl
KzQ1UWtoVFUxTk9UczdJeUFnMzU2bW5udHEwYVpOd3JWV3JWdTNZc1lNUTB0ZlhkOHN0dDNE
dXZIMzc5dFdyVjZ0SVVocm5qcVdob1dIcTFLa0hEeDRjazM2Z1dYRGZDNGduWnJONWVIaFk5
aW5lUGMrZlAvL0VFMC9jZi8vOW9uSFp5U3FEL0krWm1abmJ0bTNyNit0VFV1WHorYVpPbmNv
OW5qbHo1bmZmZmNjOS92YmJiL21OT0J5T1U2ZE9jWSs5WHUrMGFkT1V0aVlMd3pEZmZ2c3Q5
L2owNmRPMzNYWWI5N2k0dVBpZGQ5N2hCMzArbjNDdER6NzR3T2wwRWtJMmJkbzBkZXBVN28r
TVJ4NTU1TU1QUDFTUnBEVE9NTXpycjc4K1k4YU10cmEyTVlrSDJnZjN2WUQ0b0Y2bmM5eDY2
NjBQUHZpZzErdmx4cE9Ta2tLaGtIQm1LQlJLU2txUzNZTHNqMjF0YmZmZGQxOTZldnJzMmJN
NU55U0VmUHJwcDB1V0xMRmFyZHhPYjdycEptN2NaREx4dXhzZUh1WTNZamFiR1FIOGZObERr
SDFLdUZtejJjdzlQbmp3WUhaMmRpZ1VLaTh2MzdwMXEyaXRvYUdoMjIrL25SQ3lZTUVDdDl1
OWVQRmlRc2p0dDkvT1diK1NKS1Z4aG1GbXo1NzkvUFBQUytVQlhZUDdYa0RjZVBUUlIxOTc3
VFhacDVRK3dYTTRIUC96UC84akhQbnFxNjhjRG9kMHB0bHM1dXZjQ3hjdWlEWTRPanJxZHJ0
LzhwT2ZjRC9PbkRtenRyYjI4dVhMbzZPalY2NWM0U2ZQbURGRHRrN1B6TXpzNysrbk9FUjVo
SFg2dDk5K08zUG1URjdWZ2dVTEtpb3FIQTVITUJpVXJ2anpuLy84M1hmZkxTNHVKb1FVRnhj
ZlBIandycnZ1VXBla05NNHdURjlmMzV3NWM3WnMyUkx4Z1FDdGdmdGVRRHc1ZmZyMDlPblRk
KzdjK2NNUFA3QXMyOWJXSnIzdlJjUi8vdWQvRmhVVmZmYlpaeXpMc2l4NzdOaXhoUXNYeXJw
U1VWSFJDeSs4NFBQNSt2djdIM3JvSVg2RFpXVmwzM3p6VFRBWWRMdmRkcnVkRzB4TFN6dDQ4
Q0RMc3Q5OTk1M1Q2ZVFuUC9QTU13ODg4TUQzMzMvLy9mZmZDNituLy9HUGYxeStmSGxYVjlm
dzhQREpreWU1U3lMME1BeHozMzMzY1pmcDc3MzMzb3FLQ3Y2cDJ0cGFobUYyNzk0dHUrS21U
WnRtenB6SmxmQ3Z2ZmJhYmJmZHRubnpablZKU3VQY3Nadzllelk3Tzd1eXNuSk0rb0Ztd1gw
dklNNTBkSFQ4NGhlL3NObHN5Y25KeGNYRnd2dlRaZWVQam81dTNicDF3WUlGTjk5ODg4MDMz
N3hnd1lMWFgzOWRkdVpYWDMyMWNPRkNzOW5zY0RoMjdOakJiM0Rmdm4zWjJkbG1zM24rL1Bs
TlRVM2M0UHZ2dno5NzlteVR5WFQ3N2JkdjNicVZuK3p6K1g3MXExOU5talFwSXlQamozLzhv
OFZpNGNaSFJrWXFLeXNkRG9mRllzbkx5NnV0clIzVFVRdnZlM25paVNjQ2dRRC8xUDc5Kytm
T25hdjBNY09KRXlmTVpqTjN0LzdnNEtEWmJPYi9hbEdTcERUT0grUEF3RUJPVHM2TEw3NDRw
a01BZWdTZURzQS82T3pzbkRWclZxejNzbUxGaXIxNzk4WjZMOENvNEw0WEFNS3dkdTNhaXhj
dkRnd01MRisrZk4yNmRiSGIwY2pJU0hWMWRXNXVMbjg3SXdCalJXVGk4SFFBeEx6NjZxdDJ1
MzN5NU1tUFB2cm8wTkJRN0hiRU1JekQ0Y0NkaFdBOE5EWTJYcnQyalh0ODdkbzEzUGNDQUFB
NnBxMnQ3ZXV2dng0ZUhoNGVIdjc2NjYrUEh6OHVmQmFlRGdBQWVpSVFDSHorK2VjZWo4Zmo4
YlMxdFFrL2ZpZndkQUFBMERXNG5nNEFBTVlCbmc0QUFEb21nZTVsN0RwNnRPdm8wWGlyQUFD
QWljT3duajdNc3R1WExObStaTWt3eThaYkN3QUFUQkNHOWZTL3Z2cHFwY05SNlhEOEZZMy9B
UUNKaWtFOC9YSmYzNWJzYk03VHQyUm5YMVp1bkEwQUFMckc3L2UzdGJYeDl6TDYvWDdoczFy
eDlOcmEydXpzYkl2RlVsQlEwTkxTUWdqcDcrOHZMUzFOVGs0dUxTM2wrb2hLUjNqcW5ueVNN
M1F1NnA1OE1qNkhBUUFBTWFhMXRmWFVxVlBYcmwyN2R1MWFaMmRuYTJ1cjhGbXRlUHJqanov
ZTNkM3Q5L3ZmZmZmZDlQUjBRa2haV1puTDVRb0VBaTZYcTd5OFhIWkV4TWFORzdrSFo4K2Vw
ZG5wdFk0T21tazBXNlBjSTgwMHFLS2ZCbFgwMDdTcGl0QUppK0lldGFscVRMamRicjVmME1q
SWlOdnRGajZyRlUvbllGbjJ2ZmZleTgvUEo0VFk3WGJ1SDk5NHZWNnVCYlowUk1UR2pSdXZk
ekRYTzVqMnh2L0xQVkNQd0paQ21tazBXNlBjSTgwMHFJS3F4RkZGS1N5S2U5U09xb2g5VWg5
MU92bngzNENscHFaKzl0bG5oSkNrcENUdWQxRW9GREtaVExJalBLRUxGNjVVVlcxWXRZcnN6
Ynpld1F5L1BlZDZCOE05VmxuKzdkaWtzSE1vdDBhNXgvOTNNdndlb1FxcUVrZlY5UTRtdEh0
Qzk2Z2RWWDlqMlN0VlZjSDI5ckZhcGMvbjA4SDFkQTd1MnN1Y09YTUlJZW5wNmFLcVhEb2ln
cS9UQno3SnYwN3grNVBVWnRKTW85a2E1UjVwcGtFVlZDV09La3BoVWR5amhsUmR2eDRMRjlX
S3A2OVpzK2I4K2ZOK3YzLy8vdjNjZnoxM09wMzgxWFB1ZjNGSlIwVHdubzVBSUJCYWowZzlY
Ui8zdmRUVTFNeVlNU001T2ZuT08rLzh5MS8rUWdqcDdlMHRLU214V0N5TEZ5L3U2K3VUSFJH
Qk9oMnFvRXBmcWlpRm9VNFhvcHZyNmVNSGRUb0NnZEJOUk9ycGVycnZaWnlnVG9jcXFOS1hL
a3BocU5PRkpFU2RmdTNhdGU3dTd0Lzg1amZYT3hqdkp3dXd4QkpMTERXKzdPL3Y3Kzd1anVE
dWRUM2Q5ekpPVUtkREZWVHBTeFdsTU5UcDlCalQweEVJQkVMckVhbW5KMUQvZE5UcFVBVlYr
bEpGS1F4MXVoQ1JpWXN3cHFjakVBaUUxZ09lSGhiVTZWQUZWZnBTUlNrTWRicVFoUEIwM1Bl
Q0paWlk2bXNaOFgwdjZoakUwemxRcDBNVlZPbExGYVV3MU9uMEdOUFRFUWdFUXVzUmthY2ZP
WEtrdmIzZDYvV0dRaUhaQ2NiMGROVHBVQVZWdWxCRktReDFPcytWSzFlNnVycU9IVHZXMk5o
NDdOaXhycTZ1SzFldUNDY1kwOU1SQ0FSQzZ6RytheS9EdzhOZXI3ZTl2ZjNJa1NQQ2NXTjZP
dXAwcUlJcVhhaWlGSVk2blI2RGVEcnVlOEVTU3l6MXRjUjlMK0ZCblE1VlVLVXZWWlRDVUtm
VFkweFBSeUFRQ0sxSGxEd2QvVjcrRWRxc1hLQUtxaEpIRmFVdzFPa3FKSVNuSXhBSWhOWURm
UmxWRUgxR092QkpQczFuRk4xNy9pWHNITXF0VWU3eGhIc0ZWRUVWVkFtWHBEWnpJdmVvSFZY
UitvelVtSjdPZ1RvZGdVRG9KbkR0SlN5NG5nNVZVS1V2VlpUQ2NEMmRIcTE0ZWwxZFhXNXVy
c1ZpS1Nnb2FHbHBJWVF3QXJnNS9mMzlwYVdseWNuSnBhV2wvZjM5MG8yZ1RrY2dFTHFKU0Qz
ZDcvZnI0UCtSUHZ6d3crM3Q3WUZBWU5ldVhYYTduUkRDV3psUFdWbVp5K1VLQkFJdWw2dTh2
Rnk2RWRUcFVBVlYrbEpGS1F4MXVwRFcxdFpUcDA1ZHUzYnQyclZybloyZHJhMnR3bWUxNHVr
ODNkM2REb2VERU1Jd3pLMjMzbXExV3Bjdlg5N2QzVTBJc2R2dFhxK1hFT0wxZWpuZkY0RTZI
WUZBNkNZaTlYUzMyejB5TXNJOUhoa1pjYnZkd21lMTVla0RBd05GUlVVZmZQQUJQekk0T0Zo
UlVWRlNVa0lJU1VwSzRvNGtGQXFaVENiaGlxRUxGNjVVVlcxWXRZcnN6Ynpld1hoM2xsN3ZZ
TGpIS2t0U214bDJEdVhXS1BjNDhFaytWRUVWVkFtWGdVMkZFN2xIN2FqNkc4dGVxYW9LdHJl
UDFTZDFVNmUzdGJVNUhJNDllL2FJeHYxK3Y4VmlJWVNrcDZlalRrY2dFQWFKU090MG44K25n
K3ZwMWRYVkdSa1p6YzNOb3ZGTGx5NXQzTGl4dUxpWUVPSjBPdm5yNlU2blU3b1JYRStIS3Fq
U2x5cEtZYmllVG85V1BKMjVrYUdoSWU1QlNrcktzbVhMVHA4K1RRanA3ZTB0S1NteFdDeUxG
eS91Nit1VGJnUjFPZ0tCMEUzZ2U2UmhRWjBPVlZDbEwxV1V3bENuQytGTW5MZnloUEIwQkFL
QjBIcEU2dWtlaitmcTFhdHV0L3ZLbFN0WHJseHBhbW9TUG1zUVQwZS9GNmlDS2oycThxTGZ5
OWo3dlh6OTlkZU5qWTA5UFQxSGpoenhlRHhuenB3UlBtc1FUK2RBblk1QUlIUVR4djZNTkNy
Z2VqcFVRWlcrVkZFS3cvVjBJWW40R1NrQ2dVQm9QVkNuaHdWMU9sUkJsYjVVVVFwRG5VNlBN
VDBkZ1VBZ3RCN3dkQlZ3M3d0VVFaVWVWWGx4Mzh1NC84K1JDSU40T2dmcWRBUUNvWnN3ZHYv
MHFJRHI2VkFGVmZwU1JTa00xOU9GNktZdjQvaEJuWTVBSUhRVGlkQS9mWnlnVG9jcXFOS1hL
a3BocU5PRm9FNUhJQkFJN1lXeCs2ZVBFOXozQWxWUXBVZFZYdHozZ3Z0ZVZFQ2Rqa0FnZEJQ
b0RSQVdYRStIS3FqU2x5cEtZYmllTGdUOTB4RUlCRUo3QVU4UEMrcDBxSUlxZmFtaUZJWTZY
VWhDZUxyb00xSXNzY1FTUzQwdm8vVVpxVEU5blFOMU9sUkJsYjVVVVFwRG5hNUNRbmc2QW9G
QWFEMk1mZDlMWFYxZGJtNnV4V0lwS0Nob2FXa2hoUFQzOTVlV2xpWW5KNWVXbHZiMzk4dU9p
RUNkRGxWUXBTOVZsTUpRcDZ1Z1VVOS8rT0dIMjl2YkE0SEFybDI3N0hZN0lhU3NyTXpsY2dV
Q0FaZkxWVjVlTGpzaUFuVTZBb0hRVFJqYjAzbTZ1N3NkRGdjaHhHNjNlNzFlUW9qWDYrVmNY
am9pQW5VNlZFR1Z2bFJSQ2tPZFRvKzJQSDFnWUtDb3FPaUREejRnaENRbEpYRzl4MEtoa01s
a2toM2hDVjI0Y0tXcWFzT3FWV1J2NXZVT0Jrc3NzY1JTNDh1L3NleVZxcXBnZS90WWZWSWYx
OU1KSVcxdGJRNkhZOCtlUGR5UDZlbnBvcXBjT2lJQ2RUcFVRWlcrVkZFS1E1MU9qMVk4dmJx
Nk9pTWpvN201bVI5eE9wMzgxWE9uMHlrN0lnTFgweEVJaEc3QzJQZTlNRGN5TkRUVTI5dGJV
bEppc1ZnV0wxN2MxOWRIQ0pHT2lFQ2REbFZRcFM5VmxNSlFwNHNJQm9NZmYveHhZMlBqK2ZQ
blJVOXB4ZE9qQXVwMEJBS2htNGpVMHpsRFAzWHExTVdMRjV1Ym15OWZ2aXg4MXBpZWpqb2Rx
cUJLRjZvb2hhRk9GL0xSUngveGRuM3UzRG51Q3owOEJ2RjA5SHZCRWtzczliV011TitMeUt2
UG5Ea2ovTkVnbnM2Qk9oMnFvRXBmcWlpRm9VNFhvby9QU0tNQ3JxY2pFQWpkQkhydGhnVjFP
bFJCbGI1VVVRcERuUzRrRVQwZGdVQWd0Qjd3OUxDZ1RvY3FxTktYS2twaHFOUHBNWWluNDc0
WExMSEVVbC9MaU85N1NjVFBTRkduUXhWVTZVSVZwVERVNlZKR1IwZEZGMkU0ak9ucENBUUNv
ZlVZaDZlSFFxRnZ2dm5HN1haZnZueTVzYkZSK0pReFBSMTFPbFJCbFM1VVVRcERuUzZrcDZl
bnBhWGwrUEhqWjgrZWJXeHMvT2FiYjRUUEd0UFRFUWdFUXVzUnFhZC85dGxub2g0dlFvenA2
YWpUb1FxcWRLR0tVaGpxZEhvTTR1bTQ3d1ZMTExIVTF6TGkrMTdVTVlpbmM2Qk9oeXFvMHBj
cVNtR28wK2t4cHFjakVBaUUxZ09lSGhiVTZWQUZWZnBTUlNrTWRUbzl4dlIwQkFLQjBIckEw
OE9DT2gycW9FcGZxaWlGb1U2bnh5Q2VqdnRlc01RU1MzMHQ0M25meTV0dnZwbVdscGFXbHZi
Zi8vM2YwZDE5ZEVHZERsVlFwUzlWbE1KUXA5T2o2T2tzeS9LUFUxTlRqeDgvZnZ6NDhiUzB0
RmlJaUJhNG5vNUFJSFFURSt6cHQ5OStlMDFOVFNnVUloUGk2Y3lQU0VmNHdmNysvdExTMHVU
azVOTFMwdjcrZnVsR1VLZERGVlRwU3hXbE1OVHA5Q2g2ZW10cjY5S2xTN096czk5OTk5M2R1
M2VucHFhbXBxYSsrZWFic1JEQkkvSjAwYk5sWldVdWx5c1FDTGhjcnZMeWN1bnFxTk1SQ0lS
dUlpNmZrWG84bmp2dXVLT3dzTkR0ZHNkaTl5SkVubjdycmJkYXJkYmx5NWQzZDNjVFF1eDJ1
OWZySllSNHZWNjczUzVkSFhVNlZFR1Z2bFJSQ2tPZFRvK2lwL09maTc3MTFsdnZ2dnR1ZG5a
MmFXbnB4eDkvSEFzUlBOTGFmSEJ3c0tLaW9xU2toQkNTbEpRME1qSkNDQW1GUWlhVFNUZ3Rk
T0hDbGFxcURhdFdrYjJaMXpzWUxMSEVFa3VOTC8vR3NsZXFxb0x0N2RGMVVVVlBUMHRMYTJ0
cjQ2K2hoMEtoM2J0MzMzNzc3ZEhkdlFpcHB4TkMvSDYveFdJaGhLU25wNk5PaHlxb01wSXFT
bUdvMCtsUjlIVFp6MFdGTjhQRUFxbW5YN3AwYWVQR2pjWEZ4WVFRcDlQSlgwOTNPcDNTMVhF
OUhZRkE2Q1ltMk5OcmFtb201bk5SRHVaRytKR1VsSlJseTVhZFBuMmFFTkxiMjF0U1VtS3hX
Qll2WHR6WDF5ZmRDT3AwcUlJcWZhbWlGSVk2blI2RGZJK1VBM1U2QW9IUVRjRFRWUkQxQmhq
NEpKL211N25kZS80bDdCektyVkh1OFlSN0JWUkJGVlFKbDZRMmN5TDNxQjFWK0o4WTRVR2Rq
a0FnZEJPbzA4T0M2K2xRQlZYNlVrVXBETmZUNlRHbXB5TVFDSVRXQTU0ZUZ0VHBVQVZWK2xK
RktReDFPajNHOUhRRUFvSFFlc0RUVmNCOUwxQUZWWHBVNWNWOUw3anZSUVhVNlFnRVFqZUJP
ajBzdUo0T1ZWQ2xMMVdVd25BOW5SNWplam9DZ1VCb1BlRHBZVUdkRGxWUXBTOVZsTUpRcDlO
alRFOUhJQkFJclFjOFhRWGM5d0pWVUtWSFZWN2M5NEw3WGxSQW5ZNUFJSFFUcU5QRGd1dnBV
QVZWK2xKRktRelgwK2t4cHFjakVBaUUxZ09lSGhiVTZWQUZWZnBTUlNrTWRUbzl4dlIwQkFL
QjBIckEwMVhBZlM5UUJWVjZWT1hGZlMrNDcwVUYxT2tJQkVJM2dUbzlMTGllRGxWUXBTOVZs
TUp3UFowZXJYZzY4eVA4U0g5L2YybHBhWEp5Y21scGFYOS92K3lJQ05UcENBUkNOMkZzVCtj
UWVucFpXWm5MNVFvRUFpNlhxN3k4WEhaRUJPcDBxSUlxZmFtaUZJWTZuUjd0ZXJyZGJ2ZDZ2
WVFRcjlkcnQ5dGxSMFNnVGtjZ0VMcUpSUFAwcEtTa2taRVJRa2dvRkRLWlRMSWpQS0VMRjY1
VVZXMVl0WXJzemJ6ZXdYaDNsbDd2WUxqSEtrdFNteGwyRHVYV0tQYzQ4RWsrVkVFVlZBbVhn
VTJGRTdsSDdhajZHOHRlcWFvS3RyZEgxMFcxNitucDZlbWlxbHc2SWdKMU9nS0IwRTBrV3Az
dWREcjVxK2RPcDFOMlJBU3VwME1WVk9sTEZhVXdYRStuUnl1ZXp0d0lJYVMzdDdla3BNUmlz
U3hldkxpdnIwOTJSQVRxZEFRQ29ac3d0cWRIQmRUcFVBVlYrbEpGS1F4MU9qM0c5SFFFQW9I
UWVzRFRWVUMvRjZpQ0tqMnE4cUxmQy9xOXFJQTZIWUZBNkNaUXA0Y0YxOU9oQ3FyMHBZcFNH
SzZuMDJOTVQwY2dFQWl0Qnp3OUxLalRvUXFxOUtXS1VoanFkSG9NNHVtaXowaXh4QkpMTERX
K3hHZWs0VUdkRGxWUXBTOVZsTUpRcDlOalRFOUhJQkFJclFjOFBTeW8wNkVLcXZTbGlsSVk2
blI2ak9ucENBUUNvZldBcDRjRmRUcFVRWlcrVkZFS1E1MU9qMEU4SGZlOVlJa2xsdnBhNHI2
WDhLQk9oeXFvMHBjcVNtR28wK2t4cHFjakVBaUUxZ09lSGhiVTZWQUZWZnBTUlNrTWRUbzl4
dlIwQkFLQjBIckEwOE9DT2gycW9FcGZxaWlGb1U2bnh5Q2VqdnRlc01RU1MzMHRjZDlMZUZD
blF4VlU2VXNWcFREVTZmUVkwOU1SQ0FSQzY1Rm9uczRJNEViNisvdExTMHVUazVOTFMwdjcr
L3VscTZCT2h5cW8wcGNxU21HbzArblJ0S2VMUnNyS3lsd3VWeUFRY0xsYzVlWGwwbFZRcHlN
UUNOMUVBbnI2cmJmZWFyVmFseTlmM3QzZFRRaXgyKzFlcjVjUTR2VjY3WGE3ZEJYVTZWQUZW
ZnBTUlNrTWRUbzkydlYwanNIQndZcUtpcEtTRWtKSVVsTFN5TWdJSVNRVUNwbE1KdUcwMElV
TFY2cXFOcXhhUmZabVh1OWdzTVFTU3l3MXZ2d2J5MTZwcWdxMnQwZlhNN1h1NllRUXY5OXZz
VmdJSWVucDZhalRvUXFxaktTS1VoanFkSHEwN3VtWExsM2F1SEZqY1hFeEljVHBkUExYMDUx
T3AzUXlycWNqRUFqZFJLSjVPbmZIUzBwS3lySmx5MDZmUGswSTZlM3RMU2twc1Znc2l4Y3Y3
dXZyazY2Q09oMnFvRXBmcWlpRm9VNm5SN3VlSGdHbzB4RUloRzRDbmg0VzFPbFFCVlg2VWtV
cERIVTZQUWJ4ZFBSN3dSSkxMUFcxUkwrWDhLQk9oeXFvMHBjcVNtR28wK2t4cHFjakVBaUUx
Z09lSGhiVTZWQUZWZnBTUlNrTWRUbzl4dlIwQkFLQjBIckEwOE9DT2gycW9FcGZxaWlGb1U2
bnh5Q2VqdnRlc01RU1MzMHRjZDlMZUZDbjYxSlZwU1pWYVROWGhsTkZLUXgxT2ozRzlIU0Vu
a0xCMHhFSWd3YzhQU3lvMC9Xb2lsbDlXSU9xdEprcjQ2bWlGSVk2blI1amVqcENSNkhrNlFp
RXdRT2Vyb0xvTTlLQlQvSnBQcVBvM3ZNdlllZFFibzF5anlmY0s2QktOR2VCNjZBR1ZXa3pW
OFpUNWYxa0Fhbk5uTWc5YWtjVlBpTU5EK3AwUFFicWRFU0NCdXIwc09CNnVoNVY0WHA2SXF1
aUZJYnI2ZlFZMDlNUk9nclU2WWdFRFhoNldGQ25LODZwVkx0bE1KNnFVS2NudGlwS1lhalQ2
VEdtcHlQRVVYbGp4RjFQQjNQOVJ6ZS93ZE1ySlE4bVBsSHhUZ3ZDYUtGMFVzSFRWY0I5TDJw
ektwa0Zyb1BNNnNQOFVoT3FmcnpqNVFZOVd4WmNyMlE0emZIS2xSWmZRVzJlVjlGUTVVMkUr
MTcraFB0ZUl1VWZkWG9jeTFMdEZYck02c09paUxza1h0ajF5aHZxZEc1RU5EaVJMNU4ya2tO
MUNGcjZxeXVlU1loRlZpc2xQMHFEYnB1S0p4WHE5TEQ4M2RNcm1ZRXQrVFNwai80VlJ0SHVK
THVXMzVUdzdJbXVxaTM1bkQrcWUzcThyc1l5UC82KzRSUEYvOGlzUGh4RFZkS3pvdklmdVZJ
L2MwUWZCc2pPaVZ5Vndpc29yMGN3SGttdXh0Rm1SMFBYMDIvTVRDVGlLK1cyVnNtUWlzd3do
azZUOWtybWVpV1Q3em9vZjFFUm50N2YzMTlhV3BxY25GeGFXdHJmM3krZHNISGpScjdLdThI
Q3dyMDJVWXdKM2gyTkhobFBqN2VxdjJzVGVycEU3UVMvVFAvNG95SGVhVkhYT2ZHNTBuSkUv
ZkJsM2krQzRpT3k5NUhpekI4OXZlNnBweTcxOWtiTEovWGs2V1ZsWlM2WEt4QUl1Rnl1OHZK
eTZZU05HemR5dWM3L0pQL3ZyOFNQcjRmMDFicE85NnY0dXJUcVY1NGplckdsTDd6c3BvUm5U
M1JWNWJzTy92MmtWRDBkYVRZMUhsV3l1MU1TeGdmTnBpSlRKYnU3ditjcTNKdDJZRXYrMzAr
bkRzVzNhOFNxcEFjclVuWERzNEl6bk4rVXJCN1pzNTNwb0ZLbE5JZkcxR2cyUlprdXhUZk9q
eGtZazNpMWsrSEhEZjZ5TnZNR0Q1RUxwZDNKbmxveUw5Q1BubDdwY0d5Wk4rK3ZyNzQ2SEFp
TTN5ZjE1T2wydTkzcjlSSkN2RjZ2M1c2WFR0aTRjV1BZbHdHQlFDQzBFRUpQNTJMSFAvL3p0
MGVPak5NbjllVHBTVWxKSXlNamhKQlFLR1F5bWJqQnpzN081NTkvM3JWdTNiTVBQUEIvbGk1
OTdva25ubi8rK2Q4KytPRHp6ei9QUFZaWlZqenlTTmc1bEZ1ajNPTy8vZHUvUVJWVVFaVncr
Y3c5OTB6a0hyV2ppbk90OWIvNXpUODhmZW5TYnc4ZkhxZFA2c25UMDlQVHc5YnAzSU16Wjg3
UWJERHd5U2MwMDJpMlJybEhtbWxRUlQ4TnF1aW5hVk1Wb1JNV3hUMXFVQlYzN2VXVFAvODU0
YTY5T0oxTy9ucTYwK21VVHVBOVBSZ00wbXp3eXE1ZE5OTm90a2E1UjVwcFVFVS9EYXJvcDJs
VEZhRVRGc1U5YWxCVjNaTlBYdXJwb2RrVURYcnk5TjdlM3BLU0VvdkZzbmp4NHI2K1B1a0Uz
dE1wQ1owL0h5VnAwUVNxNklFcWVyU3BpbWhWbURaVjBhQW5UdzlMZTN0N3ZDVUFBRUE4TVpT
bkF3QkFnZ05QajV5NnVycmMzRnlMeFZKUVVORFMwa0lJWVg1RVU2cWtJMXBRVlZ0Ym01MmRy
VFZWSEgvNHd4L2krQ0txbkZlYVVqVXlNdktIUC94aHhvd1pOOTEwazZhRUNkT1ZucDZ1RVZY
MTlmVlpXVmttazJuMjdObjE5Zld4MnpVOFBYSWVmdmpoOXZiMlFDQ3dhOWN1NFgwNDhmVjBx
U29sbmZGVjlmampqM2QzZC92OS9uZmZmVGRlYnp6WnpCdy9mbno2OU9seGZCR2xxdUo3Um5G
SVZiMzAwa3Z6NXMxcmIyOGZIUjNWbERDZVk4ZU8vZTUzdjlPSXFpbFRwbmc4SHBabDNXNjN6
V2FMM2E3aDZWR2d1N3ZiNFhEd1AycmhIVWdrcW1SSEpoNlJCcFpsMzN2dnZmejgvRGhLSWdK
VmdVQmd3WUlGUjQ4ZTFjS0x5S3RpR09iV1cyKzFXcTNMbHkvdjd1N1dpQ3FIdytGMnUrTXJS
b2owOUY2K2ZQbTVjK2ZpcFllRFY1V2ZuKy94ZUlMQm9OdnRMaXdzak4wZTRlbmpaV0Jnb0tp
bzZJTVBQdUJIdEdBSFVsWFNrYmlyNHY0NlRrMU4vZXl6enpTaWFzMmFOWC82MDUrSUJsNUU2
ZXMxT0RoWVVWRlJVbEtpRVZVbWsybnQycldUSmsxeU9Cd0hEeDZNb3lvaWw2N1cxdGJISDM4
OGpwTElqYW8rLy96ektWT21NQXd6WmNxVXp6Ly9QSFk3aGFlUGk3YTJOb2ZEc1dmUEh1Rmcz
TzFBcWtwV1o5eFZFVUs0YXk5ejVzelJpQ3J1MG5EY0wxNHJ2VjUrdjk5aXNjUkZFcEdvc3R2
dGJyZWJ1NWd3ZGVyVWVLbVNDdU5ZdG16WlYxOTlGUzlKUktKcTd0eTUvTFdYbi83MHA3SGJM
enc5Y3FxcnF6TXlNcHFibTBYajhmVjBxU29sbmZGVnRXYk5tdlBuei92OS92Mzc5MCtiTmsw
anFuamkrQ0lxcWJwMDZkTEdqUnVMaTR2aklVcEdWWGw1dWR2dDVpNG1aR1JreEVXVnJEQkN5
TWNmZi95em4vMHNYcEtJbktyVTFGVCsya3RhV2xyc2RnMVBqeHptUm9hR2hrUWoybFExTkRT
a0JWVTFOVFV6WnN4SVRrNis4ODQ3Ly9LWHYweThKRmxWd3FmaUlrbFdGZmNnSlNWbDJiSmxw
MCtmMW9pcXMyZlAvdXhuUDdOWUxGbFpXWEc4c0M3N0l2Nzg1ejkvLy8zMzR5VkpWbFZkWFoz
RDRUQ1pUTE5telhydnZmZGl0MnQ0T2dBQUdBZDRPZ0FBR0FkNE9nQUFHQWQ0T2dBQUdBZDRP
Z0FBR0FkNE9nQUFHQWQ0T2dBQUdBZDRPa2hRNG5nSE9nQ3hBNTZ1SjRMQjRMcDE2NlpPblhy
TExiZHMyclFwM25MMEFjTXdyN3p5Q2lIazVaZGZobzlUMHQ3ZXpqQU0vc2tNSlpvNngrRHBl
bUw5K3ZVUFBQREF1WFBuTGwyNjlNd3p6OFJiamo1Z0dDWW5KMmQwZEhUZXZIbHhmNy9waFMx
YnRpUWxKVzNac2lYZVF2U0JwczR4ZUxxZW1EbHpwdWgva0F0UElQNHh3ekRyMTYrM1dxMThT
OCs0bjJkeGhHR1lKVXVXdlBUU1MwdVhMaFdtU0pTNjExNTdMUzB0TFRVMWRkZVAvMXc0a1pP
MmJObXlwNTU2YXRteVpkeVBoWVdGM0Q5Mk9IVG8wTUtGQ3draHg0OGZ6OG5KU1VsSmNibGN3
cXpHUzNCOGtaNWozQWxtTnB2NS80bXhhdFdxWC8vNjE0U1F4eDkvZlBYcTFmeUtVUmNEVDlj
VEpwTXBGSC83NEhnQUFCeHpTVVJCVkFvSlI1UTgvWlZYWHZINWZFOC8vZlNFNnRNa0RNUHMz
YnMzS1NscDM3NTlzdW5pSG0vZnZ0M3Y5emMyTnNicjM0Wm9CNS9QTjNueTVIUG56azJlUE5u
bjh4RkN0bTdkV2w1ZVRnZ3BLeXZidG0wYklTUS9QLytOTjk3dytYeTdkdTFLV0N2blVUckhR
cUZRYTJ2cjlPblRDU0hEdzhOMzMzMzN2Ly83djk5OTk5M0R3OE94RXdOUDF4TXFkZnJ3OExE
UTA2OWR1emJSNHJTS2lvOExIL052TXpoVVEwTUQzM3lxb2FHQkVQTEREei9ZYkxZelo4N1li
TGFMRnk4U1FzeG1zOS92SjRUNC9YNWtUSHBlYmQrKzNlRndKQ1VsTVF4ejAwMDNjVThkUDM2
Y1laamp4NC9IVkF3OFhVOVVWRlE4OE1BREF3TURseTlmcnFpb0lJVFk3ZmJtNXVaQUlMQmp4
dzc4Q1N3THBhZkxQazVNVnE5ZXpYMEN2Mm5USnY0cWdkUHB2T09PTzhyS3lyZ2ZGeXhZc0hQ
blRyL2YvMS8vOVYvSW1QVDhTVWxKYVd4czlQdjlicmViRy9INy9RVUZCY3VYTHk4b0tBZ0VB
ckVUQTAvWEV5ekwvc2QvL0lmZGJ1ZnZlNm11cnJiWmJHbHBhZHUyYlZQeDlFUisxMG5mYjZJ
K3FMSnpTQUluTFNzcjYrVEprNFNRa3lkUFptVmxjWU9IRGgxaUdPYlFvVVBjajIxdGJkbloy
U2twS2M4OTkxeFNVaEkzbUxBWms1NC9MN3p3Z3MxbXM5bHNtemR2NWtaV3JsejUyR09QRVVJ
ZWZmVFJKNTk4VXJwaXRJQ25Bd0FpWkdSazVQMzMzNTgzYjE2OGhZQi9BRThIQUVRQ2Q2VTRL
eXNyWHYvU0JNZ0NUd2NBQU9NQVR3Y0FBT01BVHdjQUFPTXdOazluRklpaW9JVDk2RHhhMEx3
b3d0Y3VQVDJkY2kwRE05YWtjU005UFQwbEpTWEp5Y2tsSlNXOXZiMFRvbFFyMEdTc3ZyN2U0
WEJZTEpaLytxZC82dXJxa2gweEtudjI3Smt6WjQ3RllsbTRjT0hSbzBjSklmWDE5ZlBuejA5
T1RpNHFLdnI0NDQ5VjFxMnNyQnpQT1RaMlQrK1FCRHhkZTFDbWNmWHExUnMyYkJqcldrWWxy
S2VMUmg1NjZDR1h5eFVJQkZ3dWw5UHBqS0V5cmFLZXNmVDA5SmFXbG1BdzZIYTc3Ny8vZnRr
Um8vTFFRdytkUEhreUVBanMyYk9IKzJheTArbnM2T2hnV2ZiQWdRUFRwazFUV3ZIRWlSTVpH
Umw4WWlNNHgyTGw2VnUzYm5VNEhDYVRpZjlsdm1qUkl1N20xdHJhMnRMU1V0azUwbEtvczdO
ejhlTEZGb3RsN3R5NTNDODNobUh1dlBQT3NyS3kyYk5uODkrQUFDSm8zUG5TcFV1cHFhbG56
NTRkMDFvR0pxeW4yMncycTlWNnp6MzNkSGQzRTBMUzA5TzlYaThoeE92MUptWkhnYkNlZnZq
d1ljN0IwOUxTWkVjTVQxOWZuOFZpNGIvWDdmZjc2K3JxbE83K1pGazJMeS92N2JmZjVoTWJ3
VGtXSzArZlBIbHlaV1ZsUjBkSE1CamtSdmJ0MjhkWmNGRlIwUWNmZkNBN2gwak9rcUtpb25m
ZWVZZGwyYWFtcHJsejUzSVQrRWFna3lkUHBqbklCSVRHblRkdjNzeDlDV0pNYXhrWW1zTS9m
LzU4UlVWRlNVa0pJU1FwS1dsa1pHVEpraVdoVU1oa01zVmVvT1pRejFodGJlMXR0OTAyYWRL
azU1NTdqc3VQZE1UWWZQLzk5OFhGeFh3TFZmNXE1NWRmZmlrNy85bG5uMzNra1VlSUlMRVJu
R094OHZRUFAvenczbnZ2blR0MzdpMjMzUEw3My8rZUVESThQRHhuenB6OSsvZHpUU2xsNXhE
SldXSTJtL25Lbld1YndGZjAwc21BSjJ4bWhvZUhNek16UmEwbkVqeWZsSWNmQ0FRc0Znc2hK
RDA5ZlhCd2tLQk9EOGZSbzBkbnpweXBQbUk4dnZ6eXk5bXpaN3RjcnBHUkVYN1E1L1B0Mjdj
dkx5OVBkaFd1UDR6d1drVUU1MWhzcjZlUGpJd2NQWHJVYXJWeVAyN2F0TWxxdGZLOVRHWG5K
Q2NuYzMvWWNoUVhGemMwTkFqYkk4RFRhUWliR2Y0SzJKaldNalkwaDMvMTZ0V1hYbnFwdUxp
WUVQTGdndzl1MkxDQlpka05Help3NVZXaUVUWmpvNk9qbloyZCtmbjVYSHNpMlJGRFVsTlRV
MXhjL09tbm4vSWpLMWV1N09ucFlWbTJycTR1N0hVblByRVJuR094OG5UdTkweFNVdEtzV2JQ
ZWVPTU5idkRDaFF2cDZlbGNPemVsT2V2V3JVdEpTZUczZWVyVXFidnV1b3Nia2JwNWdudVFM
TXlOOElPaWFZc1dMZHEvZjcvNldva0RUZEs0cDI2KytlYTc3cnJyOU9uVGhKRHU3dTVGaXha
eGQzSDA5UFRFUVhmOG9NOVlSa2JHbWpWcldKYVZIVEVxb3Z3TURRMjk5ZFpiczJmUE5wdk5l
WGw1SG8rSG42YTBPdmNnZ25OczR1NWxIQmtaZWYzMTE5ZXRXMGN6R1FBQVFBUk0zSGVPR0lZ
cExDemtQc01GQUFBUUMvQTlVZ0FBTUE3d2RBQUFNQTd3ZEFBQU1BNmE2L2NDeGdsTmd3aHAy
dzNocThsMWdFa29hSkltVFpHMHAwZmlRUFBlbCtZbmNVNHoyWnVDd2lhTlpkbTFhOWR5dlFH
NGFmWDE5VmxaV1NhVEtTc3I2OENCQXpTN0hydW5yejRzRG5pNmxxQnBFS0hTZGtQVUFTWkJH
Rk5YRFQ1RjBwNGVpWWI2ZTE4bFA0WS96YVNab2ZISmlvcUt3c0xDam80TzdsdVpoQkNiemRi
VTFNU3lyTWZqc2Rsc05MdU9sYWNMQjduSDB1NHUwbDR1M09UMTY5ZGJyZGJDd2tLYUF3QWlh
QnBFS0xYZGtIYUFTUkRvdTJySXBralUweU54b0t6blJQbEpoTk9Na1hRSGtvNUltVEZqeGtj
ZmZTUWNLU2dvT0hUb1VEQVliRzV1WHJod0ljMnVKODdUcGQxZHBMMWN1TW12dlBLS3orZDcr
dW1uYVE0QWlLQnBFS0hVZGtQYUFTWkJvTytxSVUyUnFLZEhRa0hqNmRMOEpNNXBKdXdPcERR
aXhHUXl1Vnd1cTlXYW1abkpmU1d3cmEwdE5UV1ZZWmpVMUZSUkp3OGxZdTdwdzhQRDNHTnBk
eGRwTHhkdXhRU3NkNkxJbUJwRUNOdHV5SGFBU1JBb2t5Wk5rV3hQajhRaHJLZEw4NU5vcHhu
ZkhVaGxoQ2MxTmRYdGRnZUR3WmFXRnU3emh1enNiSS9IdzdLczIrM095Y21oMldPc1BOMXV0
emMzTndjQ2dSMDdkZ2duQ0x1N1NIdTVFSHpkZjl4UU5vaVF0dDJRN1FDVElGQW1UWlFpYVUr
UFJFUDkzU3FibjRRNnpZVGRnWlJHaEt4WXNZTDNkSzYybURKbGlzZmpDUWFEVFUxTmNiNmVY
bDFkYmJQWjB0TFN0bTNieGdoNm93dTd1MGg3dVJCNCtyaVJiUkFoeWlxWGNGSGJEVkVIbUlT
Q0pta2tYSk9jb2FHaGlWTWNiMFRIemcrcXpPSHlreUNuR1hmSXd1NUEwaEVpeVZoWFY5ZWlS
WXZNWnJQRDRhaXZyeWVFMU5iV09od096amJyNnVwb2RvMTdHUUVBd0RqZ08wY0FBR0FjNE9r
QUFHQWM0T2tBQUdBY0p0clRjZkVkQUFCaUJ6NGpOUm8wVFVpRXJ4MTNHMnlDdjVvMHh5NU5r
YlJ0VHVKQWM1cEo4NE1PT2Vxbm1iUzdTd1R2eWpGNyt2VktjU1NtQzJpV01UVWg0ZHR1NEVV
azRaSWdmVmFsYlk3aG9Ubk5wUGxKNUE0NU5HOHhwZTR1bXZCMGhtRmVlKzIxdExTMDFOUlUv
cDlLaTM3aGZQWFZWd3NYTHVRNndIQWpzaDFnUUdTRWJVSWliTHZCVURTak1EeGhQVjJVSXFX
Mk9RbUZ5bW1ta3A4RTdKQkQ4eFpUNnU2aUZVL2Z2bjI3Mys5dmJHd1Uva0lXVHM3UHo5KzJi
WnZ3WDgzS2RvQUJFVURUaEVUYWRrTzlHWVhob1hubkNGT2sxRFluY1ZBL3paVHlrOGdkY3RU
ZllrcmRYYlRpNmNQRHcxSkJ3c2Rtczlubjh3blhrdTBBQThZS1RSTVNwYlliS3Mwb0RBL2xP
MGVhSW1IYm5NU0J2dGVOTUQ4SjNpR0hxTDdGbExxN2FNWFR3ejVlc0dEQnRtM2IrRGFOUktF
RERCZ1RsRTFJWk50dXFEZWpNRHcwN3h4UmlxUnRjeElFeXROTWxCOTB5RkYvaXlsMWQ5R29w
ek0zUWdqNTRvc3ZDZ29La3BLUytNbXlIV0RBbUJEbG1XdXlJVTJtYk9zU1VUT0t4RUY2Y2hL
RjdpWFNEaDZpdGprSkFzMXBKczJQN0ZvSmd1eGJUSlF4YVhjWDJUTlRIZHpMQ0FBQXhnSGZJ
d1VBQU9NQVR3Y0FBT01BVHdjQUFPTVFXMDlYdXRTT2EvRUFBQkFMNHZNWnFkS3RCVUFkMlhz
emVMak9MVFJOU0ZpV1hidDJiVVpHQnI4cEEvK0tyYSt2bno5L2ZuSnljbEZSRWZmbFpHblNw
QW1SSWsyK1VidVhVSjVtb3F4S2lVcjNFbDBnelpqMDJDUHJrQ1BOZkZqR2ZpOWpoempnNlJP
R1NycjR6aTAwVFVncUtpb0tDd3M3T2pwR1IwY3B0NjlmbkU1blIwY0h5N0lIRGh5WU5tMmE4
Q2srYVVvSkVTSk5qbEc3bDlDY1ppcFo1WWxLOXhKZElEMGk2YkZIMWlHSGg4OThXR0xvNmFK
ZnlHMXRiVGs1T1NrcEtSVVZGVXFlam40djZqQUtMU09FblZ0b21wRE1tREhqbzQ4K2t0MStq
SlRISGIvZlgxZFhOMi9lUEg1RW1EU2xoQWhSU2o0eFhQY1NtdE9NUTVwVklWSHBYcUlMcEJs
VE9uWVNVWWNjYWVaVmlHMmRMbnhxL3Z6NU5UVTFmcisvcXFwS3lkUFI3NFVHYWNzSVllY1dt
aVlrSnBQSjVYSlpyZGJNekV6Uk40OWlxanhlOEgrNmZ2bmxsL3lnTUdsS0NaRWlUYjVSdTVl
b24yWkVJYXRDb3RLOVJFY0lNNlowN0pGMXlKRzJabEpoNGp6ZGJEYjcvWDVDaU0vblUvSjA5
SHVoUk5neVFxbHppMG9Ua3RUVVZMZmJIUXdHVzFwYWhCZnBqUHBtSTRUNGZMNTkrL2JsNWVW
eFA0cVNwcFFRV1lUSk4zYjNrckNubVNpcklxTFN2VVJmOEJtVFBmYklPdVFvdmNHVm1EaFB6
OHZMNCtyMDZ1cHFmbno2OU9uQ1gvTG85MEtEcUdXRXRITkwyQ1lrSzFhczRDMU1xV3VtWVZp
NWNtVlBUdy9Mc25WMWRmemZzNktrS1NWRWlqRDV4dTVlb242YXlXWlZSRlM2bCtnSVljYWt4
eDVaaHh5aTBKcEpoVmg1T25NamhKQmp4NDVsWjJlbnBLU3NYNytlWDJYbnpwMVdxNVgvRWYx
ZTFPSFNJbW9aSWR1NVJkU0VSSlRNcnE2dVJZc1dtYzFtaDhOUlgxOVA1RjR2dy9EV1cyL05u
ajNiYkRibjVlVjVQQjV1VUpRMGFVSUlkYjhYSHNOMEw2RTV6V1N6S3NwWVZMcVg2QUpweHNJ
ZU8yV0hIQ0xKZkZqUTd3VUFBSXdEdmtjS0FBREdBWjRPQUFER0FaNE9BQURHSVQ3OVh1SzFI
UUFBTURhNi9Jd1VGcTlDVDA5UFNVbEpjbkp5U1VsSmIyK3Y3Qnhwc3c2YTloMEdoaVpwMGpt
SmZJOEFUY2FFRnNIZDlXL1VqQ2tkVjJWbEpUOUkyZTlGMUNXR0pzOGl4dXpweGN4Ym9vQ25h
NHFISG5ySTVYSUZBZ0dYeStWME9tWG5TSnQxMExUdk1EQTBTVk9hazVobkkwM0dlRVM5U295
YU1kRnhuVGh4Z3VzS3gvMUkwKzlGdGtzTWZaNDVZdWpwb2w5Y24zNzZhVzV1cnRsc3pzM041
VzY4ZHpnY1o4NmNJWVI4OTkxM0RvZURYOFZzTmhjVUZMUzB0TWh1Qi9kUXFwT2VudTcxZWdr
aFhxOVgvZXN6MG1ZZDZ1MDdEQXhOMHBUbUpPWjVTSCthU1h1VkdEVmp3dU5pV1RZdkwrL3R0
OStXSHF4S3Z4ZHBseGo2UFBQRXRrNFhQcFdUazdONzkyN3VlNlM1dWJtRWtKVXJWKzdjdVpO
aG1OMjdkei81NUpQOHpGQW8xTnJhT24zNmRObnRTSDhFUXBLU2trWkdScFlzV1JJS2haVDZ2
UkM1WmgzU2tjU0JKbWxLY3hMemJLUTh6WWhjcnhLalpreDRYTTgrKyt3amp6eENKQWVyM3U5
RjJpV0dQczg4RStmcEpwT0o3L2RpTnBzSklYdjI3TG4zM252dnZQUE9GU3RXdlAzMjI0U1E3
ZHUzYzErK1ltN3M5d0pQcHljOVBYMXdjSkJRL0dLWE51dFFiOTloWUdpU3BqUW5NYzlHeXRO
TXRsZUpVVE1tUEM3T3hFUlhGTUwyZTVGMmlhRi9PL1BFczA3djcrK2ZOR25TeXkrL2JMVmF1
VC9OVWxKU0doc2IvWDYvMiswV1hXOFJialk1T1ZuVTdCVHdQUGpnZ3hzMmJHQlpkc09HRFZ5
bElFWGFySU9tZlllQm9VbWEwaHlqT3BRNk5Ca2pDcjFLakpveDJlUGlCMm42dlVpN3hGRG1X
VWlzUEoyNUVVSklhMnRyVGs2T3lXVEt5Y25oRHl3N083dTN0NWUvZ1B2Q0N5L1liRGFiemJa
NTgyYm14disvSS94MXQyN2RPcTRuRE0wUkpocmQzZDJMRmkzaS9sVktUMDhQTnlqS2xiUlpo
Mno3anNTQkptblNPYkluWjRKQWt6R2kwSXpJZUJsVE9TNytSOUVjMlg0djBpNHhzbmxXUjVm
M01nSUFBSkFGM3lNRkFBRGpBRThIQUFEakFFOEhBQURqb0k5K0x3QUFBR2pBWjZSR0k3TFdK
UkcwbFRBU1NOcFlRY2JHeW9SbGJNeWUvaGJ6bGlqZzZab2lzdFlsRWJTVk1CSkkybGhCeHNi
S2hHVXNocDR1ZTZ2bSt2WHJyVlpyWVdFaEllVFlzV1B6NXMwVC9ZZFNNRTRpYTEwU1FWc0pJ
NEdralJWa2JLeE1XTVppVzZkTFBmMlZWMTd4K1h4UFAvMDBJV1QrL1BrMU5UVit2NytxcWdx
ZUhpMGlhMTBTUVZzSkk0R2tqUlZrYkt4TVdNWW0ydE9GM2NqTVpqUGZBUWFlSGkwaWExMFNR
VnNKSTRHa2pSVmtiS3hNV01ZbTJ0T0ZQK2JtNW5KMWVuVjFOVHc5V2tUV3VpU0N0aEpHQWtr
Yks4allXSm13ak1YSzAyVnZqQkhOYkcxdC9lbFBmNXFTa3VKeXVlRHAwU0t5MWlVUnRKVXdF
a2phV0VIR3hzcUVaVXdyOXpMQzB3RUFZUHhvNVh1azhIUUFBQmcvV3ZGMEFBQUE0d2VlRGdB
QXhpSE9ucjV6NTg3Smt5ZUh2ZkNDS3pNQUFFQkRuRDhqblQ1OStva1RKMFM3aUhocmdOQTFp
R0JaZHUzYXRSa1pHZnpMbDhpTk9FaWt2VGc0S2lzckUvQ2twWC92Qy9Pelo4K2VPWFBtV0N5
V2hRc1hIajE2Tk1ZYTQ0bjBTSVdHbVo2ZUxydFdmWDE5VmxhV3lXVEt5c282Y09BQU4rSndP
TGo3WHJxNnVtaDJQV1pQNzdndWp2R2MwTUovSk0zdkl1S3RBVUxYSUtLaW9xS3dzTENqbzJO
MGRKUitMUU1UV1M4T1FzaUpFeWU0WDQwVEpsVlRoRDF3VVg0ZWV1aWhreWRQQmdLQlBYdjJH
UHM3UnlwSHVucjE2ZzBiTnNpdVpiUFptcHFhV0piMWVEemMveU5OVDA5dmFXa0pCb051dC92
KysrK24yWFdzUEgzcjFxME9oOE5rTXZHL3pELzk5TlBjM0Z5ejJaeWJtOHY5UDFMWkc5aWx2
LytsNVFDRHZqSEswRFNJbURGanhrY2ZmVFRXdFF4TVpMMDRXSmJOeTh0NysrMjNFL2FzVXo5
d2xmejA5ZlZaTEJiaHQ4cU5pdWhJTDEyNmxKcWFldmJzV2RuSkJRVUZodzRkQ2dhRHpjM05D
eGN1SklTa3A2Y2ZQbnlZODNUS2YvNGVLMCtmUEhseVpXVmxSMGRITUJqa1JuSnljbmJ2M3Mx
OWF6UTNONWZmb0hRWHN2c1YvWWkrTVVyUU5JZ3dtVXd1bDh0cXRXWm1abkwvQWppUkczR1FT
SHR4UFB2c3M5eFgreEwyckZNL2NLWDhmUC85OThYRnhjODg4MHhzeFdrQTZaRnUzcno1c2Nj
ZVU1cmYxdGFXbXByS01FeHFhdXJ4NDhjSkliVzF0YmZkZHR1a1NaT2VlKzY1V1BWN29mVDBE
ei84OE41Nzc1MDdkKzR0dDl6eSs5Ly9uaEJpTXBuNDdpNW1zNW5mb0hRWHN2c1YvWWkrTVVy
UU5JaElUVTExdTkzQllMQ2xwWVc3dEpmSWpUaElwTDA0a3BLU292dk5POTJoZnRTeStmbnl5
eTluejU3dGNybEdSa1ltUkdQY2tCN3A4UEJ3Wm1ZbVo5YXlaR2RuZXp3ZWxtWGRibmRPVG83
d3FhTkhqODZjT1pObXY3RzluajR5TW5MMDZGR3IxVXFvNi9UazVPVHU3bTdwZmxWK1JOOFlJ
VFFOSWxhc1dNRjdPbWRQaWR5SWcwVGFpNE1uWWM4NnlnUG5wOVhVMUJRWEYzT1hYbzJON0pI
VzF0YVdscGFxckRWbHloU1B4eE1NQnB1YW1yanI2WVNRMGRIUnpzN08vUHo4aW9vS21sM0h5
dE81Mzh4SlNVbXpaczE2NDQwM0NDR3RyYTA1T1RrbWt5a25KNGMvVk9tNjY5YXRTMGxKa2Iz
Q0xod1Vyb0srTVVKbzJrcDBkWFV0V3JUSWJEWTdISTc2K25xbHRSS0h5SHB4OENUZ1dVZnp4
aFJPbGwxcmFHaG9ndVJPT0xKSHVtalJJdTVTcDNDYThNZmEybHFIdzhIWlpsMWRIYitkakl5
TU5XdldzQ3hMczJ1dDlIdUpGcG9TQXdBQUU0elJ2a2NLVHdjQUpESkc4M1FBQUVoazRPa0FB
R0FjTk8zcEdyeGVEd0FBV21aQ1B5T056SjNoNldPQzVrVVJ2bmJjL2VuMTlmWHo1ODlQVGs0
dUtpcjYrT09QSjBxc1ZxQkptclRmaXpTTmlRUE5DU1BOVCtKVWFaSDFlK0VRZHNpSklHTmo5
dlRya29DbmF4REtwUEd0SjV4T1owZEhCOHV5Qnc0Y21EWnRXb3pWYVJUMXBLbjBoRkhwNEdG
VXhuVENpUEtUQ08vb3lQcTlFSVVPUXByd2RHbS9GMmxkMzluWnVYanhZb3ZGTW5mdVhPNVhQ
ZmVzMld3dUtDaG9hV21KNEhnQUIwM1NwSzBuL0g1L1hWM2R2SG56WWlsTnU2Z25UYWtuakhv
SEQyTkRjOEpJODVOUTcrZ3g5WHRSNnBDakNVK1g5bnVSS2lzcUtucm5uWGRZbG0xcWFwbzdk
eTQvSGdxRldsdGJwMCtmSHNIeEFBNmFwSWxhVC9CL0ZYNzU1WmV4bEtaZDFKT20xQk5HdllP
SGdhRThZYVQ1U1p4MzlGajd2U2gxeU5HRXAwdjd2VWlWbWMxbXZuTG5tdTV1Mzc2ZCt4b1ZQ
ekxXNHdFY1laTW0yM3JDNS9QdDI3Y3ZMeTh2bHRLMFM5ZzZYZG9USm13SEQyTVQ5b1NSelUr
Q3ZLTWo2UGVpMUVGSUU1N09JZXozUWlTOVhJcUxpeHNhR2dLQkFEK1NrcExTMk5qbzkvdmRi
amUvMmVuVHB5ZHM1Umd4WVU4Q1VldUpsU3RYOXZUMHNDeGJWMWRIMmRMVGVLZ25UYmJmUzln
T0hrYUY4b1NSelU4aWVIcGsvVjU0dEZpbmM3OW5oUDFlaUtTWHk2bFRwKzY2Nnk1dWhCdDg0
WVVYYkRhYnpXYmJ2SGt6UDIzbnpwMVdxelVSem9Pb3dOd0lQeWlhSm1vOThkWmJiODJlUGR0
c051Zmw1WGs4bm9tVHF3MW9raWJiNzBYYXdTTkJrRDFod3A1bXNuazJKS0lqcGV6M0loMlBJ
R05HNi9jQ0FBQ0pqS2EvY3dRQUFHQk13Tk1CQU1BNHdOTUJBTUE0d05NQjBEVDR2QXFNQ1hn
NkFESkU3S1JSdDJDVkRVWmxYd3pEdlBMS0s0U1FsMTkrZVR3YlpCaG15NVl0NHhjbTdaUlNY
MStmbFpWbE1wbXlzcklPSERpZ3RIZlIvUm9zeTY1ZHU1YjducjJTSHZVZVBrb0twV3RKTmRN
Y2w4cmVWWTRyTFBCMEFHUklLRS9QeWNrWkhSMmROMi9lT0QwOU96djc2dFdyNHhRbTdaUmlz
OW1hbXBwWWx2VjRQUHgvNlZUU3dEK3VxS2dvTEN6czZPZ1lIUjFWMlplb2h3K05jdWxhS3Qx
ZFZJNUxxWU9RVkFNOEhZRHhJdnUrWW01c1JrVFQxRWg5eS94YUZSVVZLU2twOCtiTmEydHJJ
NFMwdGJYbDVPU2twS1JVVkZRSXR5emN1M1JmMGdaS3NnY2kxYk5reVpLWFhucHA2ZEtsM09S
UFAvMDBOemZYYkRibjV1WnkzNXBoR09hMTExNUxTMHRMVFUzZHRXdVgwbllxS3l0ZmZQRkZm
cWZTN1JRV0ZuTGlEeDA2dEhEaFFuVmhmS2VVZ29LQ1E0Y09CWVBCNXVabTliV0VCenRqeG95
UFB2cElaUUtSNitIRE1Jek5ack5hcmZmY2N3Ly9CY213YTBrMTB4eVgwbmJnNlFCRUg2VjNr
YkFaRVUxVEkvVXQ4MzVkWFYzdDkvdHJhbW9XTEZoQUNKay9mMzVOVFkzZjc2K3FxaExPVjIr
RnBOUkFLYXlldlh2M0ppVWw3ZHUzajl0Z1RrN083dDI3L1g1L2RYVjFibTR1TjJmNzl1MSt2
Nyt4c1ZHcERtVVlabWhvYU02Y09aY3VYVkxhenRhdFc4dkx5d2toWldWbDI3WnRVMUVsN0pU
UzF0YVdtcHJLTUV4cWFxcDZHd1poUWt3bWs4dmxzbHF0bVptWlN0OExVK3JoYy83OCtZcUtp
cEtTa2pHdEplM3VvbjVjU3R1QnB3TVFmYVR2SW1reklwcW1SaXBiSGg0ZTVqM2Q3L2NUUXZ4
K3Y4VmlJWVNZeldadXhPZnpjWE5vV2lGSkd5aU45VWk1eHlhVGlkKzcyV3pteG9lSGg5VVBr
QnZmdEduVDczNzNPNlh0L1BERER6YWI3Y3laTXphYjdlTEZpMHFTUkoxU3NyT3pQUjRQeTdK
dXR6c25KNGZ5V0ZKVFU5MXVkekFZYkdscFVlcFhMdHZEaHlNUUNIQ3ZCZVZhMHU0dVlZOUxh
ZS93ZEFDaWovUmRKTnVNaUlScmFpVEZicmMzTnpjSEFvRWRPM2J3bnM3VnN6VTFOZlBuenll
RTVPWGxjWFY2ZFhVMU4wZDI3MkViS0kzMVNGWHFkSlhNQ01kOVB0K3NXYk9VdGtNSWNUcWRk
OXh4UjFsWm1aSWVhYWVVS1ZPbWVEeWVZRERZMU5SRWZ6MTl4WW9Wdktjci9XMGgyOE9IRUhM
MTZ0V1hYbnFwdUxpWWNpM1o3aTVoajB0cDcvQjBBS0lQY3lORXJoa1I5NVI2VXlNcDFkWFZO
cHN0TFMxdDI3WnRvdXZwMmRuWng0NGRJNFFjTzNZc096czdKU1ZsL2ZyMVNudVg3a3ZhUUls
RWRDMm90YlUxSnlmSFpETGw1T1R3MTlObDU4dHVaOHVXTFVyYklZUWNPblNJWVpoRGh3NnA2
QkV5TkRSVVcxdkwvWTB5YTlhc3VybzZtclVJSVYxZFhZc1dMVEtielE2SG83NitYbGE4dElj
UHQvck5OOTk4MTExM25UNTlla3hyQ1RYVEhGZlk3Y2lPaEFXZURrQ2NHVk1WQm9BNjhIUUE0
Z3c4SFVRUmVEb0FBQmdIZURvQUFCZ0hlRG9BQUJnSGVEb0FBQmdIZURyUUJ3ME5EWTJOamFG
UXFMR3hzYUdoZ1hJVjlXZVZKdmg4UHJmYkxUdGZaUzBBdEFBOEhlaURob2FHVHo3NTVILy85
My8vK3RlL1JzdFZsYmJ6MVZkZlNaK0NsUU5kQUU4SCtxQ2hvZUhVcVZNZWorZlVxVk84dllv
ZU5EUTB0TGUzZXp5ZXpzNU9wVUhSTnFVN3VucjE2cUZEaDJROTNlUHhIRDU4ZUdCZ0lLcEhC
a0EwZ2FjRGZkRFEwUERERHovd1MzNVErS0Nob2VIaXhZcytuNC83VC9heWc2SnRTbmYweFJk
ZmRIVjF5VDQxT2pvNk1ERFEzTndjdmNNQ0lNckEwNEUrYUdob0dCMGRQWExreU9qb0tHKzRI
by9INS9QeExpKzFlT21nYUp1eU8xSzZiajQ2T2pvNE9BaFBCMW9Hbmc3MGdkQmgrY2Vkblow
ZWo2ZTl2VDBDVHhjWnQvUlo2WU9HaG9iRGh3K2ZPM2N1bWdjR1FGU0Jwd01BZ0hHQXB3TUFn
SEdBcHdNQWdIR0Fwd01BZ0hHQXB3TUFnSEdBcHdNQWdISDRoNmUzdGJYdEJRQUFvSDhZR0Rv
QUFCaUcvdzlSMWorN1dPODFFUUFBQUFCSlJVNUVya0pnZ2c9PSIgLz48L3A+PHA+Jm5ic3A7
PC9wPjxwPkluIENQVSB1c2FnZSBvZiB0aGUgRG9tVSwgdGhlcmUgaXMgYWxzbyBub3QgbXVj
aCB0byBzZWUsIGV2ZW50dWFsbHkgYSB2ZXJ5IHNsaWdodCBjaGFuZ2Ugb2Y8L3A+PHA+bWl4
OjwvcD48cD4mbmJzcDs8L3A+PHA+PGltZyBhbHQ9IiIgc3JjPSJkYXRhOmltYWdlL3BuZzti
YXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWZFQUFBRnNDQUlBQUFCVHFCZTNBQUFn
QUVsRVFWUjRuTzJkZTNBVVpiNzNtOHhNQ0lObUpnbGhBNFloQVVNdUpNRVFEZ0t2VXJ6V2Uw
VFJYWEVEdXF4b25WcFhUaDFBSXhHdDlXaXhXVUIyQlFRbGtDTUhoUkFJb3VuSkRiTENoa3Np
Y0lwQXdpS1N5QjNrbXBucHllMzU1NjE2LytEOW8zZmJabnBtK3BsT1pxWXYzMC85cW12eXpE
UGQzMzZtK3p1LzlQVDhIdWJ2QUFBQWRFRnpjek1UYlEwQUFBQUdnZWJtNXUzYnQvL0Qwd2tB
QUFBdHMzMzdkbmc2QUFEb0JIZzZBQURvQjNnNkFBRG9CM2c2QUFCb2lXb0o0bWZoNlFDRUJZ
WmhvaTFCRlJwQW1PanY3K2ZkSEo0T1FDUlFnNStxUVFNSUI3Mjl2YWRQbjJaWjlzNmRPelUx
TmVLbjRPa2c3TFMzdC8vcVY3OUtTRWlJalkyZFBIbnlybDI3K0hibW44VEh4Ny80NG92WHIx
OFgycVVyMFp3OXFVR3dHalNBUWFlenM3T2hvYUdscGVYU3BVczFOVFduVDU4V1B3dFBCK0hs
N05tenYvakZMelp1M1BqVFR6OXhISGYwNk5FWFhuaUJmMHB3bkd2WHJ2M21ONy81NVM5LzZk
TXVSblAycEFiQmF0QUFCcDBqUjQ3Y3VYTW4wTFB3ZEJCZVhucnBwYi84NVM5K254STd6czJi
TjYxV3E3VGRiK2RBamNLZlRxY3pPenZiWXJFNEhJN05temZ6alQvODhNT3p6ejQ3ZlBqd29V
T0gvdXUvL3V1MWE5ZjRkcmZiL2R2Zi90WnF0WTRjT1hMVnFsWENTbnA3ZTB0S1NrYU1HREZz
MkxDaW9xSjc5KzdSN3pVdlp0V3FWY25KeVZhcmRlSENoUnpIRVVKbXpKaXhZOGNPb1U5bloy
ZEtTb3I0L0V4UFR6OTE2aFQvK1BQUFArY2ZuRHAxS2owOVBZaWtRTzNDdm56MzNYZWpSNC8r
K09PUFE5b0ZvRVhnNlNDOGpCdzU4dkxseTM2ZkVqdnlyVnUzQnRIVGs1S1NkdS9lelhGY1oy
Zm5hNis5eGpkbVpXWHQzNy9mN1hiZnVYTm44ZUxGTDcvOE10LysxbHR2UGZmY2M5ZXZYNzkr
L2Zxenp6NHJyT1RERHo5ODZxbW5MbHk0Y08vZXZWZGVlZVgzdi84OS9WN3pZbWJQbm4zdDJy
VnIxNjdObmozNzdiZmZKb1RVMXRabVptYjI5Zlh4ZlY1NzdiV1ZLMWVLWC9YR0cyOXMzTGlS
RUhMaHdvV0hIbnFJZCtjTkd6WXNXclFvaUtSQTdmeStWRmRYanhneFl1L2V2U0hwQjZvRjk3
MkFhR0kybTN0NmV2dytKYmpuOWV2WFgzbmxsZWVlZTg2bjNXL25JSTNDbjZtcHFldlhyNzl3
NFVJZ1ZTNlhhOFNJRWZ6ajBhTkgvL0RERC96ajc3Ly9YbGlKdytFNGMrWU0vL2pxMWFzalI0
NE10RGEvTUF6ei9mZmY4NC9QbmozN3lDT1A4SThMQ3d1Ly9QSkxvZEhsY29sZjlmWFhYeGNW
RlJGQ1ZxNWNPV0xFQ1A2ZmpGLy8rdGZmZlBOTkVFbUIyaG1HK2VTVFQwYU5HdFhjM0J5U2VL
QitjTjhMaUE3QjgzU2VoeDkrK0lVWFhyaDY5U3JmSGhNVDA5dmJLKzdaMjlzYkV4UGpkdzEr
LzJ4dWJuNzIyV2NURXhQVDB0SjROeVNFSERwMGFQcjA2VmFybGQvb2tDRkQrSGFUeVNSc3Jx
ZW5SMWlKMld4bVJBajkvZTZDMzZmRXF6V2J6Znpqdlh2M1ptUms5UGIyenA4L2Y5MjZkVDZ2
NnVycUdqTm1EQ0ZrNHNTSkxNcysvdmpqaEpBeFk4YncxaDlJVXFCMmhtSFMwdExlZWVjZHFU
eWdhWERmQzRnYUw3MzAwdHExYS8wK0ZlZ2JQSWZEOFQvLzh6L2lsdVBIanpzY0RtbFBzOWtz
NUxrLy9mU1R6d3I3Ky90Wmx2M0ZMMzdCL3psNjlPaUtpb283ZCs3MDkvZmZ2WHRYNkR4cTFD
aS9lWHBxYXVyRml4Y3BkdEUvNGp6OSsrKy9IejE2dEtCcTRzU0p4Y1hGRG9mRDYvVktYL2pr
azAvdTNMbXpzTENRRUZKWVdMaDM3OTZaTTJjR2x4U29uV0dZQ3hjdWpCczNidlhxMVlwM0JL
Z04zUGNDb3NuWnMyZFRVbEkyYmRwMDgrWk5qdU9hbTV1bDk3MzQ4S2MvL2FtZ29PRElrU01j
eDNFY2Qvanc0VW1USnZsMXBZS0NnZzgrK01EbGNsMjhlSEh1M0xuQ0N1Zk5tM2Y2OUdtdjE4
dXliRkpTRXQrWWtKQ3dkKzllanVOKytPR0hvcUlpb2ZPYmI3NzUvUFBQMzdoeDQ4YU5HK0xy
NlgvODR4OW56NTU5N3R5NW5wNmVreWRQOHBkRTZHRVk1dGxubitVdjB6L3p6RFBGeGNYQ1V4
VVZGUXpEYk5teXhlOExWNjVjT1hyMGFENkZYN3QyN1NPUFBMSnExYXJna2dLMTgvdHk2ZEts
akl5TTB0TFNrUFFEMVlMN1hrQ1VhV3RyKytVdmYybXoyV0pqWXdzTEM4WDNwL3Z0MzkvZnYy
N2R1b2tUSnc0ZE9uVG8wS0VUSjA3ODVKTlAvUFk4ZnZ6NHBFbVR6R2F6dytIWXVIR2pzTUlk
TzNaa1pHU1l6ZWJzN096YTJscSs4YXV2dmtwTFN6T1pUR1BHakZtM2JwM1EyZVZ5L2VZM3Z4
azJiRmh5Y3ZJZi8vaEhpOFhDdC9mMTlaV1dsam9jRG92RmtwT1RVMUZSRWRKZWkrOTdlZVdW
Vnp3ZWovRFVybDI3eG84ZkgraHJoaE1uVHBqTlp2NXUvV3ZYcnBuTlp1Ry9sa0NTQXJVTCsz
amx5cFhNek13UFAvd3dwRjBBV2dTZURzRFB0TGUzangwN050eGJtVE5uenZidDI4TzlGYUJY
Y044TEFESXNXYkxrMXExYlY2NWNtVDE3OXRLbFM4TzNvYjYrdnJLeXNxeXNMT0YyUmdCQ3hj
ZkU0ZWtBK1BMeHh4OG5KU1VOSHo3OHBaZGU2dXJxQ3QrR0dJWnhPQnk0c3hBTWhKcWFtdTd1
YnY1eGQzYzM3bnNCQUFBTjA5emNmT3JVcVo2ZW5wNmVubE9uVHJXMHRJaWZoYWNEQUlDVzhI
ZzhSNDhlZFRxZFRxZXp1YmxaL1BVN2dhY0RBSUNtd2ZWMEFBRFFEL0IwQUFEUU1BYTZsL0Zj
WStPNXhzWm9xd0FBZ01paFcwL3Y0YmdOMDZkdm1ENjloK09pclFVQUFDS0ViajM5Yng5L1hP
cHdsRG9jZjBQaGZ3Q0FVZEdKcDkrNWNHRjFSZ2J2NmFzek11NEVMcHdOQUFDYXh1MTJOemMz
Qy9jeXV0MXU4Yk5xOFhScEhlcUxGeTlPbXpZdE5qWjIyclJwZkIxUmFZdEE1YXV2OG9iT1Ir
V3JyMFo2QndBQUlDSTBOVFdkT1hPbXU3dTd1N3U3dmIyOXFhbEovS3hhUEoxSDdPbno1czBy
S1NueGVEd2xKU1h6NTgvMzIrTERlKys5UndpNWRPa1N6YmE2MjlwaysxQ3VpcVliVk5GM2d5
cjZibEJGMzAyZHFoVEFzcXhRTDZpdnI0OWxXZkd6NnZYMHBLUWtmdUticTFldjhpV3dwUzAr
dlBmZWUvZmJtTmFhLzNPL2paRU56K3A4MlQ2VXE2THBCbFZRRlJWVmhjeFdGYXBTNTFoRldK
VmluOVJxbmg0VEU4Ti9GdlgyOXBwTUpyOHRBcjAvL1hUM3M4K1d2L0VHMlo3NmYwOE9JOXRU
NzdjeHdaZTlXOGJKOXVuNVFyNFA1UmFoQ3FxaW9tcFo2Z29WcWxMbldFVlkxZi9qdUx1ZmZl
WnRiUTNWSjEwdWx3YXVwL09JUFQweE1kRW5LNWUyK01EbjZWY081dDZuK0FnbEZhbXlmU2hY
UmRNTnFxQXFLcXI0UEYxdHF0UTVWcEZXZGY5K09GeFV2WjVlVkZRa1hEM241K0tTdHZqQWV6
b0NnUkNDOTNTRUdrT3BwMnZzdmhmaDdwY2ZmL3h4NnRTcEZvdmw4Y2NmdjNEaGd0OFdINUNu
UXhWVStRVHlkUFdxVXVycFdycWVQa0NRcHlNUVBvRThYYjJoMU5PMWROL0xBRUdlRGxWUTVS
UEkwOVdyQ25tNkxNalRFUWlFWmtLcHAydnB2cGNCZ2p3ZHFxQUtxalNqeWdqM3ZRd1E1T2tJ
QkVJem9kVFREVkUvdmJ1N3U2T2o0M2UvKzkzOU51WUVPK2QrRzNQMTRNVGdTMUtSS3R2bnlz
RmMyVDZVVzRRcXFJSXFxQkl2TDE2ODJOSFJvYUIrZ0krSis2QVRUK2RCbm81QUlEUVRBOGpU
Z3p5clEwOVgzVld6VUZZRlZWQUZWVVpSQlUrWEJYazZBb0hRVE9BN1VsbVFwME1WVkVHVlps
VEIwMlZCbm81QUlEUVRpang5Ly83OXJhMnRWNjllN2UzdDlkdEJ2WjdPc3V5NGNlTmlZMk5u
enB6SmwyTU1NczhSRC9KMHFJSXFxTktNS2tXZWZ2ZnUzWFBuemgwK2ZMaW1wdWJ3NGNQbnpw
MjdlL2V1dUlONlBUMDVPWmxsV1k3aldKWmRzR0FCb1p2bmlHYWdFUWdFSXZveHNHc3ZQVDA5
VjY5ZWJXMXQzYjkvdjdoZHZaNmVsSlRFc3F6WDYyVlpkc1NJRVlSNm5pUFZmUnFIc2lxb2dp
cW9Nb29xbzExUHI2cXFHak5tekxCaHd4WXZYbXcybXduMVBFZjNLZVlmd1JKTExMR003bEx4
UEVmQlVhK25DN0FzNjNBNENPWTVnaXFvZ2lvOXFUSmFuazRJNmUvdlAzMzZkRlpXMXAvKzlD
ZUNlWTRRQ0lTZVlwQThYVFAxWHZnSmoxSlNVdjd6UC8rVHYrU0NlWTZnQ3FxZ1NqK3FqT2Jw
Q2tDZWprQWdOQk9veXlnTDhuU29naXFvMG93cTVPbXlJRTlISUJDYUNYaTZMTWpUb1FxcW9F
b3pxZ3g0M3dzOTRqa3hhR3JWWTRrbGxsaEdkNmw0VGd5MzI0MzVTSkVqUUJWVVFaWEtWQ25O
MDV1YW1zNmNPZFBkM2QzZDNkM2UzdDdVMUNSK1ZvZWVqa0FnRUJvSXBaN09zaXgvZXpjaHBL
K3ZqMlZaOGJNNjlIVFZmUnFIc2lxb2dpcW9Nb29xNU9teUlFOUhJQkNhQ2FXZTduSzVjRDNk
VHhnOVI0QXFxSUtxNktveTJuMHZWVlZWNmVucEpwTXBMUzJ0cXFxS1VNK0pnVUFnRUJvSW8v
Mk9ORDQrM3VsMDhuTmkyR3cyUWowbmh1bytqVU5aRlZSQkZWUVpSZFVBUEoySWZtcWtHVS9Q
emMxMU9wMzhuQmo1K2ZtRWVrNE1CQUtCMEVBbzlYU24wM252M2oyV1plL2V2WHYzN3QzYTJs
cnhzK3IxOUtOSGo4Ykh4ek1NRXg4ZmYvVG9VVUk5SjhhVmc3azBOZWs5Sy9ObCsxemRORTIy
RCtVV29RcXFvQXFxeEV2RmMyS2NPbldxcHFhbXM3TnovLzc5VHFmei9Qbno0bWZWNituang0
OFhycjA4K3VpamhIcE9EQVFDZ2RCQUdPMDdVcnZkTGx4N1NVaElJTlJ6WXFqdXFsa29xNElx
cUlJcW82Z3kybmVrbFpXVkRvZkRaREtOSFR0MjkrN2RoSHBPREFRQ2dkQkFHQzFQVndEeWRL
aUNLcWpTakNwNHVpekkweEVJaEdZQ25pNEw4blNvZ2lxbzBvd3FlTG9zeU5NUkNJUm1RcW1u
bzM2Ni96QjZqZ0JWVUFWVjBWV0Z1b3hCd0R4SFdHS0pwYmFXaXVjNVF2MzBhSDhhcXpOSGdD
cW9ncXJvcWtLZUxndXVweU1RQ00wRTZxZkxnandkcXFBS3FqU2pDdmU5eUlJOEhZRkFhQ2FN
Vmh0QUFjalRvUXFxb0VvenFveFdQNTBSa1ppWVNERFBFUUtCMEZNWXpkTUZEaDgrL082Nzd4
TE1jd1JWVUFWVmVsSmxXRStmUFh2MjVjdVhDZVk1UWlBUWVvcEIrbzVVWTU3ZTFOUzBZTUVD
L2pIbU9ZSXFxSUlxM2FoU1BNK1JEeHJ6OUZtelpoMC9mcHgvakhtT0VBaUVmc0tBOTcwY09I
RGdpU2VlRVA3RVBFZFFCVlZRcFI5VkJyejI4dVNUVDM3MTFWZkNuNWpuQ0lGQTZDY002T21o
Z2p3ZHFxQUtxalNqQ3I4amxRVjVPZ0tCMEV3WThIcDZxQ0JQaHlxb2dpck5xRUtlTGd2eWRB
UUNvWmxBbmg0RThad1lKOWc1OXlscTBwT0tWTmsrVnc3bTB0UzJwOWtpVkVFVlZFR1ZlS2w0
VGd4Q2lOZnJQWERnUUUxTnpmWHIxMzJlMG9tbjh5QlBSeUFRbWdtbGVUcHY2R2ZPbkxsMTYx
WmRYZDJkTzNmRXorclEwMVYzMVN5VVZVRVZWRUdWVVZRcDlmUnZ2LzFXc092TGx5ODNORFNJ
bjlXaHB5TVFDSVFHUXFtbiszajErZlBueFgvcTBOTlY5MmtjeXFxZ0NxcWd5aWlxOEIycExN
alRFUWlFWnNKb3RYYjcrdnJlZi8vOVVhTkdEUmt5aEdFWVFqMG5odW8ralVOWkZWUkJGVlFa
UlpYUlBIM0ZpaFVUSmt4b2JXM3Q3Ky9uV3lqbnhFQWdFQWdOaE5FODNlRndzQ3dyYnFHY0Uw
TjFuOGFockFxcW9BcXFqS0xLYUw4ak5abE1TNVlzR1Rac21NUGgyTHQzTDZHZUUrTStSYTE2
TExIRUVzdm9MaFhQaWFIVjcwaVRrcEpZbHVVNGptWFpFU05HRU9vNU1WVDNhYXpPSEFHcW9B
cXFvcXRxWUhsNmYzKy96MFVZSHZWNit2ejU4MW1XOVhxOUxNc21KeWNUNmpreEVBZ0VRZ014
QUUvdjdlMDlmZm8weTdKMzd0eXBxYWtSUDZWZVQ3OTA2ZElUVHp4aHNWalMwOVA1Qyt1VWMy
S283dE00bEZWQkZWUkJsVkZVS2ZYMHpzN09ob2FHbHBhV1M1Y3UxZFRVbkQ1OVd2eXNlajFk
QWNqVEVRaUVaa0twcHg4NWNzU254b3NZSFhxNjZqNk5RMWtWVkVFVlZCbEZsZEh1ZTFFQThu
UUVBcUdaZ0tmTGdqd2RxcUFLcWpTakNwNHVDL0owQkFLaG1ZQ25Cd0h6SEVFVlZFR1Z0bFFO
Wko2aklPakUwM21RcHlNUUNNMEU4blJaY0QwZHFxQUtxalNqQ3A0dUMvSjBCQUtobVlpaXAz
LysrZWNKQ1FrSkNRbi8vZC8vSFE0Umd3WHlkS2lDS3FqU2pLb0llenJIY2NKanU5M2UwdExT
MHRLU2tKQVFEaEdEQmZKMEJBS2htWWl3cDQ4Wk02YTh2THkzdDVkRXlkTVpFWHdMNWptQ0tx
aUNLdjJvaXJDbk56VTF6Wmd4SXlNalkrZk9uVnUyYkxIYjdYYTcvZlBQUHcrSENMOElWaTZB
ZVk0UUNJUitJaXJYMDUxTzUyT1BQWmFmbis4ejVWQUVZQmptNFljZnRscXRzMmZQN3Vqb0lK
am5DS3FnQ3FyMHBDckNuaTU4TDdwMTY5YWRPM2RtWkdSTW16YnR3SUVENFJBUmhHdlhyaFVY
RjArZE9wVmduaU1zc2NSU1IwdkY4eHdGSjZDbkp5UWtORGMzQzlmUWUzdDd0MnpaTW1iTW1N
SGRQQTF1dDl0aXNSRE1jd1JWVUFWVmVsSVY0VHpkNy9laTRwdGhJc1B0MjdmZmUrKzl3c0pD
Z25tT0VBaUVuaUxDbmw1ZVhoNzU3MFhGOEhlOHhNWEZ6Wm8xNit6WnN3VHpIRUVWVkVHVm5s
VGhkNlN5SUU5SElCQ2FDWGk2TE1qVG9RcXFvRW96cXVEcHNpQlBSeUFRbWdsNHVpekkwNkVL
cXFCS002cmc2VUVRejRsQlU2c2VTeXl4eERLNlM4eUpJUS95ZEtpQ0txalNqQ3JrNmJMZ2Vq
b0NnZEJNd05ObFFaNE9WVkFGVlpwUkJVK1hCWGs2QW9IUVRNRFRaVUdlRGxWUUJWV2FVV1ZN
VDMvLy9mZERuUk1EZ1VBZ05CQUc5UFNXbHBhVWxCVEIweW5ueEZEZHAzRW9xNElxcUlJcW82
Z3ltcWQ3UEo2SkV5YzJOallLbms0NUp3WUNnVUJvSUl6bTZZc1hMLzd6bi85TVJKUFlVYzZK
Y2VWZ0xrMU5lcy9LZk5rK1Z6ZE5rKzFEdVVXb2dpcW9naXJ4TXRKellrU2RJVU9HK0V3elRU
a25CZ0tCUUdnZ2pKYW5Dd2g1T3VXY0dLcTdhaGJLcXFBS3FxREtLS3JnNlpSellpQVFDSVFH
d3JDZVRnL3lkS2lDS3FqU2pDcDR1aXpJMHhFSWhHWUNuaTRMOG5Tb2dpcW8wb3dxZUxvc3lO
TVJDSVJtQXA0dUMvSjBxSUlxcU5LTUtuaDZFRERQRVpaWVlxbXRKZVk1a2dkNU9sUkJGVlJw
UmhYeWRGbHdQUjJCUUdnbTRPbXlJRStIS3FpQ0tzMm9ncWZMZ2p3ZGdVQm9KdURwc2lCUGh5
cW9naXJOcURLYXAxZFVWR1JrWkZnc2xyeTh2SWFHQm9KNWpoQUloSjdDYUo2K1lNR0NqbzRP
dDl1OWMrZk94TVJFZ25tT29BcXFvRXBQcW96bTZUd2N4KzNldlRzM041ZGduaU1FQXFHbk1L
Q244N05oMk8zMkkwZU9FTXh6QkZWUUJWVTZVbVc0ZVk1NCtHc3Y0OGFOSTVqbkNJRkE2Q21N
bHFjdlhyejQrdlhyYnJkNzE2NWRJMGVPSkpqbkNLcWdDcXIwcE1wb25sNWVYajVxMUtqWTJO
akpreWYvOWE5L0paam5DSUZBNkNtTTV1a0tRSjRPVlZBRlZacFJCVStYQlhrNkFvSFFUTURU
WlVHZURsVlFCVldhVVFWUGx3VjVPZ0tCMEV6QTA0TWduaFBqQkR2blBrVk5lbEtSS3R2bnlz
RmNtdHIyTkZ1RUtxaUNLcWdTTHpFbmhqekkweEVJaEdZQ2Vib3N1SjRPVlZBRlZacFJCVStY
QlhrNkFvSFFUTURUWlVHZURsVlFCVldhVVFWUGx3VjVPZ0tCMEV3WXpkTXJLeXV6c3JJVXpJ
bWh1ay9qVUZZRlZWQUZWVVpSWlRSUGYvSEZGMXRiV3owZXorYk5tL2txakpSellpQVFDSVFH
d21pZUx0RFIwZUZ3T0FqMW5CaXErelFPWlZWUUJWVlFaUlJWeHZUMEsxZXVGQlFVZlAzMTE0
UjZUb3o3RkxYcXNjUVNTeXlqdXpUaW5Cak56YzBPaDJQYnRtMzhuNVJ6WXFqdTAxaWRPUUpV
UVJWVVJWZVYwZkwwc3JLeTVPVGt1cm82b1lWeVRnd0VBb0hRUUJqTjA1a0g2ZXJxb3B3VFEz
V2Z4cUdzQ3FxZ0NxcU1vc3BvbnE0QTVPa0lCRUl6QVUrWEJYazZWRUVWVkdsR0ZUeGRGdVRw
Q0FSQ013RlBsd1Y1T2xSQkZWUnBSaFU4WFJiazZRZ0VRak1CVHc4QzVqbUNLcWlDS20ycHdq
eEg4aUJQUnlBUW1nbms2YkxnZWpwVVFSVlVhVVlWUEYwVzVPa0lCRUl6QVUrWEJYazZWRUVW
VkdsR0ZUeGRGdVRwQ0FSQ00yRTBUeGNxdlFndG1PY0lxcUFLcXZTanltaWV6aVAyZE14emhF
QWc5QlB3ZE14ekJGVlFCVlg2VVFWUHh6eEhXR0tKcFc2V1Jwem5pRHpvNlpqbkNLcWdDcXIw
b3dwNU91WTVRaUFRK2dtamViclBQRWVFRU14ekJGVlFCVlg2VVdVMFQxY0E4blFFQXFHWmdL
ZkxnandkcXFBS3FqU2pDcDR1Qy9KMEJBS2htWUNueTRJOEhhcWdDcW8wb3dxZUhnVHhuQmcw
dGVxeHhOSVF5OVVUNzVkR1c0UEtsOUViSDh5SklRL3lkS2lDcWdlaWxHRVc3Vk9kS2pXTkZi
Tm9uekJLa1ZhRlBGMFdYRTlISU1UQkxOckhlOWI5MHVpTFVXZndReVQyOU1nRlBGMFdtVHo5
d1NOYkRUbUNOS0JLTTZvQ3VPUmdxbG85MExGaUZ1MWoyaGhtMFQ1U2pIY3dRSjcrejRpQ0tu
aTZMTUh5OUZMa0xJakJqSDhjUytIZXhBRFh3RWUwOGxBdGhOVFRJeGZ3ZEZtQzVPbi9TRmhF
eDdjYWNnUnBRSlZXVkFVeXlrRlVsVnV5ZDBDckt2M1pzSDVWa1NxYnpTai83MEd5WmsyOGd6
NURKT3dDOHZUSVFUVW5oczlSVy9xUFlOb2VDS0ZkL3lFWkNnMkV6enZZRnVEWlFWbS9zaWdW
SlhlRHVGckpKbVJXRzNTN1ArY3hnNXF0KzY2a1ZQSXZTemhHSXp6eHdCRDUvY2ZMNzc0TTFu
SCtUMCt2Zk8yMTJ6LytPRmcrcVNWUHA1b1RvNVM1c2pwWEdEWGZ3MXIwL3BIaTFQdWxvbTlJ
U24vK0JseUkzSks5NGovRm5jVTlBM1dqWE5YUGY3WXh2M3J0VStrbUtGWDUzV0x3bzhwM3JF
VGJFaHJ2bHpMOFdQMTg5b3BlSXZTL3NqcVhYaFcvc3o3cjhhdktSNTY0cDZBcVVKOUFZeVU5
Uy8rUlQ0VTBWdjlNRG53MktsVVZmRldCZ21samNnL21CczgvK0IwTXNnWnhuaTZiemRDb3Vs
L0s1QjU4b0p0NEtHUlVTVDRWb3A2blM1MkI4aDBNZUZ3OWVLcnlRK3IzdEdJVzdSTTh2ZFRo
V0QxaHd0OCsvcmpINHhtNFQyckowMm5teFBEdjRBaUVUNGl2eGJVRi91eEhoUFV0K09lbis4
OS9pdCtVSUs5cUV4bWwzNWZUdktIUmZ0UEZuczdIeHYvMXY3N2Z2MytBUHFrbFQvYzdKMFo3
ZS9zNzc3eFRzblRwVzg4Ly83OW56SGo3bFZmKzdkLys3ZTFYWG5ubm5YZUNMOTk4K21uWlBy
OS80UVhaUHBSYmhDcW9naXFvRWk5NTExcjJ1OS85N09relpueS9iOThBZlZKTG5rNHpKd1lo
NVB6NTh6UnI4eHc4S051SGNsVTAzYUNLdmh0VTBYZURLdnB1NmxSRi9ubnQ1ZUJmL21LNGF5
ODBjMklRUXJ4ZUw4M2E3bTdlTE51SGNsVTAzYUNLdmh0VTBYZURLdnB1NmxSRkNLbDg5ZFhi
blowMFBXblFrcWZUeklsQnY3YmU2OWNIVDlxZ0FWWDBRQlU5VUVXUE9sWFJveVZQbDZWMXNH
ZHJCUUFBYmFFclR3Y0FBSU1EVDFkSVpXVmxWbGFXeFdMSnk4dHJhR2dnb2dsVVZhVksycUlH
VlJVVkZSa1pHV3BUeGZQKysrOUg4VTBNY2x5cFNsVmZYOS83Nzc4L2F0U29JVU9HUkV0WThM
RktURXhVaWFxcXFxcjA5SFNUeVpTV2xsWlZWUlZ1QWZCMGhiejQ0b3V0cmEwZWoyZno1czNp
bTNDaTYrbFNWWUYwUmxmVmdnVUxPam82M0c3M3pwMDdvM1h1K1IyWmxwYVdsSlNVS0w2SlVs
WFJQYUo0cEtwV3JGZ3hZY0tFMXRiVy92NSs5YWdTT0h6NDhMdnZ2cXNTVmZIeDhVNm5rK000
bG1WdE5sdTRCY0RUQjBwSFI0ZkQ0UkQrVk1NWlNDU3EvTFpFSGg4TkhNZnQzcjA3TnpjM2lw
S0lTSlhINDVrNGNXSmpZNk1hM2tSQkZjTXdEei84c05WcW5UMTdka2RIaDBwVU9Sd09sbVdq
SzBaQWVtelBuajM3OHVYTDBkTERJNmpLemMxMU9wMWVyNWRsMmZ6OC9IQnZGNTQrSUs1Y3VW
SlFVUEQxMTE4TExXcXdBNmtxYVV2VVZmSC9JTnZ0OWlOSGpxaEUxZUxGaS8vODV6OFRGYnlK
MHZmcjJyVnJ4Y1hGVTZkT1ZZa3FrOG0wWk1tU1ljT0dPUnlPdlh2M3FrUVZUMU5UMDRJRkM2
SW9pVHlvNnVqUm8vSHg4UXpEeE1mSEh6MTZOTnliaHFjcnA3bTUyZUZ3Yk51MlRkd1lkVHVR
cXZLck0rcXFDQ0g4dFpkeDQ4YXBSQlYvYVRqcUY2OER2Vjl1dDl0aXNVUkZFcEdvU2twS1ls
bVd2NTR3WXNRSWxhamltVFZyMXZIang2TWxpVWhValI4L1hyajI4dWlqajRaNzYvQjBoWlNW
bFNVbko5ZlYxZm0wUjlmVHBhb0M2WXl1cXNXTEYxKy9mdDN0ZHUvYXRXdmt5SkVxVVNVUXhU
Y3hrS3JidDIrLzk5NTdoWVdGMFJEbFI5WDgrZk5abHVXdkp5UW5KNnRFRlNIa3dJRURUenp4
UkZUMDhFaFYyZTEyNGRwTFFrSkN1QVhBMHhYQ1BFaFhWNWRQaXpwVmRYVjFxVUZWZVhuNXFG
R2pZbU5qSjArZS9OZS8valh5a3Z5cUVqOFZGVWwrVmZFUDR1TGlaczJhZGZic1daV291blRw
MGhOUFBHR3hXTkxUMDZOMVlkM3ZPL2prazA5KzlkVlhVZEVUU0ZWbFphWEQ0VENaVEdQSGp0
MjllM2U0QmNEVEFRQkFQOERUQVFCQVA4RFRBUUJBUDhEVEFRQkFQOERUQVFCQVA4RFRBUUJB
UDhEVEFRQkFQOERUZ1VHSjRrM29BSVFQZUxxVzhIcTlTNWN1SFRGaXhFTVBQYlJ5NWNwb3k5
RUdETU9zV2JPR0VQTFJSeC9CeHlscGJXMWxHQWFUekZDaXFtTU1ucTRsbGkxYjl2enp6MSsr
ZlBuMjdkdHZ2dmxtdE9Wb0E0WmhNak16Ky92N0oweVlFUFh6VFN1c1hyMDZKaVptOWVyVjBS
YWlEVlIxak1IVHRjVG8wYU45WmlJWEgwRENZNFpobGkxYlpyVmFoY0tlVVQvT29nakRNTk9u
VDEreFlzV01HVFBFUStRemRHdlhyazFJU0xEYjdadi9PY1d3a1FkdDFxeFpyNzMyMnF4WnMv
Zy84L1B6K2VrZDZ1dnJKMDJhUkFocGFXbkp6TXlNaTRzcktTa1JqMnEwQkVjWDZUSEdIMkJt
czFtWUdlT05OOTc0N1c5L1N3aFpzR0RCb2tXTGhCY091aGg0dXBZd21VeTl2YjNpbGtDZXZt
Yk5HcGZMOWZycnIwZFVueXBoR0diNzl1MHhNVEU3ZHV6d08xejg0dzBiTnJqZDdwcWFtbWpO
SEtJZVhDN1g4T0hETDErK1BIejRjSmZMUlFoWnQyN2QvUG56Q1NIejVzMWJ2MzQ5SVNRM04v
ZlRUejkxdVZ5Yk4yODJySlVMQkRyR2VudDdtNXFhVWxKU0NDRTlQVDFQUGZYVXYvLzd2ei8x
MUZNOVBUM2hFd05QMXhKQjh2U2VuaDZ4cDNkM2QwZGFuRm9KNHVQaXg4SnBCb2VxcnE0V1Ns
QlZWMWNUUW03ZXZHbXoyYzZmUDIrejJXN2R1a1VJTVp2TmJyZWJFT0oydXpGaTB1TnF3NFlO
RG9jakppYUdZWmdoUTRid1Q3VzB0REFNMDlMU0VsWXg4SFF0VVZ4Yy9Qenp6MSs1Y3VYT25U
dkZ4Y1dFa0tTa3BMcTZPby9IczNIalJ2d0w3QmRLVC9mNzJKZ3NXclNJL3daKzVjcVZ3bFdD
b3FLaXh4NTdiTjY4ZWZ5ZkV5ZE8zTFJwazl2dC9xLy8raStNbVBUNGlZdUxxNm1wY2J2ZExN
dnlMVzYzT3k4dmIvYnMyWGw1ZVI2UEozeGk0T2xhZ3VPNC8vaVAvMGhLU2hMdWV5a3JLN1Ba
YkFrSkNldlhydy9pNlVZKzY2VG5tMDgxVkw5OWlJRUhMVDA5L2VUSms0U1FreWRQcHFlbjg0
MzE5ZlVNdzlUWDEvTi9OamMzWjJSa3hNWEZ2ZjMyMnpFeE1YeWpZVWRNZXZ4ODhNRUhOcHZO
WnJPdFdyV0tiMW00Y09ITEw3OU1DSG5wcFpkZWZmVlY2UXNIQzNnNkFFQWhmWDE5WDMzMTFZ
UUpFNkl0QlB3TVBCMEFvQVQrU25GNmVucTBaalVCZm9HbkF3Q0Fmb0NuQXdDQWZvQ25Bd0NB
ZmdqTjA1a0FES0lndzM1MVBsaDBkblpPblRvMU5qWjI2dFNwUC83NG85OCtWVlZWNmVucEpw
TXBQVDE5ejU0OWhCQ080NVlzV1pLY25Eem9iNmdtb0JtMGJkdTJqUnMzem1LeFRKbzBxYkd4
a1R4NE9pUW1Ka1pXY3BSUmRwaEp4OUJvbEphV0JqbS9wSTVhVlZXVm5aMGRHeHRiVUZCdzRN
QUJtazJFN3VsdGtvQ25xNG01YytlV2xKUjRQSjZTa3BLaW9pSy9mV3cyVzIxdExjZHhUcWZU
WnJNUlFvcUxpL1B6ODl2YTJ2cjcrNFpJZDJ3QUFCa2ZTVVJCVkNNcVZ4M1FETnJjdVhOUG5q
enA4WGkyYmR2bTgxdlRSWXNXTFYrK1BBSTYxWU95d3l6SUdCcUJFeWRPOEdsVDhHN2lEa1ZG
UlcxdGJSekg3ZG16WitUSWtUUmJDWmVucjF1M3p1RndtRXdtNFdObnlwUXAvTTJ0RlJVVjA2
Wk44OXRIbXZ1M3Q3Yy8vdmpqRm90bC9QangvTWNVd3pDVEowK2VOMjllV2xxYThBc0lJSkNZ
bUhqMTZsVkN5TldyVndPZE5ubDVlZlgxOVY2dnQ2NnVqaS9mTVdyVXFHKy8vVGFTT2xVRnph
QUpYTGh3d1dLeENML1V2WDM3dHQxdXYzVHBVcmhGcWdwbGg1bUF6eGdhQVk3amNuSnl2dmpp
aTVBOG5jZnRkbGRXVmxMZU14b3VUeDgrZkhocGFXbGJXNXZYNitWYmR1ell3VnR3UVVIQjEx
OS83YmVQZEg4S0NncSsvUEpManVOcWEydkhqeC9QZHhBS2dRNGZQcHhtSncxRlRFeE1YMS9m
OU9uVGUzdDdUU2FUM3o3TnpjMTJ1NTFoR0x2ZHp2OVMyV1F5bFpTVVdLM1cxTlRVWGJ0MlJW
Wnk5S0VaTko0Yk4yNFVGaGFLaTJLdVdyV0sveTJKb1ZCMm1QRkl4OUFJdlBYV1c3Lys5YThK
eGFVSW53N0N4YjFqeDQ3UmJDaGNudjdOTjk4ODg4d3o0OGVQZitpaGgvN3doejhRUW5wNmVz
YU5HN2RyMXk2K0tLWGZQdEw5TVp2TlF1Yk9sMDBRLy9BUEYycWtKQ1ltWHJ0MmpRUk5vREl5
TXB4T0o4ZHhMTXRtWm1ZU1F1eDJPOHV5WHErM29hSEJhSmVHQ2QyZ0VVS09IVHVXbHBaV1Vs
TFMxOWZIdC9UMDlLU21wb2E3Z29jS1VYYVlFWDlqYUJENDJpODAzMEZLbjNXNVhEdDI3TWpK
eWFIWlVIaXZwL2YxOVRVMk5scXRWdjdQbFN0WFdxMVdvWmFwM3o2eHNiRWRIUjNDczRXRmhk
WFYxZUx5Q1BEMDRMend3Z3ZMbHkvbk9HNzU4dVY4WGlBbFBqN2U2WFI2dmQ3YTJscitRdWVj
T1hNRVR6ZmdoVTZhUVNzdkx5OHNMRHgwNkpDNFViaVFhRFNVSFdaK3g5Qm9oSlNuTDF5NHNM
T3prK080eXNyS2hJUUVtdldIeTlQNXo2S1ltSml4WThkKyt1bW5mT05QUC8yVW1KaklsM01M
MUdmcDBxVnhjWEhDT3MrY09UTno1a3krUmVybThIUXBIUjBkVTZaTXNWZ3MvL0l2LzlMWjJj
azMrZ3hVUlVVRlh6UnU3Tml4bFpXVmhKQno1ODVObVRMRmJEWTdISTZxcXFvbzZJNHFOSVBH
UEVoWFZ4Y2haTXFVS1FhOFZFV1VIbVoreDlCb2lFY3ArREZHQ05tNmRXdGFXcHJaYk03SnlY
RTZuVFRyajl5OWpIMTlmWjk4OHNuU3BVdHBPZ01BQUZCQTVINXp4REJNZm40Ky8xMDVBQUNB
Y0lEZmtRSUFnSDZBcHdNQWdINkFwd01BZ0g1UVhiMFhNRUJvQ25GSTN6aURGK0tnR1RScEh5
TVh5VkYybUJsNXhPamRVbHdUSmlMMVhoYnQ4dzJEdlRjcWg2WVFCNC80alRONElRN0tlaTgr
Zll4Y0pFZlpZV2JrRWVPUmRVdWZtakFScWZkQzUrblNlekNsMVYya3RWejR6c3VXTGJOYXJm
bjUrVFE3QUh5Z0wxM2k5NDB6WUNFT1FqZG8wajVHTHBLajdEQXo4b2p4QlBmMFFEVmh3bHp2
UmFtblM2dTdTR3U1OEozWHJGbmpjcmxlZi8xMW1oMEFQdENYTHBHK2NjWXN4RUhvQmszYXg4
aEZjcFFkWmtZZU1aN2dudTYzSmd5ZkJJZXoza3VJbnQ3VDA4TS9sbFoza2RaeTRWOW90Q1J4
Y0tFc1hVSWtoNWRoQzNFUXVrR1Q5akZ5a1J4bGg1bVJSNHdudUtjSHFna1Q1bm92ZEo2ZWxK
UlVWMWZuOFhnMmJ0d283aUN1N2lLdDVVTHdjLzhCUTFPSWcwYzgxQVl2eEVFemFOSStSaTZT
byt3d00vS0k4VkQ2bTlBdEl2VmU2RHk5ckt6TVpyTWxKQ1NzWDcrZUVkVkdGMWQza2RaeW9k
OW5FQWdGcFV1a0xVWXJ4RUV6YU5JK1JpNlNvK3d3TS9LSVNVZURCTFk3b1YzVjlWNEFBQUNF
Ry96bUNBQUE5QU04SFFBQTlBTThIUUFBOUVPa1BSMFgzd0VBSUh6Z08xSzlFVkloRG9aaCtO
dUVhVjZsWTVSVkx6SHlvSVY2bVBFdFZWVlY2ZW5wSnBNcFBUMTl6NTQ5RWRRYmZXamNVdHBI
ZXFyS0VyS24zeS8xRFhpNnFxQXZ4RUVJV2JSbzBmTGx5ME45bGY1UVhDVEhzSU5Hcys5U1o3
RFpiTFcxdFJ6SE9aMU9mb1pTbzBIamxuNzdDS2VxTE9IeWRJWmgxcTVkbTVDUVlMZmJoVW1s
ZlQ2Q2poOC9QbW5TSkw0Q0ROL2l0d0lNQ0FuNlFoeTNiOSsyMisyWExsMEs2Vlc2UkZuMUVp
TVBHczIrTXd4anM5bXNWdXZUVHovTlR4eWZsNWRYWDEvdjlYcnI2dW9tVFpvVVNjRXFRWm1u
aTA5VldjTG82UnMyYkhDNzNUVTFOZUszWE53NU56ZDMvZnIxSE1jSkxYNHJ3SUNRb0MvRXNX
clZxcGRmZmpuVVYra1NaZFZMakR4bzlQdCsvZnIxNHVMaXFWT25Fa0thbTV2dGRqdkRNSGE3
dmFXbEpWSmlWWVF5VHhlZnFyS0UwZE43ZW5xa0VzV1B6V2F6eStVU3Y4cHZCUmdRRXBTRk9I
cDZlbEpUVTRYemlyNThoeTVSVnIzRXlJTVcwcjU3UEI2THhVSUl5Y2pJY0RxZEhNZXhMSnVa
bVJrQm5XcERnYWY3bktxeWhOSFRaUjlQbkRoeC9mcjFRcGxHRXFBQ0RBZ0p5a0ljRlJVVjA2
Wk5DL1ZWZWtWWjlSSWpEeHI5dnQrN2QyL0ZpaFdGaFlXRWtQajRlS2ZUNmZWNmEydHJjVDJk
c28vUHFTcEw1RHo5d1R0bEdFTElkOTk5bDVlWHg1Y2k0M3Y2clFBRFFvS21FQWNoWk1xVUtl
SmlwMzVmWlJ5VVZTOHg4cURSajlqUW9VTm56cHg1OXV4WlFraEZSWVhENGVDTFBsVldWa1pC
ZC9TUUhqK0U0aGdqa2xOVkZ0ekxDQUFBK2dHL0l3VUFBUDBBVHdjQUFQMEFUd2NBQVAwUVhr
OFBkS2tkMStJQkFDQWNST2M3MGtCZis0TGdTQWU4cXFySzRYRHd0eCtjTzNmT2J4OHBWVlZW
MmRuWnNiR3hCUVVGL085MXhlK203aWVLNURodXlaSWx5Y25Kd2tEUjFDR1JIdkI2cmZmaTl6
RHpHWitCSDJiaDNvdElRbk5pYnR1MmJkeTRjUmFMWmRLa1NZMk5qWDdYbyt6STlDSDBleG5i
ZkFPZUhtSEVnNWFZbU5qUTBPRDFlbG1XZmU2NTUvejJrVkpVVk5UVzFzWngzSjQ5ZTBhT0hD
bCtpcjZzaEhZcExpN096ODl2YTJ2cjcrL25XMmpxa0VpSFZOLzFYc1Q3RzJoOFFqM005SDIr
Qno4eDU4NmRlL0xrU1kvSHMyM2J0a0MvMGxKMlpQb1FSay8zK2VCcWJtN096TXlNaTRzckxp
NE81T21vOTBLRHo2R3piOTgrL3RBUlQwRkxjL0s0M2U3S3lzb0pFeVlJTFNHVmxkQXVvMGFO
K3ZiYmI4VXROSFZJR0VuMUVuM1hleEVmUW9IR0o5VERURHFHZW9MbXhDU0VYTGh3d1dLeGRI
ZDNTOWVnN01qMElieDV1dmlwN096czh2Snl0OXY5MldlZkJmSjAxSHVoUVR4b0ZSVVZqenp5
eUxCaHc5NSsrMjF4MlEzWmswMjR6SExzMkRHaE1hU3lFdHJGWkRLVmxKUllyZGJVMUZUKzF4
ejBkVWpFMVV2MFhlL0ZKeUh6T3o3S0RqUHhHT29KbWhQenhvMGJoWVdGYjc3NXB0ODFET1RJ
RklpY3A1dk5acmZiVFFoeHVWeUJQQjMxWG1qd08rQ05qWTJqUjQ4TzNzY0hsOHUxWThlT25K
d2MvczlReTBwb0Y3dmR6cktzMSt0dGFHamd2endJcVE2SlVMMUUzL1ZleElkUW9QRlJjSmp4
Q0dPb0oyUlB6R1BIanFXbHBaV1VsUFQxOWZsZHd3Q1BUSjdJZVhwT1RnNmZwNWVWbFFudEtT
a3A0Zzl3MUh1aHdXZkErL3Y3Mjl2YmMzTnppNHVMQS9YeFllSENoWjJkblJ6SFZWWldDdjhZ
aGxwV1Fydk1tVE5IT0hONEw2YXZReUt1WHFMdmVpL2lReWpRK0NnNHpNaURZNmduZ3ArWTVl
WGxoWVdGaHc0ZENyS0dnUnlaQXVIeWRPWkJDQ0dIRHgvT3lNaUlpNHRidG15WjhKSk5telpa
clZiaFQ5UjdDWTUwVlBrSHljbkppeGN2NXFzV1Mvc1F5ZEcyZGV2V3RMUTBzOW1jazVQamRE
cjV4bERMU21pWGMrZk9UWmt5eFd3Mk94eU9xcW9xRXFBT2ljK2c4ZU1wcmw2aTEzb3Ywa05J
T2o3S0RqUHBHT29EQlNkbVYxY1hrWXdZNVpFWkhOUjdBUUFBL1lEZmtRSUFnSDZBcHdNQWdI
NkFwd01BZ0g2SVRyMlhhSzBIQUFEMGpTYS9JNFhGQjRHbUNJbTBqOEcvN2xZMmFIcXQ5MElE
emI0cnEzbWlENElVWWdweWxnWHFVRnBhU245dWh1enBoY3hXbjRDbnF3cWFJaVNCK2hoMllK
VU5tcjdydlFTSFp0K1YxVHpSQjlKOXB6KzVmSHFlT0hHQ3IrcEYrZkl3ZXJyUEI4NmhRNGV5
c3JMTVpuTldWaFovNDczRDRUaC8vandoNUljZmZuQTRITUpMekdaelhsNWVRME9EMy9YZ0hz
cmcwQlFoQ2RUSHNFT3FiTkQwWGU4bE9KUWpwcURtaVQ2UTdqdERYZXRHZkJweUhKZVRrL1BG
RjErb3d0Tjl4R1ZtWm03WnNvWC9IV2xXVmhZaFpPSENoWnMyYldJWVpzdVdMYSsrK3FyUXM3
ZTN0Nm1wS1NVbHhlOTZwSDhDTVRSRlNBTDFNZXpBS2hzMGZkZDdDUTdOdml1cmVhSVBBdTA3
VGEwYjhXbjQxbHR2OFQ5UlZxT25tMHdtb2Q2TDJXd21oR3pidHUyWlo1NlpQSG55bkRsenZ2
amlDMExJaGcwYitCOU5NUS9XZTRHbjAwTlRoQ1JRSDhNT3JMSkIwM2U5bCtDRXRPOGgxVHpS
R1Q2Rm1BaEZyUnZ4YWNpYllVaFhKcUtacDErOGVISFlzR0VmZmZTUjFXcmw2N3ZHeGNYVjFO
UzQzVzZXWlgydXQ0aFhHeHNicTc5Q25ZTUZUUkdTUUgwTTYrbktCazNmOVY2Q1E3bnZDbXFl
NkFhL2haaG9hdDM0UFEyam42ZExiNHhwYW1yS3pNdzBtVXlabVpuQ201cVJrZkhqano4S0pi
dy8rT0FEbTgxbXM5bFdyVnJGaU1vbStIeE1MVjI2bEs4SlE3bVRoc0p2RVJLZnNaTDI4VHZP
eGtIWm9PbTEzZ3NOTkNQR0gwdXlOVTkwU2FCOTk2bDE0M2ZFL0o2R1lmUjB2MUJ1REFBQVFG
akI3MGdCQUVBL3dOTUJBRUEvd05NQkFFQS9hS1BlQ3dBQUFCcndIYW5lUU9rU0JXRFFRZ1Vq
RmlvUks4UVVzcWR2WmJiNkJEeGRWYUIwaVFJd2FLR0NFUXVWaUJWaUNxT24rNzNGY3RteVpW
YXJOVDgvbnhCeStQRGhDUk1tK014UUNnWUlTcGNvQUlNV0toaXhVSWxZSWFidzV1bFNUMSt6
Wm8zTDVYcjk5ZGNKSWRuWjJlWGw1VzYzKzdQUFBvT25EeFlvWGFJQURGcW9ZTVJDSldLRm1D
THQ2ZUpLYkdheldhZ0FBMDhmTEZDNlJBRVl0RkRCaUlWS3hBb3hSZHJUeFg5bVpXWHhlWHBa
V1JrOGZiQkE2UklGWU5CQ0JTTVdLaEVyeEJRdVQvZDdZNHhQejZhbXBrY2ZmVFF1THE2a3BB
U2VQbGlnZElrQ01HaWhnaEVMbFlnVllsTEx2WXp3ZEFBQUdEaHErUjBwUEIwQUFBYU9Xandk
QUFEQXdJR25Bd0NBZm9peXAyL2F0R240OE9HeUYxNXdaUVlBQUdpSThuZWtLU2twSjA2YzhO
bUU0clVCUWxjZ29xcXFLanM3T3pZMnRxQ2c0TUNCQTN5THcrSGd2M0EvZCs1Y3BNU3FCZm82
SktXbHBlTDd1QWJ4TmdGdFFiUGpmdTk4RTBoTVRJeUlVclhBY2R5U0pVdVNrNU9EakZ0VlZW
VjZlcnJKWkVwUFQ5K3padzlSZEdLRzdPbHQ5MzFqSUFlMGVDSnBZUk9LMXdZRWdnOWpVVkZS
VzFzYngzRjc5dXdaT1hJa0lTUXhNYkdob2NIcjliSXMrOXh6ejBWS3BscWdyRU55NHNRSi9w
emsvOFN4S3V2cGdaNWF0R2pSOHVYTHc2Qkl2UlFYRitmbjU3ZTF0ZlgzOXdmcVk3UFphbXRy
T1k1ek9wMDJtNDBvT2pIRDVlbnIxcTF6T0J3bWswbjRVRHAwNkZCV1ZwYlpiTTdLeXVMbkl3
MytNUzdlcU04bUdOU05rWU5tSE54dWQyVmxKVDhaYkdKaTRyNTkrL2hESnlFaElmd0MxUVZO
TFE2TzQzSnljcjc0NGd2eDRXcXoyYXhXNjlOUFAyM01TYzlsUGQzditOeStmZHR1dC9QVHlo
dUhVYU5HZmZ2dHQ4SDc1T1hsMWRmWGU3M2V1cnE2U1pNbUVVVW5acmc4ZmZqdzRhV2xwVzF0
YlY2dmwyL0p6TXpjc21VTC82dlJyS3dzWVlYU1RmamRycytmcUJzVEhObHhFUDcvUFhic0dD
R2tvcUxpa1VjZUdUWnMyTnR2djIyMFFoeUVyaGJIVzIrOXhmKzB6MmRzcjErL1hseGNQSFhx
MUVnSVZSazBwNXQwZkZhdFd2WHl5eStIVTVjYU1abE1KU1VsVnFzMU5UVjExNjVkZnZzME56
ZmI3WGFHWWV4MmUwdExDMUYwWW9iTDA3LzU1cHRubm5sbS9QanhEejMwMEIvKzhBZCtsNFRx
TG1heldWaWhkQk4rdCt2ekorckdCSWRtSEZ3dTE0NGRPM0p5Y3NTTmpZMk5vMGVQRHBzdWxV
SlRpeU1tSmliUUJYU1B4Mk94V0NLZ1UyMVFubTdpOGVucDZVbE5UZVVOeTFEWTdYYVdaYjFl
YjBORFE2RHZFakl5TXB4T0o4ZHhMTXRtWm1hS242SS9NY043UGIydnI2K3hzZEZxdFJMcVBE
MDJObGI2YjZ6VTA4Vi9vbTZNbE9EanNIRGh3czdPVG83aktpc3JoWC9vK3Z2NzI5dmJjM056
aTR1TEk2SlJSWVJVaDhSbmJPL2R1N2RpeFlyQ3dzSXc2bE1yTktlYnovaFVWRlJNbXpZdHZM
SlV5Wnc1Y3dSUEQ1UTN4TWZITzUxT3I5ZGJXMXZMWDA4bm9aK1k0ZkowUHBlSmlZa1pPM2Jz
cDU5K1NnaHBhbXJLek13MG1VeVptWm44OVhUaTc1aFl1blJwWEZ5YzN5dnNnYjZiUXQwWU1U
UWp0blhyMXJTME5MUFpuSk9UNDNRNmhWY2xKeWN2WHJ5WTQ3Z282STRxTkxVNEJId096cUZE
aDg2Y09mUHMyYk1SMHFvT2FBNHp2K016WmNxVVFGY2U5TTI1YytlbVRKbGlOcHNkRGtkVlZS
WGY2RE5pRlJVVkRvZUR0ODNLeWtxaTZNUlVTNzJYd1VKVllnQUFJTUxvN1hlazhIUUFnSkhS
bTZjREFJQ1JnYWNEQUlCK1VMV25xL0I2UFFBQXFKbUlma2VxekozaDZTRkJVN3BFL043eHQ4
clNGS1BRTWNycXZVaXJjeGdIbW5OLzI3WnQ0OGFOczFnc2t5Wk5hbXhzSkE4ZWVKRlNHaDJr
K3k1dGtSSm9jTVJIblN3aGUvcDlTY0RUVlFWbDZSSWVvZXdHVFRFS0hhT3Mzb3UwT29mUkNI
NXV6cDA3OStUSmt4NlBaOXUyYmZ3ZDJjWTVsNlg3TG0wSmhNOG8rUngxc29UTDA2WDFYcVFm
MGUzdDdZOC8vcmpGWWhrL2ZqeGZIWkIvMW13MjUrWGxOVFEwK04xREVCeWEwaVU4NHJJYk5N
VW9kSXl5ZWkvUzZoeEdnL0xjdkhEaGdzVmk2ZTd1Wm94WElVZlk5eUF0UG9oSFZYclV5Ukl1
VDVmV2V5R1NJNkNnb09ETEw3L2tPSzYydG5iOCtQRkNlMjl2YjFOVFUwcEtpdDlYZ2VEUWxD
N2hFWmZkb0NsR29XT1UxWHVSVnVjd0dqVG41bzBiTndvTEM5OTg4MDJoeFRnVmNxVDdMbTJS
SWg3VlFGV0dnaEF1VDVmV2U1SEtNcHZOUXViT0Y5M2RzR0VEL3pNcW9TV2tuUUdFcm5RSmta
VGRvQ2xHb1dPVTFYc0pVcDNESU1pZW04ZU9IVXRMU3lzcEtlbnI2eE8zRzZGQ2puVGZBNDJH
RCtKUkRWSmxLQkRodlo0dXJ2ZENKTFZjQ2dzTHE2dXJQUjZQMEJJWEYxZFRVK04ydTFtV0ZW
YWJrcExDMXc0RU5GQ1dMdkVwdTBGVGpFTEhLS3YzNHJjNmg2RUk3akxsNWVXRmhZVkNJUkFC
STFUSWtlNTdvTkdRNG5kVW81K244NThxNG5vdlJGTEw1Y3laTXpObnp1UmIrTVlQUHZqQVpy
UFpiTFpWcTFZSjNUWnQybVMxV3BHdFUwSlp1c1NuN0liZlloVEdRVm05RjJsMUR1UEFQSWpR
R0tSUFYxY1gvOEFJRlhJQzdidTRoY2lObU05VGxKdldXNzBYQUFBd01xcit6UkVBQUlDUWdL
Y0RBSUIrZ0tjREFJQitnS2NEb0dyd2ZSVUlDWGc2QUg1UTdLU0Ric0ZCVmpnbzIySVlaczJh
TllTUWp6NzZhQ0FyWkJobTllclZBeGNtcll0Q1UxZEhlcjhHVFFtanFxcXE3T3pzMk5qWWdv
SUM4VS9aZzkvNklhME9SRlBMUmRwSHVoN3BwaFhjaHdKUEI4QVBodkwwek16TS92NytDUk1t
RE5EVE16SXk3dDI3TjBCaDByb285SFYxeE51bEtXRlVWRlRVMXRiR2NkeWVQWHRHamh4SnFW
eGFIWWltbG92ZkNqQitxd3hKTmNEVEFSZ29mczhyNXNGaVJEUkZqWUt2V1hoVmNYRnhYRnpj
aEFrVG1wdWJDU0hOemMyWm1abHhjWEhGeGNYaU5ZdTNMdDJXdElDUzN4MlI2cGsrZmZxS0ZT
dG16SmpCZHo1MDZGQldWcGJaYk03S3l1Si9JOE13ek5xMWF4TVNFdXgyKytiTm13T3RwN1Mw
OU1NUFB4UTJLbDFQZm40K0w3Nit2bDYyUW81UUY0VytybzU0Wi8yV01QSTdHbTYzdTdLeWNz
S0VDWHdIYVVVYW4xY0ZxUTRrVzh0RjNDZlFldURwQUF3K2djNGljVEVpbXFKR3dkY3MrSFZa
V1puYjdTNHZMNTg0Y1NJaEpEczd1N3k4M08xMmYvYlpaK0wrd1VzaEJTcWdKS3RuKy9idE1U
RXhPM2JzNEZlWW1abTVaY3NXdDl0ZFZsYVdsWlhGOTltd1lZUGI3YTZwcVFtVWh6SU0wOVhW
Tlc3Y3VOdTNid2RhejdwMTYrYlBuMDhJbVRkdjN2cjE2NE9vRXRkRm9hK3JJeDRReWhKRy9J
ZGlZbUtpK01mcXdTdlNCS29PUkZQTFJkd24wSHJnNlFBTVB0S3pTRnFNaUthb1VaQTE5L1Qw
Q0o3dWRyc0pJVzYzbTYrQ1lqYWIrUmFYeThYM29TbUZKQzJnRk9xZThvOU5KcE93ZGJQWnpM
ZjM5UFFFMzBHK2ZlWEtsZSsrKzI2ZzlkeThlZE5tczUwL2Y5NW1zOTI2ZFN1UUpKKzZLUFIx
ZGNUYTZFc1l1Vnl1SFR0MjVPVGtpQnVEVktUeFd4MklwcGFMVDU5QVZZYmc2UUFNUHRLenlH
OHhJaUpYMUVoS1VsSlNYVjJkeCtQWnVIR2o0T2w4UGx0ZVhwNmRuVTBJeWNuSjRmUDBzckl5
dm8vZnJjc1dVQXAxVDRQazZVRkdSdHp1Y3JuR2poMGJhRDJFa0tLaW9zY2VlMnpldkhtQjlF
anJvdERYMVJGcm95bGh0SERod3M3T1RvN2pLaXNyRXhJU2hQYmdGV21rMVlGb2FybEkrd1Nx
TWdSUEIyRHdZUjZFK0N0R3hEOFZ2S2lSbExLeU1wdk5scENRc0g3OWVwL3I2UmtaR1ljUEh5
YUVIRDU4T0NNakl5NHVidG15WllHMkx0Mld0SUFTVVhRdHFLbXBLVE16MDJReVpXWm1DdGZU
L2ZiM3U1N1ZxMWNIV2c4aHBMNitubUdZK3ZyNklIckVkSFYxMGRUVmtiNWZma3NZK1lqZnVu
VnJXbHFhMld6T3ljbHhPcDNDZW53cTB2aThTbG9kU0txWlpyOWsxK08zUlJaNE9nQlJKcVFz
RElEZ3dOTUJpREx3ZERDSXdOTUJBRUEvd05NQkFFQS93Tk1CQUVBL3dOTUJBRUEvd05PQk5x
aXVycTZwcWVudDdhMnBxYW11cnFaOFNmQm5BM1Z3dVZ3c3kvcnRIK1JWQUtnQmVEclFCdFhW
MVFjUEh2ejczLy8rdDcvOWJiQmNOZEI2amg4L0xuMEtWZzQwQVR3ZGFJUHE2dW96Wjg0NG5j
NHpaODRJOXVyem9McTZ1clcxMWVsMHRyZTNCMnIwV2FkMFEvZnUzYXV2ci9mcjZVNm5jOSsr
ZlZldVhCblVQUU5nTUlHbkEyMVFYVjE5OCtaTllTazBpaDlVVjFmZnVuWEw1WEx4dnduMDIr
aXpUdW1HdnZ2dXUzUG56dmw5cXIrLy84cVZLM1YxZFlPM1d3QU1NdkIwb0EycXE2djcrL3Yz
NzkvZjM5OHZHSzdUNlhTNVhJTExTeTFlMnVpelRyOGJDblRkdkwrLy85cTFhL0Iwb0diZzZV
QWJpQjFXZU56ZTN1NTBPbHRiV3hWNHVvOXhTNStWUHFpdXJ0NjNiOS9seTVjSGM4Y0FHRlRn
NlFBQW9CL2c2UUFBb0IvZzZRQUFvQi9nNlFBQW9CL2c2UUFBb0IvZzZRQUFvQjkrOXZUbTV1
YnRBQUFBdEE4RFF3Y0FBTjN3L3dIU0wwMUtqNEZMZ2dBQUFBQkpSVTVFcmtKZ2dnPT0iIC8+
PC9wPjxwPiZuYnNwOzwvcD48cD5UaGVyZSBpcyBhIHNsaWdodCBpbmNyZWFzZSBpbiBzbGVh
cGluZyBqb2JzIGF0IHRoZSB0aW1lIHNsb3QgaW4gcXVlc3Rpb24sIEkgZ3Vlc3Mgbm90aGlu
ZyB3ZSBjYTwvcD48cD5kaXJlY3RseSBtYXAgdG8gdGhlIGlzc3VlOjwvcD48cD4mbmJzcDs8
L3A+PHA+PGltZyBhbHQ9IiIgc3JjPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtH
Z29BQUFBTlNVaEVVZ0FBQWZFQUFBRnNDQUlBQUFCVHFCZTNBQUFnQUVsRVFWUjRuTzJkZjNR
VDVaNy9oeWFwYllDbVB5akxMME4vMkphMmdCZktiYXRYT1h5dGlGZGR2TjYweTdyK1dBOWUz
TE9JbGxiRXk5SERjZ0JscjdKb0xWWTlYS0VXQ21xVGxsYnh4NjJGOUtwN0xBSmlMMm1iMG9M
eXM4MlBOdTN6ejU1ei8rRDd4N1BPanZOTWttbWFaRExKKzNVK1owNzY1Sm1aOXp5WnZQdkpr
OGxudU84QkFBQkVCVmFybFZOYUF3QUFnQ0JndFZyMzc5Ly92NTVPQUFBQXFKbjkrL2ZEMHdF
QUlFcUFwd01BUVBRQVR3Y0FnT2dCbmc0QUFHcWlpVUg0TER3ZGdDRERjWnpTRWlKQ0F3Z3A0
K1BqMU0zaDZRQ0Vsa2p3MDBqUUFFS0h4K1A1N3J2dnpHYnoxYXRYbTV1YmhVL0IwMEdZNEg0
bUtTbnBvWWNldW5qeG90S0tRa1VrK0dra2FBQWhvcWVucDYydHJiT3pzNysvdjdtNStidnZ2
aE0rQzA4SFlZSjNtUXNYTHZ6elAvL3pQLzdqUHlxckozUkVncDlHZ2dZUUlvNGZQMzcxNmxW
dno4TFRRWmdRdXN5bFM1ZjBlajNmdm12WHJybHo1MDZaTW9VUTRuUTYvL1ZmLzNYNjlPblRw
MDkvNG9rbm5FNG43VFl5TXJKaHc0YTB0RFNEd2ZEeXl5L1RSby9IVTExZFBXUEdqTVRFUkpQ
SmRQMzZkZHB1c1ZqeTgvTjFPcDNSYU55N2Q2K1B4Z2x0UWY2Ujd0aXhJejA5WGEvWFAvcm9v
eTZYaXhCeSsrMjNIemh3Z08vVDA5TXphOVlzNFRzek16UHo1TW1UOVBFNzc3eERINXc4ZVRJ
ek05T0hUbS90L0dqLzlhOS9uVE5uenAvKzlLY0pIUUpRTC9CMEVDYUVubjc1OG1XaHA1dE1K
bjRxNXRsbm4xMjFhdFdGQ3hjR0J3ZnZ2dnZ1eXNwSzJyNXAwNmF5c3JLK3ZyNHJWNjQ4L2ZU
VHRQR2xsMTY2NjY2Nyt2cjZybCsvL3NnamovemhEMytnN1dscGFZY09IWEs1WEQwOVBZOC8v
cmlQeGdsdFFmNlIwa080Y09IQ3FsV3JObTdjU0FocGFXbkp5OHNiR3h1amZSNS8vUEh0Mjdj
TDExcTNidDNycjc5T0NPbnI2NXMyYlJwMTV6MTc5anoxMUZNK2RIcHJwNlBkMU5RMFk4YU1E
ejc0WUVMNlFZU0Q2MTVBUk1CNytzV0xGeDk1NUpINzc3K2ZiKy92NytlN3paNDkrK3pacy9U
eDk5OS9QMmZPSFBwNDd0eTU3Q2xxTkJyUG5EbERIdzhPRHM2Y09aTStuamR2M3U3ZHUvdjYr
b1NkSlJzbnRBWDVSL3JERHovUXgyZlBucDA3ZHk1OVhGUlU5TjU3Ny9HTnc4UER3clUrL1BC
RGs4bEVDTm0rZmZ1TUdUUG9oNFBmLy83M0gzMzBrUStkM3RvNWp2dXYvL3F2MmJOblc2M1dB
QTRCUkQ2NDdnVW9EUDhkNmZUcDB4OTg4TUhCd1VHK1hkaE5vOUY0UEI3NmVIUjBWS3ZWOHUy
am82T2liV3ExV2s0QW5iMGhoRml0MXQvKzlyZXBxYWtaR1JuVUU3MDFUbWdMa29jaitaVGtJ
WHp3d1FjNU9Ua2VqNmVpb3VLMTExNFRyVFUwTkhUenpUY1RRZ29MQzgxbWMwbEpDU0hrNXB0
dnB0YnZUYWUzZG83ak1qSXlubnZ1T1ZZZWlBSnczUXRRSG0vZjJvbmFaOCtlelNlNTMzLy8v
ZXpacytsanlUeDkzcng1ZHJ2ZDJ4N0h4OGZOWnZNLy9NTS8rR2dNWUF0K0VlYnBQL3p3QS85
UlkzeDh2TEN3c0xLeTBtZzB1dDF1ZHNVNzc3enovZmZmTHlvcUlvUVVGUlY5OE1FSHk1Y3Y5
NjNUV3p2SGNYMTlmVmxaV1R0MzdweVFlQkQ1NExvWEVCSEk5UFFOR3pid2s5RXJWNjU4NXBs
bmFQdnp6ei9QenFmL3gzLzh4NnBWcTdxN3UwZEhSNy85OWxzNmQwRUlLUzh2Lys2Nzc5eHV0
OWxzVGt0TDg5RTRvUzNJUDlMZi92YTNGeTlldkhqeDRyMzMzc3QvSlVBSXFhK3Y1emp1cmJm
ZWtseHgrL2J0YytiTW9TbjhxNisrT25mdTNCMDdkdmpXNmEyZGptcC9mMzlPVHM2MmJkc21w
QjlFT0xqdUJVUUVNajNkNFhBODl0aGowNlpObXpadDJtT1BQZVp3T0dqN3lNakkrdlhyVTFK
U2twT1RkKzNhUlJ2SHhzYTJiZHRtTkJwMU9sMUJRVUY5ZlQxdFAzRGdRRTVPamxhcnpjL1Bi
MmxwOGRFNG9TM0lQMUwrdXBkSEhubUV2M1NIRUhMdzRNSHM3R3gyRW9ueXpUZmZhTFZhK25Y
eGhRc1h0RnJ0Zi8vM2Yvdlc2YTJkSDlXQmdZRzh2THlYWG5wcFFvY0ExQXM4SFlEd2NkOTk5
KzNmdjE5cEZVRGQ0TG9YQUpSbmJHeXN0cloyd1lJRi9PV01BQVNHeU1UaDZRQW9BTWR4UnFN
UlZ4YUN5ZFBjM0R3eU1rSWZqNHlNNExvWEFBQlFNVmFyOWVUSms2T2pvNk9qb3lkUG51enM3
QlErQzA4SEFBQTE0WFE2VDV3NFliRllMQmFMMVdvVmZnbFA0T2tBQUtCcU1KOE9BQURSQXp3
ZEFBQlVUQXhkeTloOTdGajNzV05LcXdBQWdQQVJ0WjQrNm5MdHVlMjJQYmZkTnVweUthMEZB
QURDUk5SNitsLys5S2R0UnVNMm8vRXZLUDhQQUloVm9zVFRyL2IxN2N6Sm9aNitNeWZuYWtC
bHJ3RUFJUEp4T0J4V3E1Vy9scEd2aVVTSlhFOXZiR3pNek16VWFEUVpHUm1OalkyRUVMdmRY
bHBhR2g4ZlgxcGFLcW92MnZEWVk5VFFhVFE4OXBoQ3FnRUFJTFMwdDdlZk9YTm1aR1JrWkdU
azlPblQ3ZTN0d21jajE5T1RrcElzRm92TDVUS2J6UWFEZ1JCU1hsNWVYVjN0ZERxcnE2c3JL
aXJZVlRadjNrd0lFZDQweHdjanAwNzU3U056VTNLNlFaWDhibEFsdnh0VXllOFdtYW9Dd0d3
MjgxV0R4c2JHekdhejhObkk5ZlNGQ3hkYUxCWmF3SHJ4NHNXRWtMUzBOSHB6bk1IQlFjbVMx
dFRUdi9ycUt6bmJ2eWJqeHNFeU55V25HMVRKN3daVjhydEJsZnh1a2FrcUFOU2FwNTg0Y1NJ
cEtZbmp1S1NrcEJNblRoQkM0dUxpNkg4bmo4ZWowV2lFblQwLy9YU3RwbWJUdW5Ya3hJbi8r
Wi8vSVNkTzNMaHh3L2ZTMDlibXQ4OW9lN3ZmUGpMM0NGVlFCVlZRSlZ6KzNlVzZWbFBqN3Vx
YXFEY09EdytyY2o0OU96dWJuM3U1NVpaYkNDR3BxYWwrOC9RYk4yNE1EQXpja0FIcDdQVGJS
K2FtNUhTREt2bmRvRXArTjZpUzN5MENWWVhDT1NQWDA1T1RrL201bDVTVUZFS0l5V1RpNTlQ
NWUzUUpvWjRPQUFDcUlEQnZWT3QxTHcwTkRVYWpVYVBSeko4Ly85Q2hRNFNRM3Q3ZTR1Smlu
VTVYVWxMU0ozVzFJdkwwaVhhREt2bmRvRXArTjZpUzJTMHdiMVRyZkhvQUlFOW5zVnF0VnF0
VmFSVUFBQWtDTXpxMVh2Y1NBTWpUMlc2K1BSMWpKYjhiVk1udkJsVXl1d1ZtZE1qVFl4ZnJ6
eWd0QklBSUpldEdGZzFGOWg2WTBhbjF1cGNBUUo0dTZtYTFXck51WkNGUEQwcTNNS3V5V3Ey
dHJhMSs3Y2JIcG9UL3pxTjdyR1IyWS90WUJTaWlLaFEyR0lXZURuaXNWaXVYZFFONXVocVJ0
SnZBdGhCY1laSjdDZWt1UWdkTmVuem5QU0VsTUtPTG9mcnB5Tk5GM2Z4Nk9zWktmamRoSHg5
MktVZFZhMnVyWHhPeFdxMEx5d2FvM1FUMkNnby9wUVgzMDRPb2haVVgrYS9nRFY1NUl5ZDZq
MFIrbmk0eWNSRlI2T21BaC9mMGdOTVFwZVlaSXhrNm5uN2QxdThXL0hiZ3NtNndqak9odlFU
M1U1cmtJY3RwRWM0Z0tUaDVMWUsraUZ6V2pVbStSeVpEWUVZWEU1NCtNakppczluV3JsMTc0
OGFOYjc3NTVzYU5HNE9EZzc2WHBMUFRiNStCZ1FHL2ZXVHVVUkZWVnF1MXNHeVF5N3BCYzZ1
SnFxTHBaT3lNbGJkUm91Tnc1TWdSMnNkcXRaWU5sbVhkeUJyY1g4aTMwTGx2bWFwYVcxdTk3
WXZmWTlhTnJQdis1UnN1NjBaaDJTQjlGZWl6d2ozeXF2aDJxb0h2U2RkdGJXMDkrYzQ3L0tz
Wm1DclJIb1VhaEV2YWsvWXBHeXp6M1hPU1kxVTJXQmJ3ZVVXMWxRMlcwUkVXdmtmQ2RyYmI3
WGFielJaQW5hK1k4SFFLOG5RaGZLNDNtVVJQdlZPbDN2QjJVRllCYkR0L2RRUWZkR0Q1UDMx
dlZxWUdZUWQrRjZLWGp4VmovU1hDWGRCTVg5Z3pnSkVSRFFLZjFmS05vaGFyNEVPTTVOQk5h
UDU2UWdNN29XM3k3NDdKdkVjbVNTaHNNQW85blovRHNucmhmMGN6a3VhSWVXRkJ2MnBDK05H
U2ZSdklVV1cxV2srKzg0N2ZNMTR0MXlkSW5oSTBjNVMwU0w2ZHptNExYWUFQZm9hRUh5dmYw
TjM1aHN1NnNiQnNnSDM1ckQ4N0VSVkQrL3p2aEVZako1TE45eVM3NXJIYm1aQXFmbXNMeXdi
WWR1Ri9EanBXdkNwK2ZJUkx1bTZ3eGtwbU43YVBwS2RIL255NmI2TFEwNFh2WHNrRXdScGh1
YWZ3SkF2aU5rVUdGTUQzKy9Ta1YvYkNnQnUvVEJJbkwwUHlyT0RkaDEreUtUbnZSOTQ4WGVS
cnZvUGRpN2VkaWo0UWVQdS93dmFVVkJ1d0t0SFdoTU1sYkJFK3VOSEllUnN4djBwRXV3NXNE
UDBlcWNqVDVaOWR3WHEzQnVCeW4zenlTVmRYMStEZ29NZmprZXdRYlo0dSttOHMrWExTcHlh
YUkyUjUvMkpuTW5tNnlMQmtxdkloaHQ5czJVQ1pYMCtYdkJKQUNGM3hENTFML1o3QkF3TURm
bFh4ZS9UOWxtQlZpVjQ3dXFQQXJqQ3hDdjVSOFZFMlVDYXlKOVpEK2F6WnQ1LytvWE9wWCt1
aEw0MWYweEh1a2RYalRaVmt0OVZMTy8wNnFmQ0VrZFFqM0tPa0xmcFFKWE9zdktsaTIrbC9D
OUVyNkhkVFdWTC9oSVMySHZCNUpUckg2RmthaWp6OTJyVnIzZDNkSFIwZHpjM05IUjBkM2Qz
ZDE2NWRFM2FJTmsrWFBCSFpGR09pRWF4L3krd0x6eHNXVFdxQ0pjYjZ5OCtWM0M4LzgvcldJ
L1JRK1ZrTTMwR21QQjQ1UFlPWVR3bTM1czJTZ2hJK1VsUkVaQTcxWk00cjlsazVXNXVNM1ky
T2pnNE9EbloxZFgzeXlTZkM5aWowZE9GL2JHOHZudndjUWVpa1dWNisrWkdmSTRpc21kVXBV
NVhWK3dRQ3YzRnZ1Wkp3WGZZQUpmOHAwaXpQOTA3NUtXbkpJUktKWi9FOTdLTFhqalpLanBW
b2EreUhOdmEvSFNjdnI1VFRoeE5reEQ2TVJ1YW1RcUZxOHB1S1lsVSt6aXZKczkzYmVjNi9F
WHc3d3lROTNSdlI1dWx5WG40ZmtlVWx0ZWV5ZnBGV1M3cFNBSWdNWFg3STJYZ0E2d3FQM2Nj
SXlEbXVTWFlRZFE1WWlmWG5tUlpSQ3dMQnhpVFBLOUd6dmxjL2N2Skl6SGs2SnlBMU5aVVFZ
cmZiUzB0TDQrUGpTMHRMN1hZN3V3cjE5TW5rQ0NJakUyMHE2K2RKRXI4NXVHUitLcGtGaS9Z
b1AzUHh1MGNmNCtCTmxkK3g4bjJBZkFjZlBZVnptbnhQMFpES1VTVXpuNUtjamZVMnBIS0dQ
YkR6S3JCTlFWWDRWVTNtdkdMUE1lVHAwblIwZER6Ly9QT0VrUEx5Y3Y0K1J4VVZGV3pQeWVm
cGZrTmt3WkxmN0xONXJtVG1HOXo1Vm0vSnRad0Q4WDE5Z3N3dHlGK0w3K3pqdjRqZjhMYXV0
NkhHN0RaQ1p2QkpCajF0Sk04Y21lOWwwZXFpa3pOWW5xNitlaStyVnEwNmYvNDhJU1F0TFcz
UTMvMUlPVFhuQ0ZBRlZWQVZPNnBpMU5QYjI5c2ZmdmhoK2pndUxvN2UzY1BqOFdnMEdtRTN6
MDgvWGF1cDJiUnUzZStXbnVDeWJtQ0pKWlpZUnZqeTd5N1h0Wm9hZDFmWFJGMVIzWFVaVjZ4
WThmWFhYOVBIcWFtcHlOT2hDcXFnS2pwVXhXS2Uvdm5ubjk5eHh4MzhueWFUaVo5UE41bE1i
UDh3ektjakVBaEVVQ0lXUGYzT08rODhjdVFJLzJkdmIyOXhjYkZPcHlzcEtlbnI2MlA3STAr
SEtxaUNLcldvVXVhNmw5cmEyc2NmZjV3UVVsNWVQbjM2OUVPSERvVkNSTEJBbm81QUlOUVNB
WHU2dytHd0Judy9VcVBSMk5QVDA5TFNjdHR0dDMzNTVaZTV1Ym1CaVFnUHlOT2hDcXFnU2ky
cUF2YjA5dmIyTTJmT2pJeU1qSXlNbkQ1OXVyMjlYZmlzSDAvWGFEUWpJeVByMXExNzlkVlhS
MGRIdFZwdFlDTENBL0owQkFLaGxnalkwODFtTTcwQ2tCQXlOalptTnB1Rnovcng5T3pzN0Mr
KytHTEpraVhkM2QwMm0rM21tMjhPVEVSNFFKNE9WVkFGVldwUnBVeWVmdURBZ2VuVHB6Lzc3
TE9Fa0NlZWVLSzJ0all3RWVFQmVUb0NnVkJMQk96cHc4UERnYytucXd2azZWQUZWVkNsRmxX
eFcrOUZQc2pURVFpRVdpSmdUNS9VNzBqYjI5dHpjbkttVEpsQ0NGbXpaazE5ZlgxZ0lrTE55
TWlJeldaYnUzWXRsM1dEdjl1NjcrWHFwWjErK3l3c0cvRGJSK1llb1FxcW9BcXFoRXU3M1c2
ejJmcjcreWRxZDlURWVTdWZtS2ZmY3NzdExTMHRITWNSUW5wN2UrZlBueCtJNDRZTDVPa0lC
RUl0RVhDZWJyRllybCsvYmphYnIxMjdkdTNhdFphV0Z1R3pmanhkcDlPNVhDN3E2WmN1WGRM
cjlZR0pDQStZVDRjcXFJSXF0YWdLMk5OUG5qelozTnpjMDlQenlTZWZXQ3lXYytmT0NaLzE0
K2tyVnF4NDU1MTNPSTdyNys5ZnMyYk42dFdyQXhNUkhwQ25JeEFJdFlReTM1SDI5L2MvOE1B
RGVyMWVyOWV2WHIzNnh4OS9ESVdJWUlFOEhhcWdDcXJVb2txWjcwalZCZkowQkFLaGxzQzFq
UDVCbmc1VlVBVlZhbEdGdW96K1FaNk9RQ0RVRXNwNHVvSjFHY2ZHeHJaczJUSjc5dXdwVTZi
UUMyL3NkbnRwYVdsOGZIeHBhYW5kYm1kWFFaNE9WVkFGVldwUnBZeW5LMWlYY2V2V3JibTV1
VjFkWGVQajQ3U2x2THljdjg5UlJVVUZ1d3J5ZEFRQ29aWlFwbjY2Z25VWmpVYWpxSVprV2xv
YTdrY0tWVkFGVmRHaEt1YnFNbW8wbXFlZmZqb3hNZEZvTkg3d3dRZUVrTGk0T0ZvMTJPUHhh
RFFhWVdmUFR6OWRxNm5adEc2ZDR2Y0N4eEpMTExHVXMveTd5M1d0cHNiZDFUVlJiNXhVL1hR
RlNVdExNNXZOTHBmTGJEYlBtREdERUpLYW1vbzhIYXFnQ3FxaVE1VXllYnFDVkZSVW1NMW10
OXR0TnB2VDA5TUpJU2FUaVo5UE41bE03Q3FZVDBjZ0VHb0paZXFuSzNndFkzOS8veDEzM0tI
VDZUSXpNK21IaTk3ZTN1TGlZcDFPVjFKUzB0Zlh4NjZDUEIycW9BcXExS0lxNXE1bERBRGs2
UWdFUWkyaFRHMEFOZDVqT3RMK0cwOW9VMUFGVlZBVkk2b200K2trNFBycGFyekhOQUtCUUVS
K0tPUHBhcnpIZEtUOU41N1FwcUFLcXFBcVJsUXA0K25xQW5rNkFvRlFTd1RyTzlMbzkvUkkr
Mjg4b1UxQkZWUkJWWXlvVXNiVDFYS1BhUXJ5ZEFRQ29aWlE1cm9YdGR4amVtUmt4R2F6clYy
N2xvdTh1NE5INWozTG9RcXFvRXBaVlhhNzNXYXo5ZmYzVDlMOUp1YnBhcnpITkFLQlFFUitL
RFAzb3NaN1RFZmFyTm1FTmdWVlVBVlZNYUlLOTVqMkQvSjBCQUtobHNBOXB2MkRQQjJxb0Fx
cTFLSUs5NWoyRC9KMEJBS2hsbEFtVDZmZmpucjdNOUpBbmc1VlVBVlZhbEUxbVR6ZDdYWi8v
dm5uemMzTkZ5OWVGRDNsdjRhWDIrM210eElYRnhld2lEQ0FQQjJCUUtnbEF2WjBhdWhuenB5
NWZQbnkwYU5IcjE2OUtueldqNmNYRnhjLzk5eHpseTlmdm56NWNsVlYxYTkvL2V2QVJBUUFK
NEMyMk8zMjB0TFMrUGo0MHRKU3U5M09yb0k4SGFxZ0NxclVvaXBnVC8vc3M4OTR1ejUvL254
Ylc1dndXVCtlZnU3Y3VaVXJWeVltSnVyMStudnV1Y2Rtc3dVbUlnRFllWjd5OG5MK1BrY1ZG
UlhzS3NqVEVRaUVXaUpnVHhkNTlibHo1NFIvUnU1M3BCekhUWjgrWGEvWHIxcTFpdjR2U1V0
THcvMUlvUXFxb0NvNlZNWG90WXdYTGx5b3JLd3NMaTRtaE1URnhkRzdaWHM4SG8xR0krem0r
ZW1uYXpVMW05YXRVL3hlNEZoaWlTV1djcFovZDdtdTFkUzR1N29tNm9xVHFyWDd0Ny85YmVY
S2xmUTNSeXRYcmhRbCtlSEI0WERvZERwQ1NHcHFLdkowcUlJcXFJb09WY3JVVDErMmJObm16
WnZwZDZTYk5tMWF0bXhaWUNJQzVzcVZLNXMzYnk0cUtpS0VtRXdtZmo3ZFpES3huVEdmamtB
ZzFCTEtlTHBXcTNXNVhQU3gwK21rK1hKNG9GZThKQ1FrckZpeDR1elpzNFNRM3Q3ZTR1Smlu
VTVYVWxMUzE5Zkhyb0k4SGFxZ0NxclVva3FaMzVFV0ZSVnQzcno1eXBVclY2NWMyYkpsQzgy
WEl4Yms2UWdFUWkyaHpIZWtQL3p3UTFsWldXSmlZbUppWWxsWldYZDNkMkFpd2dQeWRLaUNL
cWhTaTZwSjV1bmo0K09pU1JoS3BGLzNNaUdRcHlNUUNMWEVaRHpkNC9GODk5MTNaclA1NnRX
cnpjM053cWY4ZURxOWE1MWFRSjRPVlZBRlZXcFJGYkNuOS9UMHRMVzFkWFoyOXZmM056YzNm
L2ZkZDhKbi9YajZuRGx6MkJveEVRdnlkQVFDb1pZSTJOT1BIejh1cXZFaXhJK243OXExNjhr
bm54d2FHZ3BzMzJFR2VUcFVRUlZVcVVXVk10ZTljQXloRUJFc2tLY2pFQWkxQk82SjRZdVJr
UkdiemJaMjdWb3U4dTRPSHBuM0xJY3FxSUlxWlZYWjdYYWJ6ZGJmM3g5Y000d1NUNmNnVDBj
Z0VHb0paZkwwNzcvLy91Njc3NmIxWHU2KysyNzZlODZJQmZQcFVBVlZVS1VXVmNwNGVrRkJ3
UXN2dkVCL1I3cDU4K2JDd3NKUWlBZ1d5Tk1SQ0lSYVFobFAxK3Yxd25vdmVyMCtGQ0tDQmZK
MHFJSXFxRktMS21VOHZhcXFhc3VXTFh5OWw2cXFxbENJQ0JiSTB4RUloRm9pVXE1bGpPUXJH
cEduUXhWVVFaVmFWT0ZhUnY4Z1QwY2dFR3FKR1BYMExWdTI4QjhMN0haN2FXbHBmSHg4YVdt
cDNXNW5PeU5QaHlxb2dpcTFxSXBGVCsvczdKdzFheGJ2NmVYbDVmeDlqaW9xS3RqK3lOTVJD
SVJhSXVZODNlbDBGaFlXSGp0MmpQZjB0TFEwM0k4VXFxQUtxcUpEVmN4NSt2cjE2M2Z0MmtV
STRUMDlMaTV1Ykd5TUVPTHhlRFFhamJDejU2ZWZydFhVYkZxM1R2RjdnV09KSlpaWXlsbisz
ZVc2VmxQajd1b0tybk5LZXpwdm93cGU0akpseWhUUmxUYXBxYW5JMDZFS3FxQXFPbFNGTlUr
Zk1XTkdSMGZIK1BoNEpGeTJ5R3N3bVV6OGZMckpaR0o3WWo0ZGdVQ29KY0xxNlgvKzg1L256
cDByeXBTVnVqS2QzMmx2YjI5eGNiRk9weXNwS2VucjYyTjdJaytIS3FpQ0tyV29VdXczUjZI
WWE0aEFubzVBSU5RU01mY2RhUUFnVDRjcXFJSXF0YWhTeHRQLzlyZS9yVnk1a3RiYVhibHk1
Ymx6NTBJaElsZ2dUMGNnRUdvSlpUeDkyYkpsbXpkdnZuejU4dVhMbHpkdDJyUnMyYkpRaUFn
V3lOT2hDcXFnU2kycWxQRjByVllyckxXcjArbENJU0pZSUU5SElCQnFDV1U4dmFpb2FQUG16
WHl0M2FLaW9sQ0lDQmJJMDZFS3FxQktMYXFVOGZRZmZ2aWhyS3dzTVRFeE1UR3hyS3lzdTdz
N0ZDSW1qL0FlMDNMdS9Zb2xsbGhpcWV3Uzk1ajJEL0owcUlJcXFGS0xLbHpMNkIvTXB5TVFD
TFVFUE4wL3lOT2hDcXFnU2kycTRPbitRWjZPUUNEVUV2QjAveUJQaHlxb2dpcTFxRkxHMDZk
TW1SS0t2WVlJNU9rSUJFSXRvWXluejVrejUrTEZpNkhZY1NoQW5nNVZVQVZWYWxHbGpLZnYy
clhyeVNlZkhCb2FDc1crZlZOZlg1K1RrNlBUNlJZdFd0VFcxa1prMzJNYWdVQWdJajhVcTdX
clZQMzBoeDkrMkdhek9SeU85OTkvUHpVMWxjaSt4M1NrL1RlZTBLYWdDcXFnS2taVXhlaDNw
QzZYNjlDaFF3c1hMaVN5N3pHTlFDQVFrUit4Nk9uMGswRnljdkx4NDhlSjdIdE1MeXdia0hP
UDErMTN2TzIzejRaVkgvcnRJM09QVUFWVlVBVlZ3bVZZN3pITjA5N2VucE9UUTY5K1diTm1U
WDE5ZlhCMzd4YzY5NUtWbFVWazMyTWFnVUFnSWorVXlkTnZ1ZVdXbHBZV09vM2UyOXM3Zi83
OFVJaVFaUDM2OVJjdlhuUTRIQWNQSHB3NWN5YVJmWS9wU0pzMW05Q21vQXFxb0NwR1ZDbmo2
VHFkenVWeVVVKy9kT21TWHE4UGhRaEo2dXJxWnMrZUhSOGZ2M1RwMGs4Ly9aVEl2c2MwQW9G
QVJING80K2tyVnF4NDU1MTNPSTdyNys5ZnMyYk42dFdyUXlFaVdDQlBoeXFvZ2lxMXFGTEcw
L3Y3K3g5NDRBRjZQOUxWcTFmLytPT1BvUkFSTEpDbkl4QUl0VVFzWHZjeVVaQ25ReFZVUVpW
YVZNSFQvWU04SFlGQXFDV1U4ZlR2di8vKzdydnZwbk12ZDk5OTk5bXpaME1oSWxnZ1Q0Y3Fx
SUlxdGFoU3h0TUxDZ3BlZU9FRmVvL3B6WnMzRnhZV2hrSkVzRUNlamtBZzFCTEtlTHBlcjNl
NVhQU3gwK2tNNTdXTUFZQThIYXFnQ3FyVW9rb1pUNitxcXRxeVpRdk4wN2RzMlZKVlZSVUtF
Wk5uWkdURVpyT3RYYnVXVS9wZTRGaGlpU1dXY3BaMnU5MW1zL1gzOXdmWERLVTluUzNIR1A2
NmpBR0FQQjJxb0FxcTFLSUsxNzM0Qi9QcENBUkNMUUZQOXcveWRLaUNLcWhTaXlwbFBQM3c0
Y05HbzNIS2xDa3FtbnRCSUJDSXlBOWxQRDB0TGUzZ3dZTWVqeWNVK3c0NnlOT2hDcXFnU2ky
cWxQSDA1T1RrNGVIaFVPdzRGQ0JQUnlBUWFnbGxQUDNGRjEvY3NtV0wwK2tNeGI2RER2SjBx
SUlxcUZLTEttVTh2Ykd4OGFhYmJsTGtXc2FHaG9ZRkN4Ym9kTHBGaXhhMXRiVVJRdXgyZTJs
cGFYeDhmR2xwcWQxdVoxZEJubzVBSU5RU3luaDZlbnA2WTJPakl2UHBEejMwVUZkWGw5UHAz
THQzTDcxVFhYbDVPWCtmbzRxS0NuWVY1T2xRQlZWUXBSWlZ5bmg2VWxLUzR2UHBOcHZOYURR
U1F0TFMwbkEvVWdRQ0VSMFJvL1BwQXdNRFM1WXMrZkRERHdraGNYRnhZMk5qaEJDUHg2UFJh
SVRkUEQvOWRLMm1adE82ZFJGNGQzRDVmYUFLcXFBcWRsVDkzZVc2VmxQajd1b0tybWY2OFhS
bGF3TllyVmFqMGJodjN6NzZaMnBxS3ZKMEJBSVJIUkZ6dnlPdHJhMU5UMDgvZXZRbzMySXlt
Zmo1ZEpQSnhLNkMrWFNvZ2lxb1VvdXFtUE4wMGVlRG9hR2gzdDdlNHVKaW5VNVhVbExTMTlm
SHJvSThIWUZBcUNXVThYVFVaWlN6S1RYbUNGQUZWVkNsckNxRjgzU0h3L0hDQ3k5czNibzFG
Q0tDQmZKMEJBS2hsbEIrN21Wb2FDZ3BLU2tVSW9JRjhuU29naXFvVW9zcWhUM2Q0L0hVMTll
bnA2ZUhRa1N3UUo2T1FDRFVFZ3JQcDArWk1zVm9OQjQrZkRnVUlvSUY4blNvZ2lxb1Vvc3E1
ZWRlSWgvazZRZ0VRaTBCVC9jUDhuU29naXFvVW91cWNIdTZ1dTR4UFRJeVlyUFoxcTVkeXls
OUwzQXNzY1FTU3psTHU5MXVzOW42Ky91RGE0YXk4dlN4c2JGMzNubm41cHR2WHIxNmRYQjNI
MXlRcDBNVlZFR1ZXbFFwTnZmUzFOUlVVRkR3bTkvODV2ang0NkZRRUVRd240NUFJTlFTQ25q
NmlSTW5mdk9iM3hRVUZEUTFOWVZpMzBFSGVUcFVRUlZVcVVWVnVEMTk5ZXJWTjk5ODg5dHZ2
MDNMMjZvQzVPa0lCRUl0Z2U5SS9ZTThIYXFnQ3FyVW9nclhNdm9IZVRvQ2dWQkx3TlA5Z3p3
ZHFxQUtxdFNpS3VZOG5aM3RzZHZ0cGFXbDhmSHhwYVdsZHJ1ZFhRVjVPZ0tCVUV2RW5LZFRo
SjVlWGw3TzMrZW9vcUtDN1l3OEhhcWdDcXJVb2dxZVR0TFMwbkEvVWdRQ0VSMEJUeWR4Y1hI
MHdrcVB4NlBSYUlUZFBELzlkSzJtWnRPNmRSRjRkM0Q1ZmFBS3FxQXFkbFQ5M2VXNlZsUGo3
dW9Lcm1lcXlkTlRVMU9ScHlNUWlPZ0k1T25FWkRMeDgra21rNG50alBsMHFJSXFxRktMcXBq
emRQYTNUcjI5dmNYRnhUcWRycVNrcEsrdmoxMEZlVG9DZ1ZCTHhKeW5Cd0R5ZEtpQ0txaFNp
eXA0dW4rUXB5TVFDTFVFUE4wL3lOT2hDcXFnU2kycTRPbitRWjZPUUNEVUV2QjAveUJQaHlx
b2dpcTFxSUtuK3dkNU9nS0JVRXZBMC8yRFBCMnFvQXFxMUtJS251NkxrWkVSbTgyMmR1MWFU
dWw3Z1dPSkpaWll5bG5hN1hhYnpkYmYzeDljTTR3U1Q2Y2dUNGNxcUlJcXRhaENudTRmektj
akVBaTFCRHpkUDhqVG9RcXFvRW90cXVEcC9rR2Vqa0FnMUJMd2RQOGdUNGNxcUlJcXRhaUNw
L3NIZVRvQ2dWQkx3TlA5Z3p3ZHFxQUtxdFNpQ3A1TzdIWjdhV2xwZkh4OGFXbXAzVzVuT3lC
UFJ5QVFhZ25lMHhzZWYveEtiMit3ZkZKTm5sNWVYczdmNTZpaW9vTHRnRHdkcXFBS3F0U2lp
dmYwYlVianp0emN2L3pwVDZOTzUrUjlVazJlbnBhV2h2dVJJaENJNkFpaHA5TjQvVGUvK2VH
VFR5YnBrMnJ5OUxpNHVMR3hNVUtJeCtQUmFEUzA4ZlRwMDg4OTkxejFoZzNQUHZEQS83djk5
bzJQUFBMRUUwOXNmT1NSNTU1N3p2ZnltWHZ1OGR2bkR3OCs2TGVQekQxQ0ZWUkJGVlFKbDlT
MXF0YXUvVDlQdi8zMkh6NytlSkkrcVNaUFQwMU45WnVuRTBMT25Uc25aMnZPTDc3dzIwZm1w
dVIwZ3lyNTNhQktmamVva3Q4dE1sV1JuK2RldnZqUC80eTV1UmVUeWNUUHA1dE1KcllEOVhT
MzJ5MW5hOWYyN3ZYYlIrYW01SFNES3ZuZG9FcCtONmlTM3kweVZSRkNHaDU3N0VwUGo1eWVj
bENUcC9mMjloWVhGK3QwdXBLU2tyNitQcllEOVhTWmVDNWVESjYwb0FGVjhvRXErVUNWZkNK
VGxYelU1Ty9QQ0E0QUFCNkZTVVJCVk9sKzZlcnFVbG9DQUFBb1NWUjVPZ0FBeERqdzlBQnBh
R2hZc0dDQlRxZGJ0R2hSVzFzYklZVDdtWWhTeGJaRWdxcjYrdnFjbkp4SVUwWFpzbVdMZ2kr
aWovTXFvbFNOalkxdDJiSmw5dXpaVTZaTVVVcVk3N0ZLVFUyTkVGV05qWTJabVprYWpTWWpJ
Nk94c1RIVUF1RHBBZkxRUXc5MWRYVTVuYzY5ZS9jS0w4SlIxdE5aVmQ1MEtxdnE0WWNmdHRs
c0RvZmovZmZmVitxOUp6a3luWjJkczJiTlV2QkZaRlVwZTBaUldGVmJ0MjdOemMzdDZ1b2FI
eCtQSEZVOEhSMGR6ei8vZklTb1NrcEtzbGdzTHBmTGJEWWJESVpRQzRDblR4YWJ6V1kwR3Zr
L0krRWRTQmhWa2kzaFI2VEI1WElkT25SbzRjS0ZDa29pQWxWT3A3T3dzUERZc1dPUjhDTHlx
amlPbXo1OXVsNnZYN1ZxbGMxbWl4QlZScVBSYkRZcks0YUhQYmRYclZwMS92eDVwZlJRZUZV
TEZ5NjBXQ3h1dDl0c05pOWV2RGpVKzRXblQ0cUJnWUVsUzVaOCtPR0hmRXNrMkFHcmltMVJY
Qlg5Z0p5Y25IejgrUEVJVWJWKy9mcGR1M2FSQ0hnUjJkZnJ3b1VMbFpXVnhjWEZFYUpLbzlF
OC9mVFRpWW1KUnFQeGd3OCtpQkJWbFBiMjlvY2ZmbGhCU2VTWHFrNmNPSkdVbE1SeFhGSlMw
b2tUSjBLOWEzaDY0Rml0VnFQUnVHL2ZQbUdqNG5iQXFwTFVxYmdxUWdpZGU4bkt5b29RVlhS
cVdQSEphMit2bDhQaDBPbDBpa2dpaktxMHREU3oyVXpuRTJiTW1CRWhxaWdyVnF6NCt1dXZs
WkpFR0ZYWjJkbjgzTXN0dDl3UzZyM0Qwd09rdHJZMlBUMzk2Tkdqb25abFBaMVY1VTJuc3Fy
V3IxOS84ZUpGaDhOeDhPREJtVE5uUm9ncUhnVmZSRytxcmx5NXNubno1cUtpSWlWRVNhaXFx
S2d3bTgxMFBpRTlQVDFDVkJGQ1B2Lzg4enZ1dUVNUlBSUldWWEp5TWovM2twS1NFbW9COFBR
QTRYN0owTkNRcUNVeVZRME5EVVdDcXJxNnV0bXpaOGZIeHk5ZHV2VFRUejhOdnlSSlZjS25G
SkVrcVlvK1NFaElXTEZpeGRtelp5TkVWWDkvL3gxMzNLSFQ2VEl6TTVXYVdKZDhCZSs4ODg0
alI0NG9vc2VicW9hR0JxUFJxTkZvNXMrZmYralFvVkFMZ0tjREFFRDBBRThIQUlEb0FaNE9B
QURSQXp3ZEFBQ2lCM2c2QUFCRUQvQjBBQUNJSHVEcEFBQVFQY0RUQVpnVUNsN01EZ0FMUEIx
STQzYTdOMnpZTUdQR2pHblRwbTNmdmwxcE9jckRjZHdycjd4Q0NIbjU1WmZoNDRTUXJxNHVq
dU53SXhvU1llY0dQQjFJVTFWVjljQURENXcvZi83S2xTdlBQUE9NMG5LVWgrTzR2THk4OGZI
eDNOeGN4ZCsza2NET25Udmo0dUoyN3R5cHRCRGxpYWh6QTU0T3BKa3paNDdvcnVmQ2s1Vi96
SEZjVlZXVlhxL25pNGdxZms2SENJN2picnZ0dHExYnQ5NSsrKzNDd3hjTnk2dXZ2cHFTa3BL
Y25MejM1MXNWUit1QXJGaXg0dkhISDEreFlnWDljL0hpeGZRV0VLMnRyYmZlZWlzaHBMT3pN
eTh2THlFaG9icTZXamhpU2drT0hleTVRVThNclZiTDN4bGozYnAxLy9Jdi8wSUllZmpoaDU5
NjZpbCt4YUNMZ2FjRGFUUWFqY2ZqRWJaNDgvUlhYbmxsZUhqNHlTZWZES3Urc01OeDNQNzkr
K1BpNGc0Y09DQTVGUFR4bmoxN0hBNUhjM096VW5jZ0NRL0R3OE5UcDA0OWYvNzgxS2xUaDRl
SENTR3Z2ZlphUlVVRklhUzh2SHozN3QyRWtJVUxGNzd4eGh2RHc4Tjc5KzZOU2l2bjhYWnVl
RHllOXZiMldiTm1FVUpHUjBmdnV1dXVmL3UzZjd2cnJydEdSMGRESndhZURxVHhrYWVQam80
S1BYMWtaQ1RjNHBUQWg0OExIL052MStoMnNhYW1KcjVNVlZOVEV5SGswcVZMQm9QaDNMbHpC
b1BoOHVYTGhCQ3RWdXR3T0FnaERvY2p1a2VEUFIvMjdObGpOQnJqNHVJNGpwc3laUXA5cXJP
emsrTzR6czdPa0lxQnB3TnBLaXNySDNqZ2dZR0JnYXRYcjFaV1ZoSkMwdExTamg0OTZuUTZY
My85OWVqK0tDMkpURStYZkJ4OVBQWFVVL1NiOCszYnQvTXpDU2FUNlZlLytsVjVlVG45czdD
dzhNMDMzM1E0SEcrLy9YWjBqd2I3dWlja0pEUTNOenNjRHJQWlRGc2NEc2VpUll0V3JWcTFh
TkVpcDlNWk9qSHdkQ0NOeStYNjkzLy85N1MwTlA2Nmw5cmFXb1BCa0pLU3NudjNiaCtlSHEz
dlh2WjlLNnFxS3RtSFJPbUFaR1ptZnZ2dHQ0U1FiNy85TmpNemt6YTJ0clp5SE5mYTJrci90
RnF0T1RrNUNRa0pHemR1akl1TG80MVJPUnJzNi83aWl5OGFEQWFEd2JCanh3N2E4dWlqajY1
WnM0WVE4ay8vOUUrUFBmWVl1Mkt3Z0tjREFFTEkyTmpZa1NOSGNuTnpsUllTSzhEVEFRQ2hn
czRtWjJabUtuWG5reGdFbmc0QUFORURQQjBBQUtLSE1IbTY4SHVrWUcwd1dKc0NBSUNvWVdL
ZXpubEI1czVneENwQytQcW1wcVlTUW5wNmVvcUxpK1BqNDR1TGkzdDdleVhYYW14c3pNek0x
R2cwbVptWmh3OGZwaTM1K2ZueDhmRkxsaXo1L1BQUHczb01RY1hsY2ozOTlOUHA2ZW44T2Qv
WTJHZzBHblU2M2E5Ly9ldnU3bTdKdGRoQkMzcCtvd2pzNmJGdjM3NnNyQ3lkVG5mcnJiY2VP
M1pNY2kyMmo1d3hqSHpZMFdCYldOaGpEOEJVV1NidTZWazN4QUZQajJxZWV1cXBUWnMyRVVK
Kzk3dmZWVmRYTzUzTzZ1cHFrOGtrMmRsZ01MUzB0TGhjTG92RllqQVlDQ0VtaytuVXFWTXVs
K3Z3NGNNelo4NE1wL0xnVWxsWnVYang0bE9uVG8yUGo5T1cxTlRVdHJZMnQ5dHROcHZ2di85
K3liVzhEVnJVdkJlRXA4ZTMzMzdyZERyMzdkdm43VGUwYkI4NVk2Z2krTkh3MGNMREhudFF6
b3BRZWZwcnI3MW1OQm8xR28zd2Y0Nm81K25UcDB0S1NuUTZYWFoyTnMzZzJCYU80eW9yS3hN
U0VuSnpjNjFXNi8vSjhGbGtRN0xRQkFpQUsxZXVKQ2NuOS9mM0UwSlNVMU1IQndjSklZT0Rn
OTdldElzV0xXcHRiWFc3M1VlUEhxVkZQeWdPaDZPaG9VSFZGN1RObmozN3M4OCtFN2FrcHFa
Ky9QSEg5RDJaa3BJaXVaYTNRWXVPMDFKNGV2RDA5ZlhwZERyZnZ5N20rOGdaUTdYQWpvYmsr
UEN3eDg1eG5NRmcwT3YxOTl4emo4MW1DMHhHcUR4OTZ0U3AyN1p0TzNYcWxOdnRGcTR1N0xO
a3laTDMzbnZQNVhLMXRMUmtaMmRMdG5BY1YxdGI2M0E0NnVycUNnc0xKVGZGTVVVMllxZlFS
S2pac1dNSC9hRUVJU1F1TG01c2JPeTIyMjd6ZUR3YWpVYXl2OVZxVFU1TzVqZ3VPVG1aL3cw
MC93bjBxNisrQ3BQdUVLRFJhS3FycS9WNi9ieDU4dzRlUEVnSXFhK3ZuenQzYm1KaTRzYU5H
NzBOaUxkQmk0N1RVbmg2VUg3ODhjZWlvaUxmaFR5RmZlU01vVnBnUjROdEVlTHQyQzlldkZo
WldWbGNYQnlZakZCNStrY2ZmWFR2dmZkbVoyZFBtemJ0ajMvOEk3KzZzSTlXcStVbmoyaEpC
TGFGNHppK1pJUk9weE1xRVQ0V0ZkbUluVUlUSVdWMGRIVGV2SG04TmFlbXBsNjRjSUg0ek5O
emNuSXNGb3ZMNVRLYnpYbDVlWHo3OFBEd2dRTUhDZ29LUXE4NlZDUW5KNXZOWnJmYjNkYldK
cG9oUFhiczJKdzVjeVRYOGpab1VYQmFpazRQUXNoWFgzMlZrWkZSWFYwOU5qYm1iUzF2Zlh5
TW9TcGdSNE50OFFaNzdFNm5VMmgzRXlLMDgrbGpZMlBIamgzVDYvWDB6MW16WmdrenRhS2lv
cWFtSm1IcEE3YUY0N2kzM25xTDV1bjUrZm5DZGgrUFk2ZlFSRWlwcjY4dkxTM2wvM3p3d1Fj
M2JkcmtjcmsyYmRyMCs5Ly9YbktWcEtRa2k4WGlkcnRiV2xyb2ZQcWpqejdhMDlQamNya2FH
aHBVL2VINnZ2dnU0ejJkZCtmeDhmSFRwMDh2WExpUWxzUmg4VFpvVVhCYWlrNlB1cnE2b3FL
aUw3Lzgwc2Nxa24zOGpxRXFFSTJHWkF1TDVMRmZ2MzU5NjlhdFJVVkZnU2tKbGFmVFhEc3VM
bTcrL1BsdnZQRUdiWHp6elRmMWVqM2YvOHlaTTh1WEwwOUlTT0RueDlrV2ZqNDlKeWVubzZP
RDM3THcyMkhXMHlVTFRZQ0pzbXpaTWpySlFMSFpiTXVXTGFOZjAvZjA5TkJHMGF0ZlgxOVB5
OUhObnorL29hR0JFUEx1dSs5bVpHUm90ZHFDZ2dLTHhSSk8vY0dsdTd0NzJiSmxXcTNXYURR
Mk5qYVNuMC9GOVBUMDlldlh1MXd1MmswMElPeWdzU2V3U2hHZEhxTGpHaG9hSXN4b3NIMGt4
MUNOaUVaRHNrVnlOSVRIVGx0dXV1bW01Y3VYbnoxN05qQWxZYjJXTVFBbXMzRVVtZ0FBeEJx
Ui9qdlNnRDJkUTZFSkFFRHNFZW1lRGdBQVFEN3dkQUFBaUI2aXpkTlYvYVVUQUFCTWttaXI5
d0pQRHgxeTZyMndmZVNzcFZJd0lFSXdHa0lVSEkwSmUvb3BKdURwTVlLY2VpOXNIemxycVJR
TWlCQ01oaEFGUnlOVW5zN1dlMkh6K2krLy9ITEJnZ1ZhclhiQmdnWDBad2djVTkyRmJXRnJ3
bGl0VmxyZHBiS3lFcDRlT3VUVWUySDd5RmxMcFdCQWhHQTBoQ2c0R3FIeWREbjFYdkx5OHVo
dlJHdHJheGNzV0VDa3FydXdMV3hObVB6OC9McTZPb2ZEVVZOVEEwOFBIWExxdmJCOTVLeWxV
akFnUWpBYVFoUWNqVkI1dXB4Nkx4cU5obFpsR1I0ZTFtcTFSS3E2QzlzaVdTV0czdzQ4UFhU
SXFmZkM5cEd6bGtyQmdBakJhQWhSY0RSQ081OHVxdmNTSHg4dkxDQXBtYWVMcXJ1d0xXeE5t
SUtDQXBxbjE5Yld3dE5EaDV4Nkwyd2ZPV3VwRkF5SUVJeUdFQVZISTFTZVR2Tm9VYjJYRFJz
MjBGb3U5TS8yOXZhOHZEeU5ScE9YbHllYVR4ZFdkeEcxc0RWaE9qbzZhSFdYcXFvcWVIcm9r
RlB2aGUwanVWWjBnQUVSZ3RFUW91Qm9SRmE5RjNaVDhHZ0FBSkJQWlAzbUNKNE9BQUNUSWJJ
OEhRQUF3R1NBcHdNQVFQUVFXWjd1YmFZRk16QUFBQ0NIU1ArT0ZFUU9LT2doQWdNaUJLTWhS
RTMxWHQ1bEFwNGVJNkNnaHdnTWlCQ01oaEExMVh1UjZlbkNMSDdxMUtuRVMzV1hwVXVYbHBl
WFoyUmtsSmVYMDVhcXFxckV4RVMrdWd1L0tYN0xiTDBYRUI1UTBFTUVCa1FJUmtPSW11cTlU
Q2hQcjZtcG1UNTlPblZ3eVYrTmRuVjEwU1gxZldGMWw0S0NBdUYrK2Nkc3ZSY1FIbERRUXdR
R1JBaEdRNGlhNnIzSTkvVDYrdnJrNU9Uang0L1RQeVdydTdCTFVYVVhmci84WTdiZUN3Z1BL
T2doQWdNaUJLTWhSRTMxWG1SNmVuTno4NHdaTS9qNUUrSWxUMmVYZkhVWFdvV1IzeS8vbUsz
M0FzSURDbnFJd0lBSXdXZ0lVVk85RjVtZXJ0ZnJSUmZHU0ZaM1laZDhkUmUrZnJwb08yeTlG
eEFlVU5CREJBWkVDRVpEQ09xOUFBQUFDQUtSOVpzakFBQUFrd0dlRGdBQTBRTThIUUFBb29k
d2VIcGdFKzZZcGdjQWdJa1NqdTlJNGVuUkFRcDZpTUNBQ01Gb0NGRlR2WmNiVE1EVFl3UVU5
QkNCQVJHQzBSQ2lwbm92TWozZGFyWG01ZVVsSkNSVVZsYlNEbXlkRnByamE3WGFSWXNXdGJX
MVNhNEZJZ2NVOUJDQkFSR0MwUkNpcG5vdk1qMDlQeisvcnE3TzRYRFUxTlRRRHQ3cXRIZzhu
dmIyOWxtelprbXVCU0lIRlBRUWdRRVJndEVRb3FaNkx6STlYYXZWOHRWZGFBZTJUc3VlUFh1
TVJtTmNYQnpmd3E0RklnY1U5QkNCQVJHQzBSQ2lwbm92TWoyOW9LQ0FadHkxdGJXMEExdW5K
U0Vob2JtNTJlRndtTTFtMm9kZEMwUU9LT2doQWdNaUJLTWhSRTMxWG1SNmVrZEhSMDVPVGtK
Q1FsVlZsYmM2TFMrKytLTEJZREFZRER0MjdLQXQ3Rm9nY2tCQkR4RVlFQ0VZRFNHbzl3SUFB
Q0FJNEhla0FBQVFQY0RUQVFBZ2VvQ25Bd0JBOUJDSm5vNEplZ0FBQ0F4OFJ3cmtnb0llSWpB
Z1FqQWFRdFJVNzRYNzZDTnh3Tk5qQXhUMEVJRUJFWUxSRUtLbWVpOHlQWjM3K2M2aXVibTV3
anVMQ3F1N2RIWjIwdW91MWRYVi9FWkVpVC9IY2ErKyttcEtTa3B5Y3ZMZXZYdTlyUVhDQUFw
NmlNQ0FDTUZvQ0ZGVHZSZjVubDViVyt0d09PcnE2Z29MQy9sMllYV1hoUXNYdnZIR0c4UER3
M3YzN2hYNXVQRHhuajE3SEE1SGMzTXpQVWh2YTRGUWc0SWVJakFnUWpBYVF0UlU3MFcrcDlQ
S0xRNkhRNmZURVovVlhSd09odzlQSHgwZEZiWjdXd3VFR2hUMEVJRUJFWUxSRUtLbWVpL3lQ
ZjJ0dDk2aWVYcCtmajZScXU1U1dGajQ1cHR2T2h5T3Q5OSsyNGVuaXg1N1d3dUVHaFQwRUlF
QkVZTFJFS0ttZWk4VG5VL1B5Y25wNk9nZ1V0VmRyRllycmU2eWNlUEd1TGc0d2x4WFE2UThu
VjBMaEFjVTlCQ0JBUkdDMFJBU2hmVmU1R2ZRWTJOalI0NGN5YzNOblpEdXdOWUNBSURvSmxT
L09aTHA2WFJ1UFRNejg5TlBQNTNReGdOWUN3QUFvcDVJL0IwcEFBQ0F3SUNuQXdCQTlLQzhw
MGYrdFN2ZXJzTWhnaThZd2k0S0FBQWtVRUc5bDNBNnB0OTlUZklMWVZXRGdoNGlZbWRBMkhj
NjJ5TG51Qm9iRzQxR0k3MnVvN3U3VzNJNzBVRmpZMk4rZm41OGZQeVNKVXMrLy94emIzMjhq
UWJIY2FtcHFZSHRldUwzcm1zVUJ6dzkrczVJU1ZEUVEwU3NEUWg3bmd0YjVCeFhhbXBxVzF1
YjIrMDJtODMzMzMrL2p5MnJIWlBKZE9yVUtaZkxkZmp3NFprelowcjI4VFlhaEpDbm5ucHEw
NlpOZ2UwNlZKN096bGR3VE9VV0lxTzZDL3RwNFBUcDB5VWxKVHFkTGpzN20vOEh5SEZjVlZX
VlhxOWZ2SGl4Wkl1a0hzbUtOSkw1aVBEUHFxcXF4TVJFZmkzQ25KR1NDcU1BRlBRUUVXc0Q0
dHZUWlk3R3h4OS9URjBzSlNWRmNqc2N4eTFkdXJTOHZEd2pJNk84dkR5SStzT1B3K0ZvYUdq
d2RzbTF0OUc0Y3VWS2NuSnlmMzkvWURzTnE2ZUxLcmRJOW1UN2lMYS9aTW1TOTk1N3orVnl0
YlMwWkdkbjgzMWVlZVdWNGVIaEo1OThVckpGVWc5YmtVYk9zZkJyRlJRVXlGY1lCYUNnaDRo
WUd4RGZuaTdudU9ycjYrZk9uWnVZbUxoeDQwWmhIOUZickt1cml5Nm5UcDBhMUNNSUsvd1V5
bGRmZlNYWndkdG83Tml4WTgyYU5RSHZOK1NlUGpvNnludW9xSEtMNUdPMmoyajdXcTJXejZa
cDNSamFaMlJrUkNSQTJDS3BSMVNSaHQyWHBFSy9hMGtxakFKUTBFTkVyQTJJM3p4ZC9uRWRP
M1pzenB3NWt0dmgzNTZTZTFRWHc4UERCdzRjNEpNL2J3aEhZM1IwZE42OGVaMmRuUUh2TkZT
ZW5wYVdkdlRvVWFmVCtmcnJyN012ejRRZXg4ZkgyMncydnIyb3FLaXBxY25wZElxRXNWTDk2
aEZWcEdIM0phbUtYNHZQN21mTm1pWDhWeXlwTUFwQVFROFJzVFlndnQ5bE1vOXJmSHo4OU9u
VEN4Y3VyS3lzbE54T2RIajZvNDgrMnRQVDQzSzVHaG9haFBNcUl0alJxSyt2THkwdG5jeXVR
K1hwdGJXMUJvTWhKU1ZsOSs3ZDNqeWQreVdTZlFnaEd6WnNTRWhJNFA4OGMrYk04dVhMYVl1
M1hKNXRrZFFqcWtqRDdrdFNJYjhXUDUvKzVwdHY2dlY2M3dxakFCVDBFQkU3QXlMNVJoQzF5
QmtOMmprOVBYMzkrdlV1bDh2YmxvbjZQZjNkZDkvTnlNalFhclVGQlFVV2k0VTIraDBOUXNp
eVpjc09Ianc0bVYycjRGckdFS0ZTMlFBQTRBUGxmM09rRlBCMEFFRDBFYnVlRGdBQTBRYzhI
UUFBb2dmMWVicms5d3lZU0FFQUFLTEc3MGdsZHdkUER3TnlYbTYyai9BOENiaUVSZmhoYTNG
SXRtUm1abW8wbXN6TXpNT0hEOHZjVHJSbUlYS095MXRObUczYnRrWFpnT3pidHk4ckswdW4w
OTE2NjYzSGpoMlQ3QlBZR2VXWENYdDYxbzBzVWNEVFl3bzVReTNaWnpJbExNSVBXNHVEYlRF
WURDMHRMUzZYeTJLeEdBd0dtZHVoUk9zWjYvdTRKR3ZDZlBQTk4rbnA2VkUySUwvNzNlKysv
ZlpicDlPNWI5OCtINzlIQytDTThrc0lQWjJUVVhHRnJlNGlXZTlGcTlVdVdyU29yYTJOMzJ4
c1ZseUpCQUx6OUVtV3NBZy9iQzBPdG1YUm9rV3RyYTF1dC92bzBhTzMzbnFyek8xUVJHK0hx
S2x3NHZ2MFlHdkN1Rnl1Z29LQ1AvLzV6MUhtNlR4OWZYMDZuVTcwSzNkS1lHZVVYMExyNlg0
cnJvaXF1N0F0RkkvSDA5N2VQbXZXTEJMYkZWY2lnY0E4ZlpJbExNSVBXNHVEYmJGYXJjbkp5
UnpISlNjbmUvc3hkMHhWT0NIK1RnKzJKc3l6eno1TGYzUWFsWjcrNDQ4L0ZoVVZQZlBNTTVM
UEJuWkcrU1cwbnU2MzRvcW91Z3Zic21mUEhxUFJHQmNYeC8xY080V0w0WW9ya1VBQW5qNzVF
aFlLSXFwTUltekp5Y214V0N3dWw4dHNOdWZsNVUxb081SXBEbEcvdGZuTjAwVTFZZWhiT3lx
L1kvanFxNjh5TWpLcXE2dkh4c1o4OXd6c2pQSkdhRDFkK0tlY0NqQnNTMEpDUW5OenM4UGhN
SnZOZkorWXJiZ1NDUVRnNlpNdllhRUliQzBPVVV0U1VwTEZZbkc3M1MwdExUNW1QMk9rd2du
RnQzNGZOV0hVZnVBaTZ1cnFpb3FLdnZ6eVM5L2RBanVqZkJNK1Q1ZFpBVWJVOHVLTEx4b01C
b1BCc0dQSERyNVB6RlpjVVJidWwvQ05mdnRNdm9SRitLSDYyY29rd3BiNitucjZJWEwrL1Br
TkRRMzhpbksySXh5aTZQQjBPYWVIajFvMzZqMXdTVVNqTVRRMFJHU2NHNUpuMUVSUjM3V01B
QUFBdktHKzN4d0JBQUR3Qmp3ZEFBQ2lCM2c2QUFCRUR4SHQ2Wml2QndDQUNSSEM3MGpsZUhH
dytvQ2dJM3g5YVowV09TVXMySUllM2twOHFBNTJRT1RrSE96aFIwZW13bzVHWTJOamZuNStm
SHo4a2lWTGZQOTRtNjN1b3ZaNkw1S2pJYXJsd3VLdHp5UkhZOEtlYm1XQXAwYzNmSjBXT1NV
czJJSWVraVUrVkkyb2NJM3Y4OVBiNFVmTldjMlBoc2xrT25YcWxNdmxPbno0OE15Wk03MzFa
NnU3UkZPOUYzNDB2Tlg1RVNMWlovS2pFU3BQWjdQNEw3Lzhjc0dDQlZxdGRzR0NCZlJTZkxZ
UGZTeXM3a0tpNk94WEk1SjFXbnlYc0JBVjlHQmJWQTA3SUw3UFQyK0hIeDFuTlRzYURvZWpv
YUVoTnpkWHNqOWIzU1dhNnIwSVI4TmJuUjhoYkorZ2pFYjQ4dlM4dkR6Nis4L2EydG9GQ3ha
STlxRUlxN3Q0NndQQ0ExdW54WGNKQzdhZ0I5dWlhdGdCOFgxK2Vqdjg2RGlyUmFQQlR6NElm
OVF0aEszdUVrMzFYb1NqNGEzT2p4QzJUMUJHSTN5ZXJ0Rm9hSjJXNGVGaHJWWXIyWWV0N3NM
MkFXR0RyZFBpdDRRRlc5Q0RiVkV2a29Wci9PYnBrb2NmQldlMTVHZ01EdzhmT0hDQUw2NG5n
cTN1RWpYMVhyd1ZOV0xyQmJId2ZZSXlHaUgwOVBqNGVKdk54djhwbWFlTCtyRFZYUWhUeXdX
RURWR2RGamtsTE5pQ0hqNUtmS2dPeWNJMXZ0OTczZzVmMWY1RkVZM0dvNDgrMnRQVDQzSzVH
aG9hdk0wMjhMQ0hyL1lCWWM4TnlUby9JcnoxaWRBOGZjT0dEYlRpQ3YyenZiMDlMeTlQbzlI
azVlWHh2aURxdzFaM0lVd3RGeEEyUkhWYXVGOGlXY0tDTGVqaG84U0g2dkE5SUh5amNCWDI4
Q1hYVWlPaTBYajMzWGN6TWpLMFdtMUJRWUhGWXFHTk1qL0UrK2lwRmlUUERXRXRGeUtqM292
d3FZQ1ZvTjRMQUFCRUR4SDlteU1BQUFBVEFwNE9BQURSQXp3ZEFBQ2lCM2c2QUJFTnZxOENF
d0tlRG9BRUFUdHAwQzNZeHdhRHNpK080MTU1NVJWQ3lNc3Z2enlaRFhJY3QzUG56c2tMWThz
S05UWTJabVptYWpTYXpNek13NGNQZTl1NzZIb05sOHYxOU5OUDA5L1plOVBEMXFpUmMra0hX
OE5IVHEwYjlyamsxQUlLNERvVWVEb0FFc1NVcCtmbDVZMlBqK2ZtNWs3UzAzTnljcTVmdno1
SllXeFpJWVBCME5MUzRuSzVMQmFMNzd0MEN2ZGJXVm01ZVBIaVU2ZE9qWStQZSt2UDFxaVJv
NXl0NFNPbjFnMTdYUEpyQWNIVEFaZ3NrdThyN3BmRmlGNTc3VFdqMGFqUmFQaE1TazZXSjhy
Q2lPQVd1N201dWZRV3UxYXJOUzh2THlFaG9iS3lVcmhsNGQ3WmZaMCtmYnFrcEVTbjAyVm5a
L1Bab2w4NzREanV0dHR1MjdwMTYrMjMzMDQ3UzVabWV2WFZWMU5TVXBLVGsvZnUzZXR0Tzl1
MmJYdnBwWmY0bmJMYldieDRNUlhmMnRwNjY2MjMraGJHbHhWYXRHaFJhMnVyMiswK2V2U283
N1dFQnp0Nzl1elBQdnZNUndjZVlZMGFqdU1NQm9OZXI3L25ubnY0bjBPSzF2Sld3OGQzclJ2
MnVPVFhBb0tuQXpCWnZMMkxoTVdJcGs2ZHVtM2J0bE9uVHJuZGJyOHJTbmJnL2JxMnR0Ymhj
TlRWMVJVV0ZoSkM4dlB6NitycUhBNUhUVTJOc0wvdlVraExsaXg1NzczM1hDNVhTMHRMZG5h
Mi9DUGR2MzkvWEZ6Y2dRTUg2QWJabjN4ekhMZG56eDZIdzlIYzNPeXR3QVBIY1VORFExbFpX
VmV1WFBHMm5kZGVlNjJpb29JUVVsNWV2bnYzYmgrcWhHV0ZyRlpyY25JeXgzSEp5Y25zais5
Rkd2akhHbzJtdXJwYXI5ZlBtemZQeHkzTzZUOUZVWTJhaXhjdlZsWldGaGNYUzY0aVdjTkhj
anUrajB0K0xTQjRPZ0NUaFgwWHNjV0lQdnJvbzN2dnZUYzdPM3ZhdEdsLy9PTWZ2YTNvYmN1
am82TzhwOU5TU0E2SFE2ZlRFVUswV2kxZkhJbjJrVk1LU2F2VjhwazczMmRDUjBvZnM2V1pP
STRiSFIzMWZZQzBmZnYyN2M4Ly83eTM3Vnk2ZE1sZ01KdzdkODVnTUZ5K2ZObWJKRkZab1p5
Y0hJdkY0bks1ekdaelhsNmV6R05KVGs0Mm04MXV0N3V0clkzV05QZUdaSTBhcDlOSlh3c1di
elY4Zk5lNllZOUxmaTBnZURvQWs0VjlGMGtXSXlLRWpJMk5IVHQyVEsvWDB6OUZKWXhZMHRM
U2poNDk2blE2WDMvOWRkN1RhVDViVjFlWG41OVBDQ2tvS0tCNWVtMXRMZTBqdVhmUnZvcUtp
cHFhbXB4T1o4Qkg2aU5QOXpFeXd2Ymg0ZUg1OCtkNzJ3NGh4R1F5L2VwWHZ5b3ZML2VtaHkw
cmxKU1VaTEZZM0c1M1MwdUwvUG4wKys2N2ovZDBiNTh0dk5Xb3VYNzkrdGF0VzR1S2lpVFhZ
bXY0eUtsMXd4NlgvRnBBOEhRQUpndjNTNGhVTVNMNlZGeGMzUHo1ODk5NDR3MjZvcWlFRVV0
dGJhM0JZRWhKU2RtOWU3ZG9QajBuSjZlam80TVEwdEhSa1pPVGs1Q1FVRlZWNVczdjdMN09u
RG16ZlBseTJzSTNCakFYeEpabWt1L3BoSkNkTzNkNjJ3NGhwTFcxbGVPNDF0WldIM3FFREEw
TjFkZlgwODhvOCtmUGIyaG9rTE1XSWFTN3UzdlpzbVZhcmRab05EWTJOa3FLWjJ2VTBOVnZ1
dW1tNWN1WG56MTdWbkl0dG9hUFpLMGJ2OGNscHhZUTIrSVhlRG9BQ2pPaExBd0EzOERUQVZB
WWVEb0lJdkIwQUFDSUh1RHBBQUFRUGNEVEFRQWdlb0NuQXdCQTlBQlBCK3FncWFtcHViblo0
L0UwTnpjM05UWEpYTVgzczk0NkRBOFBtODFteWY0KzFnSWdFb0NuQTNYUTFOVDB4UmRmZlAv
OTkzLzV5MStDNWFyZXR2UDExMSt6VDhIS2dTcUFwd04xME5UVWRPYk1HWXZGY3ViTUdkNWVS
USthbXBxNnVyb3NGc3ZwMDZlOU5ZcTJ5ZTdvK3ZYcnJhMnRrcDV1c1ZnKy92ampnWUdCb0I0
WkFNRUVuZzdVUVZOVDA2VkxsL2dsM3loODBOVFVkUG55NWVIaFlmcGJQc2xHMFRiWkhmMzFy
My90N3U2V2ZHcDhmSHhnWU9EbzBhUEJPeXdBZ2d3OEhhaURwcWFtOGZIeFR6NzVaSHg4bkRk
Y2k4VXlQRHpNdXp4cjhXeWphSnVTTy9JMmJ6NCtQbjdod2dWNE9vaGs0T2xBSFFnZGxuOTgr
dlJwaThYUzFkVVZnS2VMakp0OWxuM1ExTlQwOGNjZm56OS9QcGdIQmtCUWdhY0RBRUQwQUU4
SEFJRG9BWjRPQUFEUkF6d2RBQUNpQjNnNkFBQkVEL0IwQUFDSUh2N1AwNjFXNjM0QUFBRHFo
NE9oQXdCQTFQRC9BWjRFWUVWMjZ4WHVBQUFBQUVsRlRrU3VRbUNDIiAvPjwvcD48cD4mbmJz
cDs8L3A+PHA+SWYgeW91IG5lZWQgb3RoZXIgY2hhcnRzLCBJIGNhbiB0cnkgdG8gcHJvZHVj
ZSB0aGVtLiA8L3A+PHA+Jm5ic3A7PC9wPjxwPkJSLDxiciAvPkNhcnN0ZW4uPC9wPjxwPiZu
YnNwOzwvcD48YmxvY2txdW90ZSBzdHlsZT0iYm9yZGVyLWxlZnQ6IDJweCBzb2xpZCAjMzI1
RkJBOyBwYWRkaW5nLWxlZnQ6IDVweDttYXJnaW4tbGVmdDo1cHg7Ij4tLS0tLVVyc3ByJnV1
bWw7bmdsaWNoZSBOYWNocmljaHQtLS0tLTxiciAvPjxzdHJvbmc+QW46PC9zdHJvbmc+CUNh
cnN0ZW4gU2NoaWVycyAmbHQ7Y2Fyc3RlbkBzY2hpZXJzLmRlJmd0Ozsgemhlbnpob25nLmR1
YW5Ab3JhY2xlLmNvbTsgbGVyc2VrQHJlZGhhdC5jb207IDxiciAvPjxzdHJvbmc+Q0M6PC9z
dHJvbmc+CXhlbi1kZXZlbCAmbHQ7eGVuLWRldmVsQGxpc3RzLnhlbnNvdXJjZS5jb20mZ3Q7
OyBrb25yYWQud2lsayAmbHQ7a29ucmFkLndpbGtAb3JhY2xlLmNvbSZndDs7IDxiciAvPjxz
dHJvbmc+Vm9uOjwvc3Ryb25nPglLb25yYWQgUnplc3p1dGVrIFdpbGsgJmx0O2tvbnJhZEBk
YXJub2sub3JnJmd0OzxiciAvPjxzdHJvbmc+R2VzZW5kZXQ6PC9zdHJvbmc+CU1vIDI4LjEx
LjIwMTEgMTY6MzM8YnIgLz48c3Ryb25nPkJldHJlZmY6PC9zdHJvbmc+CVJlOiBbWGVuLWRl
dmVsXSBMb2FkIGluY3JlYXNlIGFmdGVyIG1lbW9yeSB1cGdyYWRlIChwYXJ0Mik8YnIgLz5P
biBGcmksIE5vdiAyNSwgMjAxMSBhdCAxMToxMTo1NVBNICswMTAwLCBDYXJzdGVuIFNjaGll
cnMgd3JvdGU6PGJyIC8+Jmd0OyBJIGdvdCB0aGUgdmFsdWVzIGluIERvbVUuIEkgd2lsbCBo
YXZlPGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7ICZuYnNwOyAtIGFwcm94LiA1JSBsb2FkIGluIERv
bVUgd2l0aCAyLjYuMzQgWGVuaWZpZWQgS2VybmVsPGJyIC8+Jmd0OyAmbmJzcDsgLSBhcHJv
eC4gMTUlIGxvYWQgaW4gRG9tVSB3aXRoIDIuNi4zMi40NiBKZXJlbXkgb3IgMy4xLjIgS2Vy
bmVsIHdpdGggb25lIGNhcmQgYXR0YWNoZWQ8YnIgLz4mZ3Q7ICZuYnNwOyAtIGFwcm94LiAz
MCUgbG9hZCBpbiBEb21VIHdpdGggMi42LjMyLjQ2IEplcmVteSBvciAzLjEuMiBLZXJuZWwg
d2l0aCB0d28gY2FyZHMgYXR0YWNoZWQ8YnIgLz48YnIgLz5IQSE8YnIgLz48YnIgLz5JIGp1
c3Qgd29uZGVyIGlmIHRoZSBpc3N1ZSBpcyB0aGF0IHRoZSByZXBvcnRpbmcgb2YgQ1BVIHNw
ZW50IGlzIHdyb25nLjxiciAvPkxhc3psbyBFcnNlayBhbmQgWmhlbnpob25nIER1YW4gaGF2
ZSBib3RoIHJlcG9ydGVkIGEgYnVnIGluIHRoZSBwdm9wczxiciAvPmNvZGUgd2hlbiBpdCBj
YW1lIHRvIGFjY291bnQgb2YgQ1BVIHRpbWUuPGJyIC8+PGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7
IEkgbG9va2VkIHRocm91Z2ggbXkgb2xkIG1haWxzIGZyb20geW91IGFuZCB5b3UgZXhwbGFp
bmVkIGFscmVhZHkgdGhlIG5lY2Vzc2l0eSBvZiBkb3VibGU8YnIgLz4mZ3Q7IGJvdW5jZSBi
dWZmZXJpbmcgKFBDSS0mZ3Q7YmVsb3cgNEdCLSZndDthYm92ZSA0R0IpLiBXaGF0IEkgZG9u
JiMzOTt0IHVuZGVyc3RhbmQgaXM6IHdoeSBkb2VzIHRoZTxiciAvPiZndDsgWGVuaWZpZWQg
a2VybmVsIG5vdCBoYXZlIHRoaXMga2luZCBvZiBpc3N1ZT88YnIgLz48YnIgLz5UaGF0IGlz
IGEgcHV6emxlLiBJdCBzaG91bGQgbm90LiBUaGUgY29kZSBpcyB2ZXJ5IG11Y2ggdGhlIHNh
bWUgLSBib3RoPGJyIC8+dXNlIHRoZSBnZW5lcmljIFNXSU9UTEIgd2hpY2ggaGFzIG5vdCBj
aGFuZ2VkIGZvciB5ZWFycy48YnIgLz4mZ3Q7IDxiciAvPiZndDsgVGhlIGRyaXZlciBpbiBx
dWVzdGlvbiBpcyBuZWFybHkgaWRlbnRpY2FsIGJldHdlZW4gdGhlIHR3byBrZXJuZWwgdmVy
c2lvbnMuIEl0IGlzIGluPGJyIC8+Jmd0OyBEcml2ZXJzL21lZGlhL2R2Yi90dHBjaSBieSB0
aGUgd2F5IGFuZCB3aGVuIEkgdW5kZXJzdG9vZCB0aGUgY29kZSByaWdodCwgdGhlIGFsbG8g
aW4gPGJyIC8+Jmd0OyBxdWVzdGlvbiBpczo8YnIgLz4mZ3Q7IDxiciAvPiZndDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7IC8qIGFsbG9jYXRlIGFuZCBpbml0IGJ1ZmZlcnMgKi88
YnIgLz4mZ3Q7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBhdjcxMTAtJmd0O2RlYmlf
dmlydCA9IHBjaV9hbGxvY19jb25zaXN0ZW50KHBkZXYsIDgxOTIsICZhbXA7YXY3MTEwLSZn
dDtkZWJpX2J1cyk7PGJyIC8+PGJyIC8+R29vZC4gU28gaXQgYWxsb2NhdGVzIGl0IGR1cmlu
ZyBpbml0IGFuZCB1c2VzIGl0LjxiciAvPiZndDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IGlmICghYXY3MTEwLSZndDtkZWJpX3ZpcnQpPGJyIC8+Jmd0OyAmbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IGdvdG8gZXJyX3Nh
YTcxNDY2X3ZmcmVlXzQ7PGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7IGlzbiYjMzk7dCBpdD8gSSB0
aGluayB0aGUgY2FyZHMgYXJlIGNvbnN0YW50bHkgdHJhbnNmZXJyaW5nIHRoZSBzdHJlYW0g
cmVjZWl2ZWQgdGhyb3VnaCBETUEuIDxiciAvPjxiciAvPlllYWgsIGFuZCB0aGF0IG1lbW9y
eSBpcyBzZXQgYXNpZGUgZm9yIHRoZSBsaWZlIG9mIHRoZSBkcml2ZXIuIFNvIHRoZXJlPGJy
IC8+c2hvdWxkIGJlIG5vIGJvdW5jZSBidWZmZXJpbmcgaGFwcGVuaW5nIChhcyBpdCBhbGxv
Y2F0ZWQgdGhlIG1lbW9yeTxiciAvPmJlbG93IHRoZSA0R0IgbWFyaykuPGJyIC8+Jmd0OyA8
YnIgLz4mZ3Q7IEkgaGF2ZSBzZXQgZG9tMF9tZW09NTEyTSBieSB0aGUgd2F5LCBzaGFsbCBJ
IGNoYW5nZSB0aGF0IGluIHNvbWUgd2F5PzxiciAvPjxiciAvPkRvZXMgdGhlIHJlcG9ydGlu
ZyAoQ1BVIHVzYWdlIG9mIERvbVUpIGNoYW5nZSBpbiBhbnkgd2F5IHdpdGggdGhhdD88YnIg
Lz4mZ3Q7IDxiciAvPiZndDsgSSBjYW4gdHJ5IG91dCBzb21lIHRoaW5ncywgaWYgeW91IHdh
bnQgbWUgdG8uIEJ1dCBJIGhhdmUgbm8gaWRlYSB3aGF0IHRvIGRvIGFuZCB3aGVyZSB0bzxi
ciAvPiZndDsgc3RhcnQsIHNvIEkgcmVseSBvbiB5b3VyIGhlbHAuLi48YnIgLz4mZ3Q7IDxi
ciAvPiZndDsgQ2Fyc3Rlbi48YnIgLz4mZ3Q7IDxiciAvPiZndDsgLS0tLS1VcnNwcj9uZ2xp
Y2hlIE5hY2hyaWNodC0tLS0tPGJyIC8+Jmd0OyBWb246IHhlbi1kZXZlbC1ib3VuY2VzQGxp
c3RzLnhlbnNvdXJjZS5jb20gW21haWx0bzp4ZW4tZGV2ZWwtYm91bmNlc0BsaXN0cy54ZW5z
b3VyY2UuY29tXSBJbSBBdWZ0cmFnIHZvbiBLb25yYWQgUnplc3p1dGVrIFdpbGs8YnIgLz4m
Z3Q7IEdlc2VuZGV0OiBGcmVpdGFnLCAyNS4gTm92ZW1iZXIgMjAxMSAxOTo0MzxiciAvPiZn
dDsgQW46IENhcnN0ZW4gU2NoaWVyczxiciAvPiZndDsgQ2M6IHhlbi1kZXZlbDsga29ucmFk
LndpbGs8YnIgLz4mZ3Q7IEJldHJlZmY6IFJlOiBbWGVuLWRldmVsXSBMb2FkIGluY3JlYXNl
IGFmdGVyIG1lbW9yeSB1cGdyYWRlIChwYXJ0Mik8YnIgLz4mZ3Q7IDxiciAvPiZndDsgT24g
VGh1LCBOb3YgMjQsIDIwMTEgYXQgMDE6Mjg6NDRQTSArMDEwMCwgQ2Fyc3RlbiBTY2hpZXJz
IHdyb3RlOjxiciAvPiZndDsgJmd0OyBIZWxsbyBhZ2FpbiwgSSB3b3VsZCBsaWtlIHRvIGNv
bWUgYmFjayB0byB0aGF0IHRoaW5nLi4uc29ycnkgdGhhdCBJIGRpZCBub3QgaGF2ZSB0aGUg
dGltZSB1cCB0byBub3cuPGJyIC8+Jmd0OyAmZ3Q7IDxiciAvPiZndDsgJmd0OyA/PzxiciAv
PiZndDsgJmd0OyBXZSAobm93KSBzcGVhayBhYm91dDxiciAvPiZndDsgJmd0OyA8YnIgLz4m
Z3Q7ICZndDsgPz88YnIgLz4mZ3Q7ICZndDsgKglYZW4gNC4xLjI8YnIgLz4mZ3Q7ICZndDsg
KglEb20wIGlzIEplcmVteSYjMzk7cyAyLjYuMzIuNDYgNjQgYml0PGJyIC8+Jmd0OyAmZ3Q7
ICoJRG9tVSBpbiBxdWVzdGlvbiBpcyBub3cgMy4xLjIgNjQgYml0PGJyIC8+Jmd0OyAmZ3Q7
ICoJU2FtZSB0aGluZyBpZiBEb21VIGlzIGFsc28gMi42LjMyLjQ2PGJyIC8+Jmd0OyAmZ3Q7
ICoJRG9tVSBvd25zIHR3byBQQ0kgY2FyZHMgKERWQi1DKSB0aGF0IG8gRE1BPGJyIC8+Jmd0
OyAmZ3Q7ICoJTWFjaGluZSBoYXMgOEdCLCBEb20wIHBpbm5lZCBhdCA1MTJNQjxiciAvPiZn
dDsgJmd0OyA8YnIgLz4mZ3Q7ICZndDsgPz88YnIgLz4mZ3Q7ICZndDsgQXMgY29tcGFyZWQg
dG8gMi42LjM0IEtlcm5lbCB3aXRoIGJhY2twb3J0ZWQgcGF0Y2hlcywgdGhlIGxvYWQgb24g
dGhlIERvbVUgaXMgYXQgbGVhc3QgdHdpY2UgYXMgaGlnaC4gSXQ8YnIgLz4mZ3Q7ICZndDsg
PGJyIC8+Jmd0OyAmZ3Q7IHdpbGwgYmUgJnF1b3Q7Y2xvc2UgdG8gbm9ybWFsJnF1b3Q7IGlm
IEkgcmVkdWNlIHRoZSBtZW1vcnkgdXNlZCB0byA0R0IuPGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7
IFRoYXQgaXMgaW4gdGhlIGRvbTAgb3IganVzdCBpbiBnZW5lcmFsIG9uIHRoZSBtYWNoaW5l
PzxiciAvPiZndDsgJmd0OyA8YnIgLz4mZ3Q7ICZndDsgPz88YnIgLz4mZ3Q7ICZndDsgQXMg
eW91IGNhbiBzZWUgZnJvbSB0aGUgYXR0YWNobWVudCwgeW91IG9uY2UgaGFkIGFuIGlkZWEu
IFNvIHNob3VsZCB3ZSB0cnkgdG8gZmluZCBzb21ldGhpbmcuLi4/PGJyIC8+Jmd0OyA8YnIg
Lz4mZ3Q7IEkgdGhpbmsgdGhhdCB3YXMgdG8gaW5zdHJ1bWVudCBzd2lvdGxiIHRvIGdpdmUg
YW4gaWRlYSBvZiBob3c8YnIgLz4mZ3Q7IG9mdGVuIGl0IGlzIGNhbGxlZCBhbmQgYmFzaWNh
bGx5IGhhdmUgYSBtYXRyaXggb2YgaXRzIGxvYWQuIEFuZDxiciAvPiZndDsgZnJvbSB0aGVy
ZSBmaWd1cmUgb3V0IGlmIHRoZSBpc3N1ZSBpcyB0aGF0OjxiciAvPiZndDsgPGJyIC8+Jmd0
OyAmbmJzcDsxKS4gVGhlIGRyaXZlcnMgYWxsb2NvYXRlL2JvdW5jZS9kZWFsbG9jYXRlIGJ1
ZmZlcnMgb24gZXZlcnkgaW50ZXJydXB0PGJyIC8+Jmd0OyAmbmJzcDsgJm5ic3A7IChiYWQs
IGRyaXZlciBzaG91bGQgYmUgdXNpbmcgc29tZSBmb3JtIG9mIGRtYSBwb29sIGFuZCBtb3N0
IG9mIHRoZTxiciAvPiZndDsgJm5ic3A7ICZuYnNwOyBpdnR2IGRvIHRoYXQpPGJyIC8+Jmd0
OyA8YnIgLz4mZ3Q7ICZuYnNwOzIpLiBUaGUgYnVmZmVycyBhbGxvY2F0ZWQgdG8gdGhlIGRy
aXZlcnMgYXJlIGFib3ZlIHRoZSA0R0IgYW5kIHdlIGVuZDxiciAvPiZndDsgJm5ic3A7ICZu
YnNwOyB1cCBib3VuY2luZyBpdCBuZWVkbGVzc2x5LiBUaGF0IGNhbiBoYXBwZW4gaWYgdGhl
IGRvbTAgaGFzIG1vc3Qgb2Y8YnIgLz4mZ3Q7ICZuYnNwOyAmbmJzcDsgdGhlIHByZWNpb3Vz
IG1lbW9yeSB1bmRlciA0R0IuIEhvd2V2ZXIsIHRoYXQgaXMgdXN1YWxseSBub3QgdGhlIGNh
c2U8YnIgLz4mZ3Q7ICZuYnNwOyAmbmJzcDsgYXMgdGhlIGRvbWFpbiBpc3VzdWFsbHkgYWxs
b2NhdGVkIGZyb20gdGhlIHRvcCBvZiB0aGUgbWVtb3J5LiBUaGU8YnIgLz4mZ3Q7ICZuYnNw
OyAmbmJzcDsgZml4IGZvciB0aGF0IHdhcyB0byBzZXQgZG9tMF9tZW09bWF4OlhYLiAuLiBi
dXQgd2l0aCBEb20wIGtlcm5lbHM8YnIgLz4mZ3Q7ICZuYnNwOyAmbmJzcDsgYmVmb3JlIDMu
MSwgdGhlIHBhcmFtZXRlciB3b3VsZCBiZSBpZ25vcmVkLCBzbyB5b3UgaGFkIHRvIHVzZTxi
ciAvPiZndDsgJm5ic3A7ICZuYnNwOyAmIzM5O21lbT1YWCYjMzk7IG9uIHRoZSBMaW51eCBj
b21tYW5kIGxpbmUgYXMgd2VsbC48YnIgLz4mZ3Q7IDxiciAvPiZndDsgJm5ic3A7MykuIFdo
ZXJlIGRpZCB5b3UgZ2V0IHRoZSBsb2FkIHZhbHVlcz8gV2FzIGl0IGRvbTA/IG9yIGRvbVU/
PGJyIC8+Jmd0OyA8YnIgLz4mZ3Q7IDxiciAvPiZndDsgPGJyIC8+Jmd0OyAmZ3Q7IDxiciAv
PiZndDsgJmd0OyA/PzxiciAvPiZndDsgJmd0OyBDYXJzdGVuLjxiciAvPiZndDsgJmd0OyA/
PzxiciAvPiZndDsgJmd0OyAtLS0tLVVyc3ByPz9uZ2xpY2hlIE5hY2hyaWNodC0tLS0tPGJy
IC8+Jmd0OyAmZ3Q7IEFuOmtvbnJhZC53aWxrICZsdDtrb25yYWQud2lsa0BvcmFjbGUuY29t
Jmd0OzsgPGJyIC8+Jmd0OyAmZ3Q7IENDOmxpbnV4ICZsdDtsaW51eEBlaWtlbGVuYm9vbS5p
dCZndDs7IHhlbi1kZXZlbCAmbHQ7eGVuLWRldmVsQGxpc3RzLnhlbnNvdXJjZS5jb20mZ3Q7
OyA8YnIgLz4mZ3Q7ICZndDsgVm9uOkNhcnN0ZW4gU2NoaWVycyAmbHQ7Y2Fyc3RlbkBzY2hp
ZXJzLmRlJmd0OzxiciAvPiZndDsgJmd0OyBHZXNlbmRldDpNaSAyOS4wNi4yMDExIDIzOjE3
PGJyIC8+Jmd0OyAmZ3Q7IEJldHJlZmY6QVc6IFJlOiBSZTogUmU6IEFXOiBSZTogW1hlbi1k
ZXZlbF0gQVc6IExvYWQgaW5jcmVhc2UgYWZ0ZXIgbWVtb3J5IHVwZ3JhZGU/PGJyIC8+Jmd0
OyAmZ3Q7ICZndDsgTGV0cyBmaXJzdCBkbyB0aGUgYykgZXhwZXJpbWVudCBhcyB0aGF0IHdp
bGwgbGlrZWx5IGV4cGxhaW4geW91ciBsb2FkIGF2ZXJhZ2UgaW5jcmVhc2UuPGJyIC8+Jmd0
OyAmZ3Q7IC4uLjxiciAvPiZndDsgJmd0OyAmZ3Q7ICZndDtjKS4gSWYgeW91IHdhbnQgdG8g
c2VlIGlmIHRoZSBmYXVsdCBoZXJlIGxpZXMgaW4gdGhlIGJvdW5jZSBidWZmZXIgPGJyIC8+
Jmd0OyAmZ3Q7ICZndDsgYmVpbmcgdXNlZCBtb3JlPGJyIC8+Jmd0OyAmZ3Q7ICZndDsgJmd0
O29mdGVuIGluIHRoZSBEb21VIGIvYyB5b3UgaGF2ZSA4R0Igb2YgbWVtb3J5IG5vdyBhbmQg
eW91IGVuZCB1cCB1c2luZyA8YnIgLz4mZ3Q7ICZndDsgJmd0OyBtb3JlIHBhZ2VzPGJyIC8+
Jmd0OyAmZ3Q7ICZndDsgJmd0O3Bhc3QgNEdCIChpbiBEb21VKSwgSSBjYW4gY29vayB1cCBh
IHBhdGNoIHRvIGZpZ3VyZSB0aGlzIG91dC4gQnV0IGFuIDxiciAvPiZndDsgJmd0OyAmZ3Q7
IGVhc2llciB3YXkgaXM8YnIgLz4mZ3Q7ICZndDsgJmd0OyAmZ3Q7dG8ganVzdCBkbyAob24g
dGhlIFhlbiBoeXBlcnZpc29yIGxpbmUpOiBtZW09NEcgYW5kIHRoYXQgd2lsbCBtYWtlIDxi
ciAvPiZndDsgJmd0OyAmZ3Q7IHRoaW5rIHlvdSBvbmx5IGhhdmU8YnIgLz4mZ3Q7ICZndDsg
Jmd0OyAmZ3Q7NEdCIG9mIHBoeXNpY2FsIFJBTS4gPz9JZiB0aGUgbG9hZCBjb21lcyBiYWNr
IHRvIHRoZSBub3JtYWwgJnF1b3Q7YW1vdW50JnF1b3Q7IDxiciAvPiZndDsgJmd0OyAmZ3Q7
IHRoZW4gdGhlIGxpa2VseTxiciAvPiZndDsgJmd0OyAmZ3Q7ICZndDtjdWxwcml0IGlzIHRo
YXQgYW5kIHdlIGNhbiB0aGluayBvbiBob3cgdG8gZml4IHRoaXMuPGJyIC8+Jmd0OyAmZ3Q7
IDxiciAvPiZndDsgJmd0OyBZb3UgYXJlIG9uIHRoZSByaWdodCB0cmFjay4gTG9hZCB3YXMg
Z29pbmcgZG93biB0byAmcXVvdDtub3JtYWwmcXVvdDsgMTAlIHdoZW4gcmVkdWNpbmc8YnIg
Lz4mZ3Q7ICZndDsgWGVuIHRvIDRHQiBieSB0aGUgcGFyYW1ldGVyLiBMb2FkIHNlZW1zIHRv
IGJlIHN0aWxsIGEgbGl0dGxlLCBsaXR0bGUgYml0IGxvd2VyPGJyIC8+Jmd0OyAmZ3Q7IHdp
dGggWGVuaWZpZWQgS2VybmVsICg4LTklKSwgYnV0IHRoaXMgaXMgZHJhc3RpY2FsbHkgbG93
ZXIgdGhhbiB0aGUgMjAlIHdlIGhhZDxiciAvPiZndDsgJmd0OyBiZWZvcmUuPGJyIC8+Jmd0
OyA8YnIgLz4mZ3Q7ICZndDsgX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX188YnIgLz4mZ3Q7ICZndDsgWGVuLWRldmVsIG1haWxpbmcgbGlzdDxiciAv
PiZndDsgJmd0OyBYZW4tZGV2ZWxAbGlzdHMueGVuc291cmNlLmNvbTxiciAvPiZndDsgJmd0
OyBodHRwOi8vbGlzdHMueGVuc291cmNlLmNvbS94ZW4tZGV2ZWw8YnIgLz4mZ3Q7IDxiciAv
PiZndDsgPGJyIC8+Jmd0OyBfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fXzxiciAvPiZndDsgWGVuLWRldmVsIG1haWxpbmcgbGlzdDxiciAvPiZndDsg
WGVuLWRldmVsQGxpc3RzLnhlbnNvdXJjZS5jb208YnIgLz4mZ3Q7IGh0dHA6Ly9saXN0cy54
ZW5zb3VyY2UuY29tL3hlbi1kZXZlbDxiciAvPiZndDsgPGJyIC8+PGJyIC8+X19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX188YnIgLz5YZW4tZGV2ZWwg
bWFpbGluZyBsaXN0PGJyIC8+WGVuLWRldmVsQGxpc3RzLnhlbnNvdXJjZS5jb208YnIgLz5o
dHRwOi8vbGlzdHMueGVuc291cmNlLmNvbS94ZW4tZGV2ZWw8YnIgLz48L2Jsb2NrcXVvdGU+
CjwvYm9keT4KPC9odG1sPg==
--=_NUWQF-8k01W10DsG1N5+EZa3ojZPE3HDoZ4sFFhq0eeh0y-I--



--===============7373466658977440381==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

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

--===============7373466658977440381==--



From xen-devel-bounces@lists.xensource.com Mon Nov 28 17:00:38 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Mon, 28 Nov 2011 17:00:38 +0000
Received: from localhost ([127.0.0.1] helo=lists.xen.org)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RV4ZF-0003hK-8W; Mon, 28 Nov 2011 17:00:33 +0000
Received: from mail182.messagelabs.com ([85.158.139.83])
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <Ian.Jackson@eu.citrix.com>) id 1RV4ZB-0003e7-EM
	for xen-devel@lists.xensource.com; Mon, 28 Nov 2011 17:00:30 +0000
X-Env-Sender: Ian.Jackson@eu.citrix.com
X-Msg-Ref: server-14.tower-182.messagelabs.com!1322499591!5005186!4
X-Originating-IP: [62.200.22.115]
X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: 
	VHJ1c3RlZCBJUDogNjIuMjAwLjIyLjExNSA9PiA5MDc3Nw==\n
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 29141 invoked from network); 28 Nov 2011 16:59:53 -0000
Received: from smtp.eu.citrix.com (HELO SMTP.EU.CITRIX.COM) (62.200.22.115)
	by server-14.tower-182.messagelabs.com with RC4-SHA encrypted SMTP;
	28 Nov 2011 16:59:53 -0000
X-IronPort-AV: E=Sophos;i="4.69,585,1315180800"; 
   d="scan'208";a="9169231"
Received: from lonpmailmx01.citrite.net ([10.30.203.162])
	by LONPIPO01.EU.CITRIX.COM with ESMTP/TLS/RC4-MD5;
	28 Nov 2011 16:59:51 +0000
Received: from norwich.cam.xci-test.com (10.80.248.129) by
	smtprelay.citrix.com (10.30.203.162) with Microsoft SMTP Server id
	8.3.213.0; Mon, 28 Nov 2011 16:59:51 +0000
Received: from mariner.cam.xci-test.com	([10.80.2.22]
	helo=mariner.uk.xensource.com ident=Debian-exim)	by
	norwich.cam.xci-test.com
	with esmtp (Exim 4.72)	(envelope-from <Ian.Jackson@eu.citrix.com>)	id
	1RV4YZ-00055a-Bv; Mon, 28 Nov 2011 16:59:51 +0000
Received: from iwj by mariner.uk.xensource.com with local (Exim 4.72)
	(envelope-from <Ian.Jackson@eu.citrix.com>)	id 1RV4YZ-0000cR-Aw;
	Mon, 28 Nov 2011 16:59:51 +0000
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: <xen-devel@lists.xensource.com>
Date: Mon, 28 Nov 2011 16:59:30 +0000
Message-ID: <1322499580-2322-4-git-send-email-ian.jackson@eu.citrix.com>
X-Mailer: git-send-email 1.7.2.5
In-Reply-To: <1322499580-2322-1-git-send-email-ian.jackson@eu.citrix.com>
References: <1322499580-2322-1-git-send-email-ian.jackson@eu.citrix.com>
MIME-Version: 1.0
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Subject: [Xen-devel] [PATCH 03/13] libxl: Provide a version of bsd's queue.h
	as _libxl_list.h
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.13
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/options/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com

We would like some linked list macros which are (a) well known to be
sane and (b) typesafe.  BSD's queue.h meets these criteria.

We also provide some simple perlery to arrange to add the libxl_
namespace prefix to the macros.  This will allow us to #include
_libxl_list.h in our public header file without clashing with anyone
else who is also using another version of queue.h.

(A note on copyright: The FreeBSD files we are adding have an
[L]GPL-compatible licence, so there is no need to change our COPYING.
Although FreeBSD's queue.3 still contains the advertising clause, this
has been withdrawn by UCB as recorded in the FreeBSD COPYRIGHT file,
which is included in tools/libxl/external/ for reference.)

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Ian Campbell <Ian.campbell@citrix.com>
Tested-by: Roger Pau Monne <roger.pau@entel.upc.edu>
---
 tools/libxl/Makefile                 |   10 +-
 tools/libxl/bsd-sys-queue-h-seddery  |   70 +++
 tools/libxl/external/README          |   14 +
 tools/libxl/external/bsd-COPYRIGHT   |  126 ++++
 tools/libxl/external/bsd-queue.3     | 1044 ++++++++++++++++++++++++++++++++++
 tools/libxl/external/bsd-sys-queue.h |  637 +++++++++++++++++++++
 6 files changed, 1898 insertions(+), 3 deletions(-)
 create mode 100755 tools/libxl/bsd-sys-queue-h-seddery
 create mode 100644 tools/libxl/external/README
 create mode 100644 tools/libxl/external/bsd-COPYRIGHT
 create mode 100644 tools/libxl/external/bsd-queue.3
 create mode 100644 tools/libxl/external/bsd-sys-queue.h

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index a7a4625..f363da2 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -42,7 +42,7 @@ LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore) $(CFLAGS_libblktapctl)
 
-AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h
+AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h _libxl_list.h
 AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c
 LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \
 	libxlu_disk_l.o libxlu_disk.o
@@ -55,7 +55,7 @@ $(XL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h
 $(XL_OBJS): CFLAGS += $(CFLAGS_libxenlight)
 
 testidl.o: CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenlight)
-testidl.c: libxl_types.idl gentest.py libxl.h
+testidl.c: libxl_types.idl gentest.py libxl.h $(AUTOINCS)
 	$(PYTHON) gentest.py libxl_types.idl testidl.c.new
 	mv testidl.c.new testidl.c
 
@@ -63,7 +63,7 @@ testidl.c: libxl_types.idl gentest.py libxl.h
 all: $(CLIENTS) libxenlight.so libxenlight.a libxlutil.so libxlutil.a \
 	$(AUTOSRCS) $(AUTOINCS)
 
-$(LIBXLU_OBJS): $(AUTOINCS)
+$(LIBXL_OBJS) $(LIBXLU_OBJS) $(XL_OBJS): $(AUTOINCS)
 
 %.c %.h: %.y
 	@rm -f $*.[ch]
@@ -81,6 +81,10 @@ _libxl_paths.h: genpath
 	rm -f $@.tmp
 	$(call move-if-changed,$@.2.tmp,$@)
 
+_libxl_list.h: bsd-sys-queue-h-seddery external/bsd-sys-queue.h
+	perl ./$^ --prefix=libxl >$@.new
+	$(call move-if-changed,$@.new,$@)
+
 libxl_paths.c: _libxl_paths.h
 
 libxl.h: _libxl_types.h
diff --git a/tools/libxl/bsd-sys-queue-h-seddery b/tools/libxl/bsd-sys-queue-h-seddery
new file mode 100755
index 0000000..c0aa079
--- /dev/null
+++ b/tools/libxl/bsd-sys-queue-h-seddery
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -p
+#
+# This script is part of the Xen build system.  It has a very
+# permissive licence to avoid complicating the licence of the
+# generated header file and to allow this seddery to be reused by
+# other projects.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this individual file (the "Software"), to deal
+# in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute,
+# sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# Copyright (C) 2011 Citrix Ltd
+
+our $namespace, $ucnamespace;
+
+BEGIN {
+    die unless @ARGV;
+    $namespace = pop @ARGV;
+    $namespace =~ s/^--prefix=// or die;
+    $ucnamespace = uc $namespace;
+
+    print <<END or die $!;
+/*
+ * DO NOT EDIT THIS FILE
+ *
+ * Generated automatically by bsd-sys-queue-h-seddery to
+ *  - introduce ${ucnamespace}_ and ${namespace}_ namespace prefixes
+ *  - turn "struct type" into "type" so that type arguments
+ *     to the macros are type names not struct tags
+ *  - remove the reference to sys/cdefs.h, which is not needed
+ *
+ * The purpose of this seddery is to allow the resulting file to be
+ * freely included by software which might also want to include other
+ * list macros; to make it usable when struct tags are not being used
+ * or not known; to make it more portable.
+ */
+END
+}
+
+s/\b( _SYS_QUEUE |
+      SLIST | LIST | STAILQ | TAILQ | QUEUE
+      )/${ucnamespace}_$1/xg;
+
+s/\b( TRACEBUF | TRASHIT |
+      QMD_
+      )/${ucnamespace}__$1/xg;
+
+s/\b(
+      qm_
+      )/${namespace}__$1/xg;
+
+s/\b struct \s+ type \b/type/xg;
+
+s,^\#include.*sys/cdefs.*,/* $& */,xg;
diff --git a/tools/libxl/external/README b/tools/libxl/external/README
new file mode 100644
index 0000000..8c8beea
--- /dev/null
+++ b/tools/libxl/external/README
@@ -0,0 +1,14 @@
+WARNING - DO NOT EDIT THINGS IN THIS DIRECTORY (apart from this README)
+-----------------------------------------------------------------------
+
+These files were obtained elsewhere and should only be updated by
+copying new versions from the source location, as documented below:
+
+bsd-COPYRIGHT
+bsd-sys-queue.h
+bsd-queue.3
+
+  Obtained from the FreeBSD SVN using the following commands:
+    svn co -r 221843 svn://svn.freebsd.org/base/head/sys/sys/
+    svn co -r 221843 svn://svn.freebsd.org/base/head/share/man/man3
+    svn cat -r 221843 http://svn.freebsd.org/base/head/COPYRIGHT >tools/libxl/external/bsd-COPYRIGHT
diff --git a/tools/libxl/external/bsd-COPYRIGHT b/tools/libxl/external/bsd-COPYRIGHT
new file mode 100644
index 0000000..6dc5d16
--- /dev/null
+++ b/tools/libxl/external/bsd-COPYRIGHT
@@ -0,0 +1,126 @@
+# $FreeBSD$
+#	@(#)COPYRIGHT	8.2 (Berkeley) 3/21/94
+
+The compilation of software known as FreeBSD is distributed under the
+following terms:
+
+Copyright (c) 1992-2011 The FreeBSD Project. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The 4.4BSD and 4.4BSD-Lite software is distributed under the following
+terms:
+
+All of the documentation and software included in the 4.4BSD and 4.4BSD-Lite
+Releases is copyrighted by The Regents of the University of California.
+
+Copyright 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
+	The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement:
+This product includes software developed by the University of
+California, Berkeley and its contributors.
+4. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+The Institute of Electrical and Electronics Engineers and the American
+National Standards Committee X3, on Information Processing Systems have
+given us permission to reprint portions of their documentation.
+
+In the following statement, the phrase ``this text'' refers to portions
+of the system documentation.
+
+Portions of this text are reprinted and reproduced in electronic form in
+the second BSD Networking Software Release, from IEEE Std 1003.1-1988, IEEE
+Standard Portable Operating System Interface for Computer Environments
+(POSIX), copyright C 1988 by the Institute of Electrical and Electronics
+Engineers, Inc.  In the event of any discrepancy between these versions
+and the original IEEE Standard, the original IEEE Standard is the referee
+document.
+
+In the following statement, the phrase ``This material'' refers to portions
+of the system documentation.
+
+This material is reproduced with permission from American National
+Standards Committee X3, on Information Processing Systems.  Computer and
+Business Equipment Manufacturers Association (CBEMA), 311 First St., NW,
+Suite 500, Washington, DC 20001-2178.  The developmental work of
+Programming Language C was completed by the X3J11 Technical Committee.
+
+The views and conclusions contained in the software and documentation are
+those of the authors and should not be interpreted as representing official
+policies, either expressed or implied, of the Regents of the University
+of California.
+
+
+NOTE: The copyright of UC Berkeley's Berkeley Software Distribution ("BSD")
+source has been updated.  The copyright addendum may be found at
+ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change and is
+included below.
+
+July 22, 1999
+
+To All Licensees, Distributors of Any Version of BSD:
+
+As you know, certain of the Berkeley Software Distribution ("BSD") source
+code files require that further distributions of products containing all or
+portions of the software, acknowledge within their advertising materials
+that such products contain software developed by UC Berkeley and its
+contributors.
+
+Specifically, the provision reads:
+
+"     * 3. All advertising materials mentioning features or use of this software
+      *    must display the following acknowledgement:
+      *    This product includes software developed by the University of
+      *    California, Berkeley and its contributors."
+
+Effective immediately, licensees and distributors are no longer required to
+include the acknowledgement within advertising materials.  Accordingly, the
+foregoing paragraph of those BSD Unix files containing it is hereby deleted
+in its entirety.
+
+William Hoskins
+Director, Office of Technology Licensing
+University of California, Berkeley
diff --git a/tools/libxl/external/bsd-queue.3 b/tools/libxl/external/bsd-queue.3
new file mode 100644
index 0000000..007ca5c
--- /dev/null
+++ b/tools/libxl/external/bsd-queue.3
@@ -0,0 +1,1044 @@
+.\" Copyright (c) 1993
+.\"	The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"	@(#)queue.3	8.2 (Berkeley) 1/24/94
+.\" $FreeBSD$
+.\"
+.Dd May 13, 2011
+.Dt QUEUE 3
+.Os
+.Sh NAME
+.Nm SLIST_EMPTY ,
+.Nm SLIST_ENTRY ,
+.Nm SLIST_FIRST ,
+.Nm SLIST_FOREACH ,
+.Nm SLIST_FOREACH_SAFE ,
+.Nm SLIST_HEAD ,
+.Nm SLIST_HEAD_INITIALIZER ,
+.Nm SLIST_INIT ,
+.Nm SLIST_INSERT_AFTER ,
+.Nm SLIST_INSERT_HEAD ,
+.Nm SLIST_NEXT ,
+.Nm SLIST_REMOVE_AFTER ,
+.Nm SLIST_REMOVE_HEAD ,
+.Nm SLIST_REMOVE ,
+.Nm SLIST_SWAP ,
+.Nm STAILQ_CONCAT ,
+.Nm STAILQ_EMPTY ,
+.Nm STAILQ_ENTRY ,
+.Nm STAILQ_FIRST ,
+.Nm STAILQ_FOREACH ,
+.Nm STAILQ_FOREACH_SAFE ,
+.Nm STAILQ_HEAD ,
+.Nm STAILQ_HEAD_INITIALIZER ,
+.Nm STAILQ_INIT ,
+.Nm STAILQ_INSERT_AFTER ,
+.Nm STAILQ_INSERT_HEAD ,
+.Nm STAILQ_INSERT_TAIL ,
+.Nm STAILQ_LAST ,
+.Nm STAILQ_NEXT ,
+.Nm STAILQ_REMOVE_AFTER ,
+.Nm STAILQ_REMOVE_HEAD ,
+.Nm STAILQ_REMOVE ,
+.Nm STAILQ_SWAP ,
+.Nm LIST_EMPTY ,
+.Nm LIST_ENTRY ,
+.Nm LIST_FIRST ,
+.Nm LIST_FOREACH ,
+.Nm LIST_FOREACH_SAFE ,
+.Nm LIST_HEAD ,
+.Nm LIST_HEAD_INITIALIZER ,
+.Nm LIST_INIT ,
+.Nm LIST_INSERT_AFTER ,
+.Nm LIST_INSERT_BEFORE ,
+.Nm LIST_INSERT_HEAD ,
+.Nm LIST_NEXT ,
+.Nm LIST_REMOVE ,
+.Nm LIST_SWAP ,
+.Nm TAILQ_CONCAT ,
+.Nm TAILQ_EMPTY ,
+.Nm TAILQ_ENTRY ,
+.Nm TAILQ_FIRST ,
+.Nm TAILQ_FOREACH ,
+.Nm TAILQ_FOREACH_SAFE ,
+.Nm TAILQ_FOREACH_REVERSE ,
+.Nm TAILQ_FOREACH_REVERSE_SAFE ,
+.Nm TAILQ_HEAD ,
+.Nm TAILQ_HEAD_INITIALIZER ,
+.Nm TAILQ_INIT ,
+.Nm TAILQ_INSERT_AFTER ,
+.Nm TAILQ_INSERT_BEFORE ,
+.Nm TAILQ_INSERT_HEAD ,
+.Nm TAILQ_INSERT_TAIL ,
+.Nm TAILQ_LAST ,
+.Nm TAILQ_NEXT ,
+.Nm TAILQ_PREV ,
+.Nm TAILQ_REMOVE ,
+.Nm TAILQ_SWAP
+.Nd implementations of singly-linked lists, singly-linked tail queues,
+lists and tail queues
+.Sh SYNOPSIS
+.In sys/queue.h
+.\"
+.Fn SLIST_EMPTY "SLIST_HEAD *head"
+.Fn SLIST_ENTRY "TYPE"
+.Fn SLIST_FIRST "SLIST_HEAD *head"
+.Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
+.Fn SLIST_HEAD "HEADNAME" "TYPE"
+.Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
+.Fn SLIST_INIT "SLIST_HEAD *head"
+.Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_REMOVE_AFTER "TYPE *elm" "SLIST_ENTRY NAME"
+.Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME"
+.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
+.Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "SLIST_ENTRY NAME"
+.\"
+.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2"
+.Fn STAILQ_EMPTY "STAILQ_HEAD *head"
+.Fn STAILQ_ENTRY "TYPE"
+.Fn STAILQ_FIRST "STAILQ_HEAD *head"
+.Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn STAILQ_HEAD "HEADNAME" "TYPE"
+.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
+.Fn STAILQ_INIT "STAILQ_HEAD *head"
+.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE" "STAILQ_ENTRY NAME"
+.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
+.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
+.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
+.Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "STAILQ_ENTRY NAME"
+.\"
+.Fn LIST_EMPTY "LIST_HEAD *head"
+.Fn LIST_ENTRY "TYPE"
+.Fn LIST_FIRST "LIST_HEAD *head"
+.Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
+.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
+.Fn LIST_HEAD "HEADNAME" "TYPE"
+.Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
+.Fn LIST_INIT "LIST_HEAD *head"
+.Fn LIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_INSERT_HEAD "LIST_HEAD *head" "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_NEXT "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
+.Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
+.\"
+.Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME"
+.Fn TAILQ_EMPTY "TAILQ_HEAD *head"
+.Fn TAILQ_ENTRY "TYPE"
+.Fn TAILQ_FIRST "TAILQ_HEAD *head"
+.Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
+.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
+.Fn TAILQ_HEAD "HEADNAME" "TYPE"
+.Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
+.Fn TAILQ_INIT "TAILQ_HEAD *head"
+.Fn TAILQ_INSERT_AFTER "TAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_BEFORE "TYPE *listelm" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_HEAD "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_INSERT_TAIL "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_LAST "TAILQ_HEAD *head" "HEADNAME"
+.Fn TAILQ_NEXT "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_PREV "TYPE *elm" "HEADNAME" "TAILQ_ENTRY NAME"
+.Fn TAILQ_REMOVE "TAILQ_HEAD *head" "TYPE *elm" "TAILQ_ENTRY NAME"
+.Fn TAILQ_SWAP "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TYPE" "TAILQ_ENTRY NAME"
+.\"
+.Sh DESCRIPTION
+These macros define and operate on four types of data structures:
+singly-linked lists, singly-linked tail queues, lists, and tail queues.
+All four structures support the following functionality:
+.Bl -enum -compact -offset indent
+.It
+Insertion of a new entry at the head of the list.
+.It
+Insertion of a new entry after any element in the list.
+.It
+O(1) removal of an entry from the head of the list.
+.It
+Forward traversal through the list.
+.It
+Swawpping the contents of two lists.
+.El
+.Pp
+Singly-linked lists are the simplest of the four data structures
+and support only the above functionality.
+Singly-linked lists are ideal for applications with large datasets
+and few or no removals,
+or for implementing a LIFO queue.
+Singly-linked lists add the following functionality:
+.Bl -enum -compact -offset indent
+.It
+O(n) removal of any entry in the list.
+.El
+.Pp
+Singly-linked tail queues add the following functionality:
+.Bl -enum -compact -offset indent
+.It
+Entries can be added at the end of a list.
+.It
+O(n) removal of any entry in the list.
+.It
+They may be concatenated.
+.El
+However:
+.Bl -enum -compact -offset indent
+.It
+All list insertions must specify the head of the list.
+.It
+Each head entry requires two pointers rather than one.
+.It
+Code size is about 15% greater and operations run about 20% slower
+than singly-linked lists.
+.El
+.Pp
+Singly-linked tailqs are ideal for applications with large datasets and
+few or no removals,
+or for implementing a FIFO queue.
+.Pp
+All doubly linked types of data structures (lists and tail queues)
+additionally allow:
+.Bl -enum -compact -offset indent
+.It
+Insertion of a new entry before any element in the list.
+.It
+O(1) removal of any entry in the list.
+.El
+However:
+.Bl -enum -compact -offset indent
+.It
+Each element requires two pointers rather than one.
+.It
+Code size and execution time of operations (except for removal) is about
+twice that of the singly-linked data-structures.
+.El
+.Pp
+Linked lists are the simplest of the doubly linked data structures and support
+only the above functionality over singly-linked lists.
+.Pp
+Tail queues add the following functionality:
+.Bl -enum -compact -offset indent
+.It
+Entries can be added at the end of a list.
+.It
+They may be traversed backwards, from tail to head.
+.It
+They may be concatenated.
+.El
+However:
+.Bl -enum -compact -offset indent
+.It
+All list insertions and removals must specify the head of the list.
+.It
+Each head entry requires two pointers rather than one.
+.It
+Code size is about 15% greater and operations run about 20% slower
+than singly-linked lists.
+.El
+.Pp
+In the macro definitions,
+.Fa TYPE
+is the name of a user defined structure,
+that must contain a field of type
+.Li SLIST_ENTRY ,
+.Li STAILQ_ENTRY ,
+.Li LIST_ENTRY ,
+or
+.Li TAILQ_ENTRY ,
+named
+.Fa NAME .
+The argument
+.Fa HEADNAME
+is the name of a user defined structure that must be declared
+using the macros
+.Li SLIST_HEAD ,
+.Li STAILQ_HEAD ,
+.Li LIST_HEAD ,
+or
+.Li TAILQ_HEAD .
+See the examples below for further explanation of how these
+macros are used.
+.Sh SINGLY-LINKED LISTS
+A singly-linked list is headed by a structure defined by the
+.Nm SLIST_HEAD
+macro.
+This structure contains a single pointer to the first element
+on the list.
+The elements are singly linked for minimum space and pointer manipulation
+overhead at the expense of O(n) removal for arbitrary elements.
+New elements can be added to the list after an existing element or
+at the head of the list.
+An
+.Fa SLIST_HEAD
+structure is declared as follows:
+.Bd -literal -offset indent
+SLIST_HEAD(HEADNAME, TYPE) head;
+.Ed
+.Pp
+where
+.Fa HEADNAME
+is the name of the structure to be defined, and
+.Fa TYPE
+is the type of the elements to be linked into the list.
+A pointer to the head of the list can later be declared as:
+.Bd -literal -offset indent
+struct HEADNAME *headp;
+.Ed
+.Pp
+(The names
+.Li head
+and
+.Li headp
+are user selectable.)
+.Pp
+The macro
+.Nm SLIST_HEAD_INITIALIZER
+evaluates to an initializer for the list
+.Fa head .
+.Pp
+The macro
+.Nm SLIST_EMPTY
+evaluates to true if there are no elements in the list.
+.Pp
+The macro
+.Nm SLIST_ENTRY
+declares a structure that connects the elements in
+the list.
+.Pp
+The macro
+.Nm SLIST_FIRST
+returns the first element in the list or NULL if the list is empty.
+.Pp
+The macro
+.Nm SLIST_FOREACH
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in
+turn to
+.Fa var .
+.Pp
+The macro
+.Nm SLIST_FOREACH_SAFE
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in
+turn to
+.Fa var .
+However, unlike
+.Fn SLIST_FOREACH
+here it is permitted to both remove
+.Fa var
+as well as free it from within the loop safely without interfering with the
+traversal.
+.Pp
+The macro
+.Nm SLIST_INIT
+initializes the list referenced by
+.Fa head .
+.Pp
+The macro
+.Nm SLIST_INSERT_HEAD
+inserts the new element
+.Fa elm
+at the head of the list.
+.Pp
+The macro
+.Nm SLIST_INSERT_AFTER
+inserts the new element
+.Fa elm
+after the element
+.Fa listelm .
+.Pp
+The macro
+.Nm SLIST_NEXT
+returns the next element in the list.
+.Pp
+The macro
+.Nm SLIST_REMOVE_AFTER
+removes the element after
+.Fa elm
+from the list. Unlike
+.Fa SLIST_REMOVE ,
+this macro does not traverse the entire list.
+.Pp
+The macro
+.Nm SLIST_REMOVE_HEAD
+removes the element
+.Fa elm
+from the head of the list.
+For optimum efficiency,
+elements being removed from the head of the list should explicitly use
+this macro instead of the generic
+.Fa SLIST_REMOVE
+macro.
+.Pp
+The macro
+.Nm SLIST_REMOVE
+removes the element
+.Fa elm
+from the list.
+.Pp
+The macro
+.Nm SLIST_SWAP
+swaps the contents of
+.Fa head1
+and
+.Fa head2 .
+.Sh SINGLY-LINKED LIST EXAMPLE
+.Bd -literal
+SLIST_HEAD(slisthead, entry) head =
+    SLIST_HEAD_INITIALIZER(head);
+struct slisthead *headp;		/* Singly-linked List head. */
+struct entry {
+	...
+	SLIST_ENTRY(entry) entries;	/* Singly-linked List. */
+	...
+} *n1, *n2, *n3, *np;
+
+SLIST_INIT(&head);			/* Initialize the list. */
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the head. */
+SLIST_INSERT_HEAD(&head, n1, entries);
+
+n2 = malloc(sizeof(struct entry));	/* Insert after. */
+SLIST_INSERT_AFTER(n1, n2, entries);
+
+SLIST_REMOVE(&head, n2, entry, entries);/* Deletion. */
+free(n2);
+
+n3 = SLIST_FIRST(&head);
+SLIST_REMOVE_HEAD(&head, entries);	/* Deletion from the head. */
+free(n3);
+					/* Forward traversal. */
+SLIST_FOREACH(np, &head, entries)
+	np-> ...
+					/* Safe forward traversal. */
+SLIST_FOREACH_SAFE(np, &head, entries, np_temp) {
+	np->do_stuff();
+	...
+	SLIST_REMOVE(&head, np, entry, entries);
+	free(np);
+}
+
+while (!SLIST_EMPTY(&head)) {		/* List Deletion. */
+	n1 = SLIST_FIRST(&head);
+	SLIST_REMOVE_HEAD(&head, entries);
+	free(n1);
+}
+.Ed
+.Sh SINGLY-LINKED TAIL QUEUES
+A singly-linked tail queue is headed by a structure defined by the
+.Nm STAILQ_HEAD
+macro.
+This structure contains a pair of pointers,
+one to the first element in the tail queue and the other to
+the last element in the tail queue.
+The elements are singly linked for minimum space and pointer
+manipulation overhead at the expense of O(n) removal for arbitrary
+elements.
+New elements can be added to the tail queue after an existing element,
+at the head of the tail queue, or at the end of the tail queue.
+A
+.Fa STAILQ_HEAD
+structure is declared as follows:
+.Bd -literal -offset indent
+STAILQ_HEAD(HEADNAME, TYPE) head;
+.Ed
+.Pp
+where
+.Li HEADNAME
+is the name of the structure to be defined, and
+.Li TYPE
+is the type of the elements to be linked into the tail queue.
+A pointer to the head of the tail queue can later be declared as:
+.Bd -literal -offset indent
+struct HEADNAME *headp;
+.Ed
+.Pp
+(The names
+.Li head
+and
+.Li headp
+are user selectable.)
+.Pp
+The macro
+.Nm STAILQ_HEAD_INITIALIZER
+evaluates to an initializer for the tail queue
+.Fa head .
+.Pp
+The macro
+.Nm STAILQ_CONCAT
+concatenates the tail queue headed by
+.Fa head2
+onto the end of the one headed by
+.Fa head1
+removing all entries from the former.
+.Pp
+The macro
+.Nm STAILQ_EMPTY
+evaluates to true if there are no items on the tail queue.
+.Pp
+The macro
+.Nm STAILQ_ENTRY
+declares a structure that connects the elements in
+the tail queue.
+.Pp
+The macro
+.Nm STAILQ_FIRST
+returns the first item on the tail queue or NULL if the tail queue
+is empty.
+.Pp
+The macro
+.Nm STAILQ_FOREACH
+traverses the tail queue referenced by
+.Fa head
+in the forward direction, assigning each element
+in turn to
+.Fa var .
+.Pp
+The macro
+.Nm STAILQ_FOREACH_SAFE
+traverses the tail queue referenced by
+.Fa head
+in the forward direction, assigning each element
+in turn to
+.Fa var .
+However, unlike
+.Fn STAILQ_FOREACH
+here it is permitted to both remove
+.Fa var
+as well as free it from within the loop safely without interfering with the
+traversal.
+.Pp
+The macro
+.Nm STAILQ_INIT
+initializes the tail queue referenced by
+.Fa head .
+.Pp
+The macro
+.Nm STAILQ_INSERT_HEAD
+inserts the new element
+.Fa elm
+at the head of the tail queue.
+.Pp
+The macro
+.Nm STAILQ_INSERT_TAIL
+inserts the new element
+.Fa elm
+at the end of the tail queue.
+.Pp
+The macro
+.Nm STAILQ_INSERT_AFTER
+inserts the new element
+.Fa elm
+after the element
+.Fa listelm .
+.Pp
+The macro
+.Nm STAILQ_LAST
+returns the last item on the tail queue.
+If the tail queue is empty the return value is
+.Dv NULL .
+.Pp
+The macro
+.Nm STAILQ_NEXT
+returns the next item on the tail queue, or NULL this item is the last.
+.Pp
+The macro
+.Nm STAILQ_REMOVE_AFTER
+removes the element after
+.Fa elm
+from the tail queue. Unlike
+.Fa STAILQ_REMOVE ,
+this macro does not traverse the entire tail queue.
+.Pp
+The macro
+.Nm STAILQ_REMOVE_HEAD
+removes the element at the head of the tail queue.
+For optimum efficiency,
+elements being removed from the head of the tail queue should
+use this macro explicitly rather than the generic
+.Fa STAILQ_REMOVE
+macro.
+.Pp
+The macro
+.Nm STAILQ_REMOVE
+removes the element
+.Fa elm
+from the tail queue.
+.Pp
+The macro
+.Nm STAILQ_SWAP
+swaps the contents of
+.Fa head1
+and
+.Fa head2 .
+.Sh SINGLY-LINKED TAIL QUEUE EXAMPLE
+.Bd -literal
+STAILQ_HEAD(stailhead, entry) head =
+    STAILQ_HEAD_INITIALIZER(head);
+struct stailhead *headp;		/* Singly-linked tail queue head. */
+struct entry {
+	...
+	STAILQ_ENTRY(entry) entries;	/* Tail queue. */
+	...
+} *n1, *n2, *n3, *np;
+
+STAILQ_INIT(&head);			/* Initialize the queue. */
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the head. */
+STAILQ_INSERT_HEAD(&head, n1, entries);
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the tail. */
+STAILQ_INSERT_TAIL(&head, n1, entries);
+
+n2 = malloc(sizeof(struct entry));	/* Insert after. */
+STAILQ_INSERT_AFTER(&head, n1, n2, entries);
+					/* Deletion. */
+STAILQ_REMOVE(&head, n2, entry, entries);
+free(n2);
+					/* Deletion from the head. */
+n3 = STAILQ_FIRST(&head);
+STAILQ_REMOVE_HEAD(&head, entries);
+free(n3);
+					/* Forward traversal. */
+STAILQ_FOREACH(np, &head, entries)
+	np-> ...
+					/* Safe forward traversal. */
+STAILQ_FOREACH_SAFE(np, &head, entries, np_temp) {
+	np->do_stuff();
+	...
+	STAILQ_REMOVE(&head, np, entry, entries);
+	free(np);
+}
+					/* TailQ Deletion. */
+while (!STAILQ_EMPTY(&head)) {
+	n1 = STAILQ_FIRST(&head);
+	STAILQ_REMOVE_HEAD(&head, entries);
+	free(n1);
+}
+					/* Faster TailQ Deletion. */
+n1 = STAILQ_FIRST(&head);
+while (n1 != NULL) {
+	n2 = STAILQ_NEXT(n1, entries);
+	free(n1);
+	n1 = n2;
+}
+STAILQ_INIT(&head);
+.Ed
+.Sh LISTS
+A list is headed by a structure defined by the
+.Nm LIST_HEAD
+macro.
+This structure contains a single pointer to the first element
+on the list.
+The elements are doubly linked so that an arbitrary element can be
+removed without traversing the list.
+New elements can be added to the list after an existing element,
+before an existing element, or at the head of the list.
+A
+.Fa LIST_HEAD
+structure is declared as follows:
+.Bd -literal -offset indent
+LIST_HEAD(HEADNAME, TYPE) head;
+.Ed
+.Pp
+where
+.Fa HEADNAME
+is the name of the structure to be defined, and
+.Fa TYPE
+is the type of the elements to be linked into the list.
+A pointer to the head of the list can later be declared as:
+.Bd -literal -offset indent
+struct HEADNAME *headp;
+.Ed
+.Pp
+(The names
+.Li head
+and
+.Li headp
+are user selectable.)
+.Pp
+The macro
+.Nm LIST_HEAD_INITIALIZER
+evaluates to an initializer for the list
+.Fa head .
+.Pp
+The macro
+.Nm LIST_EMPTY
+evaluates to true if there are no elements in the list.
+.Pp
+The macro
+.Nm LIST_ENTRY
+declares a structure that connects the elements in
+the list.
+.Pp
+The macro
+.Nm LIST_FIRST
+returns the first element in the list or NULL if the list
+is empty.
+.Pp
+The macro
+.Nm LIST_FOREACH
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in turn to
+.Fa var .
+.Pp
+The macro
+.Nm LIST_FOREACH_SAFE
+traverses the list referenced by
+.Fa head
+in the forward direction, assigning each element in turn to
+.Fa var .
+However, unlike
+.Fn LIST_FOREACH
+here it is permitted to both remove
+.Fa var
+as well as free it from within the loop safely without interfering with the
+traversal.
+.Pp
+The macro
+.Nm LIST_INIT
+initializes the list referenced by
+.Fa head .
+.Pp
+The macro
+.Nm LIST_INSERT_HEAD
+inserts the new element
+.Fa elm
+at the head of the list.
+.Pp
+The macro
+.Nm LIST_INSERT_AFTER
+inserts the new element
+.Fa elm
+after the element
+.Fa listelm .
+.Pp
+The macro
+.Nm LIST_INSERT_BEFORE
+inserts the new element
+.Fa elm
+before the element
+.Fa listelm .
+.Pp
+The macro
+.Nm LIST_NEXT
+returns the next element in the list, or NULL if this is the last.
+.Pp
+The macro
+.Nm LIST_REMOVE
+removes the element
+.Fa elm
+from the list.
+.Pp
+The macro
+.Nm LIST_SWAP
+swaps the contents of
+.Fa head1
+and
+.Fa head2 .
+.Sh LIST EXAMPLE
+.Bd -literal
+LIST_HEAD(listhead, entry) head =
+    LIST_HEAD_INITIALIZER(head);
+struct listhead *headp;			/* List head. */
+struct entry {
+	...
+	LIST_ENTRY(entry) entries;	/* List. */
+	...
+} *n1, *n2, *n3, *np, *np_temp;
+
+LIST_INIT(&head);			/* Initialize the list. */
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the head. */
+LIST_INSERT_HEAD(&head, n1, entries);
+
+n2 = malloc(sizeof(struct entry));	/* Insert after. */
+LIST_INSERT_AFTER(n1, n2, entries);
+
+n3 = malloc(sizeof(struct entry));	/* Insert before. */
+LIST_INSERT_BEFORE(n2, n3, entries);
+
+LIST_REMOVE(n2, entries);		/* Deletion. */
+free(n2);
+					/* Forward traversal. */
+LIST_FOREACH(np, &head, entries)
+	np-> ...
+
+					/* Safe forward traversal. */
+LIST_FOREACH_SAFE(np, &head, entries, np_temp) {
+	np->do_stuff();
+	...
+	LIST_REMOVE(np, entries);
+	free(np);
+}
+
+while (!LIST_EMPTY(&head)) {		/* List Deletion. */
+	n1 = LIST_FIRST(&head);
+	LIST_REMOVE(n1, entries);
+	free(n1);
+}
+
+n1 = LIST_FIRST(&head);			/* Faster List Deletion. */
+while (n1 != NULL) {
+	n2 = LIST_NEXT(n1, entries);
+	free(n1);
+	n1 = n2;
+}
+LIST_INIT(&head);
+.Ed
+.Sh TAIL QUEUES
+A tail queue is headed by a structure defined by the
+.Nm TAILQ_HEAD
+macro.
+This structure contains a pair of pointers,
+one to the first element in the tail queue and the other to
+the last element in the tail queue.
+The elements are doubly linked so that an arbitrary element can be
+removed without traversing the tail queue.
+New elements can be added to the tail queue after an existing element,
+before an existing element, at the head of the tail queue,
+or at the end of the tail queue.
+A
+.Fa TAILQ_HEAD
+structure is declared as follows:
+.Bd -literal -offset indent
+TAILQ_HEAD(HEADNAME, TYPE) head;
+.Ed
+.Pp
+where
+.Li HEADNAME
+is the name of the structure to be defined, and
+.Li TYPE
+is the type of the elements to be linked into the tail queue.
+A pointer to the head of the tail queue can later be declared as:
+.Bd -literal -offset indent
+struct HEADNAME *headp;
+.Ed
+.Pp
+(The names
+.Li head
+and
+.Li headp
+are user selectable.)
+.Pp
+The macro
+.Nm TAILQ_HEAD_INITIALIZER
+evaluates to an initializer for the tail queue
+.Fa head .
+.Pp
+The macro
+.Nm TAILQ_CONCAT
+concatenates the tail queue headed by
+.Fa head2
+onto the end of the one headed by
+.Fa head1
+removing all entries from the former.
+.Pp
+The macro
+.Nm TAILQ_EMPTY
+evaluates to true if there are no items on the tail queue.
+.Pp
+The macro
+.Nm TAILQ_ENTRY
+declares a structure that connects the elements in
+the tail queue.
+.Pp
+The macro
+.Nm TAILQ_FIRST
+returns the first item on the tail queue or NULL if the tail queue
+is empty.
+.Pp
+The macro
+.Nm TAILQ_FOREACH
+traverses the tail queue referenced by
+.Fa head
+in the forward direction, assigning each element in turn to
+.Fa var .
+.Fa var
+is set to
+.Dv NULL
+if the loop completes normally, or if there were no elements.
+.Pp
+The macro
+.Nm TAILQ_FOREACH_REVERSE
+traverses the tail queue referenced by
+.Fa head
+in the reverse direction, assigning each element in turn to
+.Fa var .
+.Pp
+The macros
+.Nm TAILQ_FOREACH_SAFE
+and
+.Nm TAILQ_FOREACH_REVERSE_SAFE
+traverse the list referenced by
+.Fa head
+in the forward or reverse direction respectively,
+assigning each element in turn to
+.Fa var .
+However, unlike their unsafe counterparts,
+.Nm TAILQ_FOREACH
+and
+.Nm TAILQ_FOREACH_REVERSE
+permit to both remove
+.Fa var
+as well as free it from within the loop safely without interfering with the
+traversal.
+.Pp
+The macro
+.Nm TAILQ_INIT
+initializes the tail queue referenced by
+.Fa head .
+.Pp
+The macro
+.Nm TAILQ_INSERT_HEAD
+inserts the new element
+.Fa elm
+at the head of the tail queue.
+.Pp
+The macro
+.Nm TAILQ_INSERT_TAIL
+inserts the new element
+.Fa elm
+at the end of the tail queue.
+.Pp
+The macro
+.Nm TAILQ_INSERT_AFTER
+inserts the new element
+.Fa elm
+after the element
+.Fa listelm .
+.Pp
+The macro
+.Nm TAILQ_INSERT_BEFORE
+inserts the new element
+.Fa elm
+before the element
+.Fa listelm .
+.Pp
+The macro
+.Nm TAILQ_LAST
+returns the last item on the tail queue.
+If the tail queue is empty the return value is
+.Dv NULL .
+.Pp
+The macro
+.Nm TAILQ_NEXT
+returns the next item on the tail queue, or NULL if this item is the last.
+.Pp
+The macro
+.Nm TAILQ_PREV
+returns the previous item on the tail queue, or NULL if this item
+is the first.
+.Pp
+The macro
+.Nm TAILQ_REMOVE
+removes the element
+.Fa elm
+from the tail queue.
+.Pp
+The macro
+.Nm TAILQ_SWAP
+swaps the contents of
+.Fa head1
+and
+.Fa head2 .
+.Sh TAIL QUEUE EXAMPLE
+.Bd -literal
+TAILQ_HEAD(tailhead, entry) head =
+    TAILQ_HEAD_INITIALIZER(head);
+struct tailhead *headp;			/* Tail queue head. */
+struct entry {
+	...
+	TAILQ_ENTRY(entry) entries;	/* Tail queue. */
+	...
+} *n1, *n2, *n3, *np;
+
+TAILQ_INIT(&head);			/* Initialize the queue. */
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the head. */
+TAILQ_INSERT_HEAD(&head, n1, entries);
+
+n1 = malloc(sizeof(struct entry));	/* Insert at the tail. */
+TAILQ_INSERT_TAIL(&head, n1, entries);
+
+n2 = malloc(sizeof(struct entry));	/* Insert after. */
+TAILQ_INSERT_AFTER(&head, n1, n2, entries);
+
+n3 = malloc(sizeof(struct entry));	/* Insert before. */
+TAILQ_INSERT_BEFORE(n2, n3, entries);
+
+TAILQ_REMOVE(&head, n2, entries);	/* Deletion. */
+free(n2);
+					/* Forward traversal. */
+TAILQ_FOREACH(np, &head, entries)
+	np-> ...
+					/* Safe forward traversal. */
+TAILQ_FOREACH_SAFE(np, &head, entries, np_temp) {
+	np->do_stuff();
+	...
+	TAILQ_REMOVE(&head, np, entries);
+	free(np);
+}
+					/* Reverse traversal. */
+TAILQ_FOREACH_REVERSE(np, &head, tailhead, entries)
+	np-> ...
+					/* TailQ Deletion. */
+while (!TAILQ_EMPTY(&head)) {
+	n1 = TAILQ_FIRST(&head);
+	TAILQ_REMOVE(&head, n1, entries);
+	free(n1);
+}
+					/* Faster TailQ Deletion. */
+n1 = TAILQ_FIRST(&head);
+while (n1 != NULL) {
+	n2 = TAILQ_NEXT(n1, entries);
+	free(n1);
+	n1 = n2;
+}
+TAILQ_INIT(&head);
+.Ed
+.Sh SEE ALSO
+.Xr tree 3
+.Sh HISTORY
+The
+.Nm queue
+functions first appeared in
+.Bx 4.4 .
diff --git a/tools/libxl/external/bsd-sys-queue.h b/tools/libxl/external/bsd-sys-queue.h
new file mode 100644
index 0000000..274e636
--- /dev/null
+++ b/tools/libxl/external/bsd-sys-queue.h
@@ -0,0 +1,637 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *				SLIST	LIST	STAILQ	TAILQ
+ * _HEAD			+	+	+	+
+ * _HEAD_INITIALIZER		+	+	+	+
+ * _ENTRY			+	+	+	+
+ * _INIT			+	+	+	+
+ * _EMPTY			+	+	+	+
+ * _FIRST			+	+	+	+
+ * _NEXT			+	+	+	+
+ * _PREV			-	-	-	+
+ * _LAST			-	-	+	+
+ * _FOREACH			+	+	+	+
+ * _FOREACH_SAFE		+	+	+	+
+ * _FOREACH_REVERSE		-	-	-	+
+ * _FOREACH_REVERSE_SAFE	-	-	-	+
+ * _INSERT_HEAD			+	+	+	+
+ * _INSERT_BEFORE		-	+	-	+
+ * _INSERT_AFTER		+	+	+	+
+ * _INSERT_TAIL			-	-	+	+
+ * _CONCAT			-	-	+	+
+ * _REMOVE_AFTER		+	-	+	-
+ * _REMOVE_HEAD			+	-	+	-
+ * _REMOVE			+	+	+	+
+ * _SWAP			+	+	+	+
+ *
+ */
+#ifdef QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+	char * lastfile;
+	int lastline;
+	char * prevfile;
+	int prevline;
+};
+
+#define	TRACEBUF	struct qm_trace trace;
+#define	TRASHIT(x)	do {(x) = (void *)-1;} while (0)
+#define	QMD_SAVELINK(name, link)	void **name = (void *)&(link)
+
+#define	QMD_TRACE_HEAD(head) do {					\
+	(head)->trace.prevline = (head)->trace.lastline;		\
+	(head)->trace.prevfile = (head)->trace.lastfile;		\
+	(head)->trace.lastline = __LINE__;				\
+	(head)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#define	QMD_TRACE_ELEM(elem) do {					\
+	(elem)->trace.prevline = (elem)->trace.lastline;		\
+	(elem)->trace.prevfile = (elem)->trace.lastfile;		\
+	(elem)->trace.lastline = __LINE__;				\
+	(elem)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#else
+#define	QMD_TRACE_ELEM(elem)
+#define	QMD_TRACE_HEAD(head)
+#define	QMD_SAVELINK(name, link)
+#define	TRACEBUF
+#define	TRASHIT(x)
+#endif	/* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var) && ((tvar) = SLIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
+	for ((varp) = &SLIST_FIRST((head));				\
+	    ((var) = *(varp)) != NULL;					\
+	    (varp) = &SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	QMD_SAVELINK(oldnext, (elm)->field.sle_next);			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_REMOVE_AFTER(curelm, field);			\
+	}								\
+	TRASHIT(*oldnext);						\
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do {				\
+	SLIST_NEXT(elm, field) =					\
+	    SLIST_NEXT(SLIST_NEXT(elm, field), field);			\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+#define SLIST_SWAP(head1, head2, type) do {				\
+	struct type *swap_first = SLIST_FIRST(head1);			\
+	SLIST_FIRST(head1) = SLIST_FIRST(head2);			\
+	SLIST_FIRST(head2) = swap_first;				\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_CONCAT(head1, head2) do {				\
+	if (!STAILQ_EMPTY((head2))) {					\
+		*(head1)->stqh_last = (head2)->stqh_first;		\
+		(head1)->stqh_last = (head2)->stqh_last;		\
+		STAILQ_INIT((head2));					\
+	}								\
+} while (0)
+
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+
+#define	STAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = STAILQ_FIRST((head));				\
+	    (var) && ((tvar) = STAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	*(head)->stqh_last = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head, type, field)					\
+	(STAILQ_EMPTY((head)) ?						\
+		NULL :							\
+	        ((struct type *)(void *)				\
+		((char *)((head)->stqh_last) - __offsetof(struct type, field))))
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	QMD_SAVELINK(oldnext, (elm)->field.stqe_next);			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		STAILQ_REMOVE_AFTER(head, curelm, field);		\
+	}								\
+	TRASHIT(*oldnext);						\
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do {			\
+	if ((STAILQ_NEXT(elm, field) =					\
+	     STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define STAILQ_SWAP(head1, head2, type) do {				\
+	struct type *swap_first = STAILQ_FIRST(head1);			\
+	struct type **swap_last = (head1)->stqh_last;			\
+	STAILQ_FIRST(head1) = STAILQ_FIRST(head2);			\
+	(head1)->stqh_last = (head2)->stqh_last;			\
+	STAILQ_FIRST(head2) = swap_first;				\
+	(head2)->stqh_last = swap_last;					\
+	if (STAILQ_EMPTY(head1))					\
+		(head1)->stqh_last = &STAILQ_FIRST(head1);		\
+	if (STAILQ_EMPTY(head2))					\
+		(head2)->stqh_last = &STAILQ_FIRST(head2);		\
+} while (0)
+
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define	QMD_LIST_CHECK_HEAD(head, field) do {				\
+	if (LIST_FIRST((head)) != NULL &&				\
+	    LIST_FIRST((head))->field.le_prev !=			\
+	     &LIST_FIRST((head)))					\
+		panic("Bad list head %p first->prev != head", (head));	\
+} while (0)
+
+#define	QMD_LIST_CHECK_NEXT(elm, field) do {				\
+	if (LIST_NEXT((elm), field) != NULL &&				\
+	    LIST_NEXT((elm), field)->field.le_prev !=			\
+	     &((elm)->field.le_next))					\
+	     	panic("Bad link elm %p next->prev != elm", (elm));	\
+} while (0)
+
+#define	QMD_LIST_CHECK_PREV(elm, field) do {				\
+	if (*(elm)->field.le_prev != (elm))				\
+		panic("Bad link elm %p prev->next != elm", (elm));	\
+} while (0)
+#else
+#define	QMD_LIST_CHECK_HEAD(head, field)
+#define	QMD_LIST_CHECK_NEXT(elm, field)
+#define	QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = LIST_FIRST((head));				\
+	    (var) && ((tvar) = LIST_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	QMD_LIST_CHECK_NEXT(listelm, field);				\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	QMD_LIST_CHECK_PREV(listelm, field);				\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	QMD_LIST_CHECK_HEAD((head), field);				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	QMD_SAVELINK(oldnext, (elm)->field.le_next);			\
+	QMD_SAVELINK(oldprev, (elm)->field.le_prev);			\
+	QMD_LIST_CHECK_NEXT(elm, field);				\
+	QMD_LIST_CHECK_PREV(elm, field);				\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+	TRASHIT(*oldnext);						\
+	TRASHIT(*oldprev);						\
+} while (0)
+
+#define LIST_SWAP(head1, head2, type, field) do {			\
+	struct type *swap_tmp = LIST_FIRST((head1));			\
+	LIST_FIRST((head1)) = LIST_FIRST((head2));			\
+	LIST_FIRST((head2)) = swap_tmp;					\
+	if ((swap_tmp = LIST_FIRST((head1))) != NULL)			\
+		swap_tmp->field.le_prev = &LIST_FIRST((head1));		\
+	if ((swap_tmp = LIST_FIRST((head2))) != NULL)			\
+		swap_tmp->field.le_prev = &LIST_FIRST((head2));		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+	TRACEBUF							\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+	TRACEBUF							\
+}
+
+/*
+ * Tail queue functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define	QMD_TAILQ_CHECK_HEAD(head, field) do {				\
+	if (!TAILQ_EMPTY(head) &&					\
+	    TAILQ_FIRST((head))->field.tqe_prev !=			\
+	     &TAILQ_FIRST((head)))					\
+		panic("Bad tailq head %p first->prev != head", (head));	\
+} while (0)
+
+#define	QMD_TAILQ_CHECK_TAIL(head, field) do {				\
+	if (*(head)->tqh_last != NULL)					\
+	    	panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); 	\
+} while (0)
+
+#define	QMD_TAILQ_CHECK_NEXT(elm, field) do {				\
+	if (TAILQ_NEXT((elm), field) != NULL &&				\
+	    TAILQ_NEXT((elm), field)->field.tqe_prev !=			\
+	     &((elm)->field.tqe_next))					\
+		panic("Bad link elm %p next->prev != elm", (elm));	\
+} while (0)
+
+#define	QMD_TAILQ_CHECK_PREV(elm, field) do {				\
+	if (*(elm)->field.tqe_prev != (elm))				\
+		panic("Bad link elm %p prev->next != elm", (elm));	\
+} while (0)
+#else
+#define	QMD_TAILQ_CHECK_HEAD(head, field)
+#define	QMD_TAILQ_CHECK_TAIL(head, headname)
+#define	QMD_TAILQ_CHECK_NEXT(elm, field)
+#define	QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define	TAILQ_CONCAT(head1, head2, field) do {				\
+	if (!TAILQ_EMPTY(head2)) {					\
+		*(head1)->tqh_last = (head2)->tqh_first;		\
+		(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;	\
+		(head1)->tqh_last = (head2)->tqh_last;			\
+		TAILQ_INIT((head2));					\
+		QMD_TRACE_HEAD(head1);					\
+		QMD_TRACE_HEAD(head2);					\
+	}								\
+} while (0)
+
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var) && ((tvar) = TAILQ_NEXT((var), field), 1);		\
+	    (var) = (tvar))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);	\
+	    (var) = (tvar))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	QMD_TAILQ_CHECK_NEXT(listelm, field);				\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else {								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	QMD_TAILQ_CHECK_PREV(listelm, field);				\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+	QMD_TRACE_ELEM(&listelm->field);				\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	QMD_TAILQ_CHECK_HEAD(head, field);				\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	QMD_TAILQ_CHECK_TAIL(head, field);				\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+	QMD_TRACE_HEAD(head);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	QMD_SAVELINK(oldnext, (elm)->field.tqe_next);			\
+	QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);			\
+	QMD_TAILQ_CHECK_NEXT(elm, field);				\
+	QMD_TAILQ_CHECK_PREV(elm, field);				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else {								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+		QMD_TRACE_HEAD(head);					\
+	}								\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+	TRASHIT(*oldnext);						\
+	TRASHIT(*oldprev);						\
+	QMD_TRACE_ELEM(&(elm)->field);					\
+} while (0)
+
+#define TAILQ_SWAP(head1, head2, type, field) do {			\
+	struct type *swap_first = (head1)->tqh_first;			\
+	struct type **swap_last = (head1)->tqh_last;			\
+	(head1)->tqh_first = (head2)->tqh_first;			\
+	(head1)->tqh_last = (head2)->tqh_last;				\
+	(head2)->tqh_first = swap_first;				\
+	(head2)->tqh_last = swap_last;					\
+	if ((swap_first = (head1)->tqh_first) != NULL)			\
+		swap_first->field.tqe_prev = &(head1)->tqh_first;	\
+	else								\
+		(head1)->tqh_last = &(head1)->tqh_first;		\
+	if ((swap_first = (head2)->tqh_first) != NULL)			\
+		swap_first->field.tqe_prev = &(head2)->tqh_first;	\
+	else								\
+		(head2)->tqh_last = &(head2)->tqh_first;		\
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
-- 
1.7.2.5


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

From xen-devel-bounces@lists.xensource.com Wed Nov 30 16:26:30 2011
Return-path: <xen-devel-bounces@lists.xensource.com>
Envelope-to: archives@lists.xen.org
Delivery-date: Wed, 30 Nov 2011 16:26:30 +0000
Received: from localhost ([127.0.0.1] helo=lists.xen.org)
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <xen-devel-bounces@lists.xensource.com>)
	id 1RVmz4-00059Q-Ln; Wed, 30 Nov 2011 16:26:10 +0000
Received: from mail27.messagelabs.com ([193.109.254.147])
	by lists.xen.org with esmtp (Exim 4.72)
	(envelope-from <konrad.wilk@oracle.com>) id 1RVmz3-000595-81
	for xen-devel@lists.xensource.com; Wed, 30 Nov 2011 16:26:09 +0000
X-Env-Sender: konrad.wilk@oracle.com
X-Msg-Ref: server-15.tower-27.messagelabs.com!1322670313!57168728!1
X-Originating-IP: [141.146.126.227]
X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: 
	VHJ1c3RlZCBJUDogMTQxLjE0Ni4xMjYuMjI3ID0+IDQxNjMxNw==\n
X-StarScan-Version: 6.4.1; banners=-,-,-
X-VirusChecked: Checked
Received: (qmail 16897 invoked from network); 30 Nov 2011 16:25:14 -0000
Received: from acsinet15.oracle.com (HELO acsinet15.oracle.com)
	(141.146.126.227)
	by server-15.tower-27.messagelabs.com with DHE-RSA-AES256-SHA encrypted
	SMTP; 30 Nov 2011 16:25:14 -0000
Received: from ucsinet22.oracle.com (ucsinet22.oracle.com [156.151.31.94])
	by acsinet15.oracle.com (Switch-3.4.4/Switch-3.4.4) with ESMTP id
	pAUGPD4D017520
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK);
	Wed, 30 Nov 2011 16:25:14 GMT
Received: from acsmt357.oracle.com (acsmt357.oracle.com [141.146.40.157])
	by ucsinet22.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id
	pAUGPAaH020925
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO);
	Wed, 30 Nov 2011 16:25:10 GMT
Received: from abhmt104.oracle.com (abhmt104.oracle.com [141.146.116.56])
	by acsmt357.oracle.com (8.12.11.20060308/8.12.11) with ESMTP id
	pAUGP3Jc005526; Wed, 30 Nov 2011 10:25:03 -0600
Received: from phenom.dumpdata.com (/209.6.85.33)
	by default (Oracle Beehive Gateway v4.0)
	with ESMTP ; Wed, 30 Nov 2011 08:25:02 -0800
Received: from phenom.dumpdata.com (localhost.localdomain [127.0.0.1])
	by phenom.dumpdata.com (Postfix) with ESMTP id 5882141C2D;
	Wed, 30 Nov 2011 11:24:33 -0500 (EST)
Received: (from konrad@localhost)
	by phenom.dumpdata.com (8.14.5/8.14.5/Submit) id pAUGNWfw010876;
	Wed, 30 Nov 2011 11:23:32 -0500
Date: Wed, 30 Nov 2011 11:23:32 -0500
From: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
To: Pasi =?iso-8859-1?Q?K=E4rkk=E4inen?= <pasik@iki.fi>
Message-ID: <20111130162332.GA10832@phenom.dumpdata.com>
References: <20110106223121.GT2754@reaktio.net>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="3MwIy2ne0vdjdPXF"
Content-Disposition: inline
In-Reply-To: <20110106223121.GT2754@reaktio.net>
User-Agent: Mutt/1.5.21 (2010-09-15)
Content-Transfer-Encoding: 7bit
X-Source-IP: ucsinet22.oracle.com [156.151.31.94]
X-CT-RefId: str=0001.0A090205.4ED658EC.0079,ss=1,re=-6.500,fgs=0
Cc: Jeremy Fitzhardinge <jeremy@goop.org>, xen-devel@lists.xensource.com,
	Ian Campbell <Ian.Campbell@citrix.com>
Subject: Re: [Xen-devel] [RFC PATCH v01] Xen PVSCSI drivers for pvops
 xen/stable-2.6.32.x kernel
X-BeenThere: xen-devel@lists.xensource.com
X-Mailman-Version: 2.1.13
Precedence: list
List-Id: Xen developer discussion <xen-devel.lists.xensource.com>
List-Unsubscribe: <http://lists.xensource.com/mailman/options/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
List-Post: <mailto:xen-devel@lists.xensource.com>
List-Help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-Subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>,
	<mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
Sender: xen-devel-bounces@lists.xensource.com
Errors-To: xen-devel-bounces@lists.xensource.com


--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Jan 07, 2011 at 12:31:21AM +0200, Pasi K=E4rkk=E4inen wrote:
> Hello,
>=20
> http://pasik.reaktio.net/xen/patches/xen-pvscsi-drivers-linux-2.6.32.27=
-pvops-v01.diff
>=20
> This is the first version of Xen PVSCSI drivers, both the scsiback back=
end and
> scsifront frontend, ported from Novell SLES11SP1 2.6.32 Xenlinux kernel=
 to=20
> pvops xen/stable-2.6.32.x branch.
>=20
> At the moment it's *only* compile-tested with the latest xen/stable-2.6=
.32.x=20
> git kernel as of today (2.6.32.27), on Fedora 14 x86_64.
>=20
> Comments welcome.
>=20
> I'm sure there are still things to fix in it.=20
> Hopefully I managed to properly fix all the differences between Xenlinu=
x <-> pvops..
> Let me know how it goes, if you feel adventurous enough to try it :)

I took a look at the patches and rebased them on top of v3.0 some time ag=
o.

Had to fix up some things, but not much (most of the P2M API calls, and s=
ome of the
grant table modifications) and stuck the patches in:

git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen.git devel/xen-sc=
si.v1.0

Attached is also the full patch against v3.0 kernel. I found that it work=
s
with my SCSI disks, but you need to use Xen 4.1 (and xm). Earlier version=
s
do something weird. I am not really sure who is using it=20

Ah, I also put the 2Tb fix in it.

 drivers/scsi/Kconfig                   |   16 +
 drivers/scsi/Makefile                  |    2 +
 drivers/scsi/xen-scsiback/Makefile     |    4 +
 drivers/scsi/xen-scsiback/common.h     |  187 ++++++++
 drivers/scsi/xen-scsiback/emulate.c    |  478 ++++++++++++++++++++
 drivers/scsi/xen-scsiback/interface.c  |  141 ++++++
 drivers/scsi/xen-scsiback/scsiback.c   |  757 ++++++++++++++++++++++++++=
++++++
 drivers/scsi/xen-scsiback/translate.c  |  168 +++++++
 drivers/scsi/xen-scsiback/xenbus.c     |  374 ++++++++++++++++
 drivers/scsi/xen-scsifront/Makefile    |    4 +
 drivers/scsi/xen-scsifront/common.h    |  137 ++++++
 drivers/scsi/xen-scsifront/scsifront.c |  469 ++++++++++++++++++++
 drivers/scsi/xen-scsifront/xenbus.c    |  414 +++++++++++++++++
 include/xen/interface/grant_table.h    |    4 +
 include/xen/interface/io/vscsiif.h     |  105 +++++
 15 files changed, 3260 insertions(+), 0 deletions(-)

--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pv-scsi-against.v3.0.patch"

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8d9dae8..380e4f05 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1909,6 +1909,22 @@ config SCSI_BFA_FC
 	  To compile this driver as a module, choose M here. The module will
 	  be called bfa.
 
+config XEN_SCSI_FRONTEND
+        tristate "Xen PVSCSI frontend driver"
+        depends on XEN && SCSI
+        default m
+        help
+          The SCSI frontend driver allows the kernel to access SCSI Devices
+          within another guest OS.
+
+config XEN_SCSI_BACKEND
+        tristate "Xen PVSCSI backend driver"
+        depends on XEN_BACKEND && SCSI
+        default m
+        help
+          The PVSCSI backend driver allows the kernel to export its SCSI Devices
+          to other Xen guests via a high-performance shared-memory interface.
+
 endif # SCSI_LOWLEVEL
 
 source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 3c08f53..7b6f4d2 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -140,6 +140,8 @@ obj-$(CONFIG_SCSI_CXGB4_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgbi/
 obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/
 obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/
 obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o
+obj-$(CONFIG_XEN_SCSI_FRONTEND)	+= xen-scsifront/
+obj-$(CONFIG_XEN_SCSI_BACKEND)	+= xen-scsiback/
 obj-$(CONFIG_VMWARE_PVSCSI)	+= vmw_pvscsi.o
 
 obj-$(CONFIG_ARM)		+= arm/
diff --git a/drivers/scsi/xen-scsiback/Makefile b/drivers/scsi/xen-scsiback/Makefile
new file mode 100644
index 0000000..94926dc
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_XEN_SCSI_BACKEND) := xen-scsiback.o
+
+xen-scsiback-y	:= interface.o scsiback.o xenbus.o translate.o emulate.o
+
diff --git a/drivers/scsi/xen-scsiback/common.h b/drivers/scsi/xen-scsiback/common.h
new file mode 100644
index 0000000..dafa79e
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/common.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __SCSIIF__BACKEND__COMMON_H__
+#define __SCSIIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/xen.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/vscsiif.h>
+
+
+#define DPRINTK(_f, _a...)			\
+	pr_debug("(file=%s, line=%d) " _f,	\
+		 __FILE__ , __LINE__ , ## _a )
+
+struct ids_tuple {
+	unsigned int hst;		/* host    */
+	unsigned int chn;		/* channel */
+	unsigned int tgt;		/* target  */
+	unsigned int lun;		/* LUN     */
+};
+
+struct v2p_entry {
+	struct ids_tuple v;		/* translate from */
+	struct scsi_device *sdev;	/* translate to   */
+	struct list_head l;
+};
+
+struct vscsibk_info {
+	struct xenbus_device *dev;
+
+	domid_t domid;
+	unsigned int evtchn;
+	unsigned int irq;
+
+	int feature;
+
+	struct vscsiif_back_ring  ring;
+	void  *ring_area;
+
+	spinlock_t ring_lock;
+	atomic_t nr_unreplied_reqs;
+
+	spinlock_t v2p_lock;
+	struct list_head v2p_entry_lists;
+
+	struct task_struct *kthread;
+	wait_queue_head_t waiting_to_free;
+	wait_queue_head_t wq;
+	unsigned int waiting_reqs;
+	struct page **mmap_pages;
+
+};
+
+typedef struct {
+	unsigned char act;
+	struct vscsibk_info *info;
+	struct scsi_device *sdev;
+
+	uint16_t rqid;
+
+	uint16_t v_chn, v_tgt;
+
+	uint8_t nr_segments;
+	uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE];
+	uint8_t cmd_len;
+
+	uint8_t sc_data_direction;
+	uint16_t timeout_per_command;
+
+	uint32_t request_bufflen;
+	struct scatterlist *sgl;
+	grant_ref_t gref[VSCSIIF_SG_TABLESIZE];
+
+	int32_t rslt;
+	uint32_t resid;
+	uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
+
+	struct list_head free_list;
+} pending_req_t;
+
+
+
+#define scsiback_get(_b) (atomic_inc(&(_b)->nr_unreplied_reqs))
+#define scsiback_put(_b)				\
+	do {						\
+		if (atomic_dec_and_test(&(_b)->nr_unreplied_reqs))	\
+			wake_up(&(_b)->waiting_to_free);\
+	} while (0)
+
+#define VSCSIIF_TIMEOUT		(900*HZ)
+
+#define VSCSI_TYPE_HOST		1
+
+irqreturn_t scsiback_intr(int, void *);
+int scsiback_init_sring(struct vscsibk_info *info,
+		unsigned long ring_ref, unsigned int evtchn);
+int scsiback_schedule(void *data);
+
+
+struct vscsibk_info *vscsibk_info_alloc(domid_t domid);
+void scsiback_free(struct vscsibk_info *info);
+void scsiback_disconnect(struct vscsibk_info *info);
+int __init scsiback_interface_init(void);
+void scsiback_interface_exit(void);
+int scsiback_xenbus_init(void);
+void scsiback_xenbus_unregister(void);
+
+void scsiback_init_translation_table(struct vscsibk_info *info);
+
+int scsiback_add_translation_entry(struct vscsibk_info *info,
+			struct scsi_device *sdev, struct ids_tuple *v);
+
+int scsiback_del_translation_entry(struct vscsibk_info *info,
+				struct ids_tuple *v);
+struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
+			struct ids_tuple *v);
+void scsiback_release_translation_entry(struct vscsibk_info *info);
+
+
+void scsiback_cmd_exec(pending_req_t *pending_req);
+void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
+			uint32_t resid, pending_req_t *pending_req);
+void scsiback_fast_flush_area(pending_req_t *req);
+
+void scsiback_rsp_emulation(pending_req_t *pending_req);
+void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req);
+void scsiback_emulation_init(void);
+
+
+#endif /* __SCSIIF__BACKEND__COMMON_H__ */
diff --git a/drivers/scsi/xen-scsiback/emulate.c b/drivers/scsi/xen-scsiback/emulate.c
new file mode 100644
index 0000000..c5b0999
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/emulate.c
@@ -0,0 +1,478 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+* Patched to support >2TB drives + allow tape & autoloader operations
+* 2010, Samuel Kvasnica, IMS Nanofabrication AG
+*/
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include "common.h"
+
+/* Following SCSI commands are not defined in scsi/scsi.h */
+#define EXTENDED_COPY		0x83	/* EXTENDED COPY command        */
+#define REPORT_ALIASES		0xa3	/* REPORT ALIASES command       */
+#define CHANGE_ALIASES		0xa4	/* CHANGE ALIASES command       */
+#define SET_PRIORITY		0xa4	/* SET PRIORITY command         */
+
+
+/*
+  The bitmap in order to control emulation.
+  (Bit 3 to 7 are reserved for future use.)
+*/
+#define VSCSIIF_NEED_CMD_EXEC		0x01	/* If this bit is set, cmd exec	*/
+						/* is required.			*/
+#define VSCSIIF_NEED_EMULATE_REQBUF	0x02	/* If this bit is set, need	*/
+						/* emulation reqest buff before	*/
+						/* cmd exec.			*/
+#define VSCSIIF_NEED_EMULATE_RSPBUF	0x04	/* If this bit is set, need	*/
+						/* emulation resp buff after	*/
+						/* cmd exec.			*/
+
+/* Additional Sense Code (ASC) used */
+#define NO_ADDITIONAL_SENSE		0x0
+#define LOGICAL_UNIT_NOT_READY		0x4
+#define UNRECOVERED_READ_ERR		0x11
+#define PARAMETER_LIST_LENGTH_ERR	0x1a
+#define INVALID_OPCODE			0x20
+#define ADDR_OUT_OF_RANGE		0x21
+#define INVALID_FIELD_IN_CDB		0x24
+#define INVALID_FIELD_IN_PARAM_LIST	0x26
+#define POWERON_RESET			0x29
+#define SAVING_PARAMS_UNSUP		0x39
+#define THRESHOLD_EXCEEDED		0x5d
+#define LOW_POWER_COND_ON		0x5e
+
+
+
+/* Number os SCSI op_code	*/
+#define VSCSI_MAX_SCSI_OP_CODE		256
+static unsigned char bitmap[VSCSI_MAX_SCSI_OP_CODE];
+
+#define NO_EMULATE(cmd) \
+	bitmap[cmd] = VSCSIIF_NEED_CMD_EXEC; \
+	pre_function[cmd] = NULL; \
+	post_function[cmd] = NULL
+
+
+
+/*
+  Emulation routines for each SCSI op_code.
+*/
+static void (*pre_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
+static void (*post_function[VSCSI_MAX_SCSI_OP_CODE])(pending_req_t *, void *);
+
+
+static const int check_condition_result =
+		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+static void scsiback_mk_sense_buffer(uint8_t *data, uint8_t key,
+			uint8_t asc, uint8_t asq)
+{
+	data[0] = 0x70;  /* fixed, current */
+	data[2] = key;
+	data[7] = 0xa;	  /* implies 18 byte sense buffer */
+	data[12] = asc;
+	data[13] = asq;
+}
+
+static void resp_not_supported_cmd(pending_req_t *pending_req, void *data)
+{
+	scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
+		INVALID_OPCODE, 0);
+	pending_req->resid = 0;
+	pending_req->rslt  = check_condition_result;
+}
+
+
+static int __copy_to_sg(struct scatterlist *sgl, unsigned int nr_sg,
+	       void *buf, unsigned int buflen)
+{
+	struct scatterlist *sg;
+	void *from = buf;
+	void *to;
+	unsigned int from_rest = buflen;
+	unsigned int to_capa;
+	unsigned int copy_size = 0;
+	unsigned int i;
+	unsigned long pfn;
+
+	for_each_sg (sgl, sg, nr_sg, i) {
+		if (sg_page(sg) == NULL) {
+			printk(KERN_WARNING "%s: inconsistent length field in "
+			       "scatterlist\n", __FUNCTION__);
+			return -ENOMEM;
+		}
+
+		to_capa  = sg->length;
+		copy_size = min_t(unsigned int, to_capa, from_rest);
+
+		pfn = page_to_pfn(sg_page(sg));
+		to = pfn_to_kaddr(pfn) + (sg->offset);
+		memcpy(to, from, copy_size);
+
+		from_rest  -= copy_size;
+		if (from_rest == 0) {
+			return 0;
+		}
+
+		from += copy_size;
+	}
+
+	printk(KERN_WARNING "%s: no space in scatterlist\n",
+	       __FUNCTION__);
+	return -ENOMEM;
+}
+#if 0
+static int __copy_from_sg(struct scatterlist *sgl, unsigned int nr_sg,
+		 void *buf, unsigned int buflen)
+{
+	struct scatterlist *sg;
+	void *from;
+	void *to = buf;
+	unsigned int from_rest;
+	unsigned int to_capa = buflen;
+	unsigned int copy_size;
+	unsigned int i;
+	unsigned long pfn;
+
+	for_each_sg (sgl, sg, nr_sg, i) {
+		if (sg_page(sg) == NULL) {
+			printk(KERN_WARNING "%s: inconsistent length field in "
+			       "scatterlist\n", __FUNCTION__);
+			return -ENOMEM;
+		}
+
+		from_rest = sg->length;
+		if ((from_rest > 0) && (to_capa < from_rest)) {
+			printk(KERN_WARNING
+			       "%s: no space in destination buffer\n",
+			       __FUNCTION__);
+			return -ENOMEM;
+		}
+		copy_size = from_rest;
+
+		pfn = page_to_pfn(sg_page(sg));
+		from = pfn_to_kaddr(pfn) + (sg->offset);
+		memcpy(to, from, copy_size);
+
+		to_capa  -= copy_size;
+		to += copy_size;
+	}
+
+	return 0;
+}
+#endif
+static int __nr_luns_under_host(struct vscsibk_info *info)
+{
+	struct v2p_entry *entry;
+	struct list_head *head = &(info->v2p_entry_lists);
+	unsigned long flags;
+	int lun_cnt = 0;
+
+	spin_lock_irqsave(&info->v2p_lock, flags);
+	list_for_each_entry(entry, head, l) {
+			lun_cnt++;
+	}
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+	return (lun_cnt);
+}
+
+
+/* REPORT LUNS Define*/
+#define VSCSI_REPORT_LUNS_HEADER	8
+#define VSCSI_REPORT_LUNS_RETRY		3
+
+/* quoted scsi_debug.c/resp_report_luns() */
+static void __report_luns(pending_req_t *pending_req, void *data)
+{
+	struct vscsibk_info *info   = pending_req->info;
+	unsigned int        channel = pending_req->v_chn;
+	unsigned int        target  = pending_req->v_tgt;
+	unsigned int        nr_seg  = pending_req->nr_segments;
+	unsigned char *cmd = (unsigned char *)pending_req->cmnd;
+
+	unsigned char *buff = NULL;
+	unsigned char alloc_len;
+	unsigned int alloc_luns = 0;
+	unsigned int req_bufflen = 0;
+	unsigned int actual_len = 0;
+	unsigned int retry_cnt = 0;
+	int select_report = (int)cmd[2];
+	int i, lun_cnt = 0, lun, upper, err = 0;
+
+	struct v2p_entry *entry;
+	struct list_head *head = &(info->v2p_entry_lists);
+	unsigned long flags;
+
+	struct scsi_lun *one_lun;
+
+	req_bufflen = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+	if ((req_bufflen < 4) || (select_report != 0))
+		goto fail;
+
+	alloc_luns = __nr_luns_under_host(info);
+	alloc_len  = sizeof(struct scsi_lun) * alloc_luns
+				+ VSCSI_REPORT_LUNS_HEADER;
+retry:
+	if ((buff = kzalloc(alloc_len, GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "scsiback:%s kmalloc err\n", __FUNCTION__);
+		goto fail;
+	}
+
+	one_lun = (struct scsi_lun *) &buff[8];
+	spin_lock_irqsave(&info->v2p_lock, flags);
+	list_for_each_entry(entry, head, l) {
+		if ((entry->v.chn == channel) &&
+		    (entry->v.tgt == target)) {
+			/* check overflow */
+			if (lun_cnt >= alloc_luns) {
+				spin_unlock_irqrestore(&info->v2p_lock,
+							flags);
+
+				if (retry_cnt < VSCSI_REPORT_LUNS_RETRY) {
+					retry_cnt++;
+					if (buff)
+						kfree(buff);
+					goto retry;
+				}
+
+				goto fail;
+			}
+
+			lun = entry->v.lun;
+			upper = (lun >> 8) & 0x3f;
+			if (upper)
+				one_lun[lun_cnt].scsi_lun[0] = upper;
+			one_lun[lun_cnt].scsi_lun[1] = lun & 0xff;
+			lun_cnt++;
+		}
+	}
+
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+
+	buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
+	buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
+
+	actual_len = lun_cnt * sizeof(struct scsi_lun)
+				+ VSCSI_REPORT_LUNS_HEADER;
+	req_bufflen = 0;
+	for (i = 0; i < nr_seg; i++)
+		req_bufflen += pending_req->sgl[i].length;
+
+	err = __copy_to_sg(pending_req->sgl, nr_seg, buff,
+				min(req_bufflen, actual_len));
+	if (err)
+		goto fail;
+
+	memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
+	pending_req->rslt = 0x00;
+	pending_req->resid = req_bufflen - min(req_bufflen, actual_len);
+
+	kfree(buff);
+	return;
+
+fail:
+	scsiback_mk_sense_buffer(pending_req->sense_buffer, ILLEGAL_REQUEST,
+		INVALID_FIELD_IN_CDB, 0);
+	pending_req->rslt  = check_condition_result;
+	pending_req->resid = 0;
+	if (buff)
+		kfree(buff);
+	return;
+}
+
+
+
+int __pre_do_emulation(pending_req_t *pending_req, void *data)
+{
+	uint8_t op_code = pending_req->cmnd[0];
+
+	if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_REQBUF) &&
+	    pre_function[op_code] != NULL) {
+		pre_function[op_code](pending_req, data);
+	}
+
+	/*
+	    0: no need for native driver call, so should return immediately.
+	    1: non emulation or should call native driver
+	       after modifing the request buffer.
+	*/
+	return !!(bitmap[op_code] & VSCSIIF_NEED_CMD_EXEC);
+}
+
+void scsiback_rsp_emulation(pending_req_t *pending_req)
+{
+	uint8_t op_code = pending_req->cmnd[0];
+
+	if ((bitmap[op_code] & VSCSIIF_NEED_EMULATE_RSPBUF) &&
+	    post_function[op_code] != NULL) {
+		post_function[op_code](pending_req, NULL);
+	}
+
+	return;
+}
+
+
+void scsiback_req_emulation_or_cmdexec(pending_req_t *pending_req)
+{
+	if (__pre_do_emulation(pending_req, NULL)) {
+		scsiback_cmd_exec(pending_req);
+	}
+	else {
+		scsiback_fast_flush_area(pending_req);
+		scsiback_do_resp_with_sense(pending_req->sense_buffer,
+		  pending_req->rslt, pending_req->resid, pending_req);
+	}
+}
+
+
+/*
+  Following are not customizable functions.
+*/
+void scsiback_emulation_init(void)
+{
+	int i;
+
+	/* Initialize to default state */
+	for (i = 0; i < VSCSI_MAX_SCSI_OP_CODE; i++) {
+		bitmap[i]        = (VSCSIIF_NEED_EMULATE_REQBUF |
+					VSCSIIF_NEED_EMULATE_RSPBUF);
+		pre_function[i]  = resp_not_supported_cmd;
+		post_function[i] = NULL;
+		/* means,
+		   - no need for pre-emulation
+		   - no need for post-emulation
+		   - call native driver
+		*/
+	}
+
+	/*
+	  Register appropriate functions below as you need.
+	  (See scsi/scsi.h for definition of SCSI op_code.)
+	*/
+
+	/*
+	  Following commands do not require emulation.
+	*/
+	NO_EMULATE(TEST_UNIT_READY);       /*0x00*/ /* sd,st */
+	NO_EMULATE(REZERO_UNIT);           /*0x01*/ /* st */
+	NO_EMULATE(REQUEST_SENSE);         /*0x03*/
+	NO_EMULATE(FORMAT_UNIT);           /*0x04*/
+	NO_EMULATE(READ_BLOCK_LIMITS);     /*0x05*/ /* st */
+	/*NO_EMULATE(REASSIGN_BLOCKS);       *//*0x07*/
+	NO_EMULATE(INITIALIZE_ELEMENT_STATUS); /*0x07*/ /* ch */
+	NO_EMULATE(READ_6);                /*0x08*/ /* sd,st */
+	NO_EMULATE(WRITE_6);               /*0x0a*/ /* sd,st */
+	NO_EMULATE(SEEK_6);                /*0x0b*/
+	/*NO_EMULATE(READ_REVERSE);          *//*0x0f*/
+	NO_EMULATE(WRITE_FILEMARKS);       /*0x10*/ /* st */
+	NO_EMULATE(SPACE);                 /*0x11*/ /* st */
+	NO_EMULATE(INQUIRY);               /*0x12*/
+	/*NO_EMULATE(RECOVER_BUFFERED_DATA); *//*0x14*/
+	NO_EMULATE(MODE_SELECT);           /*0x15*/ /* st */
+	/*NO_EMULATE(RESERVE);               *//*0x16*/
+	/*NO_EMULATE(RELEASE);               *//*0x17*/
+	/*NO_EMULATE(COPY);                  *//*0x18*/
+	NO_EMULATE(ERASE);                 /*0x19*/ /* st */
+	NO_EMULATE(MODE_SENSE);            /*0x1a*/ /* st */
+	NO_EMULATE(START_STOP);            /*0x1b*/ /* sd,st */
+	NO_EMULATE(RECEIVE_DIAGNOSTIC);    /*0x1c*/
+	NO_EMULATE(SEND_DIAGNOSTIC);       /*0x1d*/
+	NO_EMULATE(ALLOW_MEDIUM_REMOVAL);  /*0x1e*/
+
+	/*NO_EMULATE(SET_WINDOW);            *//*0x24*/
+	NO_EMULATE(READ_CAPACITY);         /*0x25*/ /* sd */
+	NO_EMULATE(READ_10);               /*0x28*/ /* sd */
+	NO_EMULATE(WRITE_10);              /*0x2a*/ /* sd */
+	NO_EMULATE(SEEK_10);               /*0x2b*/ /* st */
+	NO_EMULATE(POSITION_TO_ELEMENT);   /*0x2b*/ /* ch */
+	/*NO_EMULATE(WRITE_VERIFY);          *//*0x2e*/
+	/*NO_EMULATE(VERIFY);                *//*0x2f*/
+	/*NO_EMULATE(SEARCH_HIGH);           *//*0x30*/
+	/*NO_EMULATE(SEARCH_EQUAL);          *//*0x31*/
+	/*NO_EMULATE(SEARCH_LOW);            *//*0x32*/
+	NO_EMULATE(SET_LIMITS);            /*0x33*/
+	NO_EMULATE(PRE_FETCH);             /*0x34*/ /* st! */
+	NO_EMULATE(READ_POSITION);          /*0x34*/ /* st */
+	NO_EMULATE(SYNCHRONIZE_CACHE);      /*0x35*/ /* sd */
+	NO_EMULATE(LOCK_UNLOCK_CACHE);     /*0x36*/
+	NO_EMULATE(READ_DEFECT_DATA);      /*0x37*/
+	NO_EMULATE(MEDIUM_SCAN);           /*0x38*/
+	/*NO_EMULATE(COMPARE);               *//*0x39*/
+	/*NO_EMULATE(COPY_VERIFY);           *//*0x3a*/
+	NO_EMULATE(WRITE_BUFFER);          /*0x3b*/
+	NO_EMULATE(READ_BUFFER);           /*0x3c*/ /* osst */
+	/*NO_EMULATE(UPDATE_BLOCK);          *//*0x3d*/
+	/*NO_EMULATE(READ_LONG);             *//*0x3e*/
+	/*NO_EMULATE(WRITE_LONG);            *//*0x3f*/
+	/*NO_EMULATE(CHANGE_DEFINITION);     *//*0x40*/
+	/*NO_EMULATE(WRITE_SAME);            *//*0x41*/
+	NO_EMULATE(READ_TOC);              /*0x43*/ /* sr */
+	NO_EMULATE(LOG_SELECT);            /*0x4c*/
+	NO_EMULATE(LOG_SENSE);             /*0x4d*/ /* st! */
+	/*NO_EMULATE(MODE_SELECT_10);        *//*0x55*/
+	/*NO_EMULATE(RESERVE_10);            *//*0x56*/
+	/*NO_EMULATE(RELEASE_10);            *//*0x57*/
+	NO_EMULATE(MODE_SENSE_10);         /*0x5a*/ /* scsi_lib */
+	/*NO_EMULATE(PERSISTENT_RESERVE_IN); *//*0x5e*/
+	/*NO_EMULATE(PERSISTENT_RESERVE_OUT); *//*0x5f*/
+	/*           REPORT_LUNS             *//*0xa0*//*Full emulaiton*/
+	NO_EMULATE(MAINTENANCE_IN);           /*0xa3*/ /* IFT alua */
+	NO_EMULATE(MAINTENANCE_OUT);       /*0xa4*/ /* IFT alua */
+	NO_EMULATE(MOVE_MEDIUM);           /*0xa5*/ /* ch */
+	NO_EMULATE(EXCHANGE_MEDIUM);       /*0xa6*/ /* ch */
+	/*NO_EMULATE(READ_12);               *//*0xa8*/
+	/*NO_EMULATE(WRITE_12);              *//*0xaa*/
+	/*NO_EMULATE(WRITE_VERIFY_12);       *//*0xae*/
+	/*NO_EMULATE(SEARCH_HIGH_12);        *//*0xb0*/
+	/*NO_EMULATE(SEARCH_EQUAL_12);       *//*0xb1*/
+	/*NO_EMULATE(SEARCH_LOW_12);         *//*0xb2*/
+	NO_EMULATE(READ_ELEMENT_STATUS);   /*0xb8*/ /* ch */
+	NO_EMULATE(SEND_VOLUME_TAG);       /*0xb6*/ /* ch */
+	/*NO_EMULATE(WRITE_LONG_2);          *//*0xea*/
+	NO_EMULATE(READ_16);               /*0x88*/ /* sd >2TB */
+	NO_EMULATE(WRITE_16);              /*0x8a*/ /* sd >2TB */
+	NO_EMULATE(VERIFY_16);	           /*0x8f*/
+	NO_EMULATE(SERVICE_ACTION_IN);     /*0x9e*/ /* sd >2TB */
+
+/* st: QFA_REQUEST_BLOCK, QFA_SEEK_BLOCK might be needed ? */
+	/*
+	  Following commands require emulation.
+	*/
+	pre_function[REPORT_LUNS] = __report_luns;
+	bitmap[REPORT_LUNS] = (VSCSIIF_NEED_EMULATE_REQBUF |
+					VSCSIIF_NEED_EMULATE_RSPBUF);
+
+	return;
+}
diff --git a/drivers/scsi/xen-scsiback/interface.c b/drivers/scsi/xen-scsiback/interface.c
new file mode 100644
index 0000000..663568e
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/interface.c
@@ -0,0 +1,141 @@
+/*
+ * interface management.
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include "common.h"
+
+#include <xen/evtchn.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+
+
+static struct kmem_cache *scsiback_cachep;
+
+struct vscsibk_info *vscsibk_info_alloc(domid_t domid)
+{
+	struct vscsibk_info *info;
+
+	info = kmem_cache_zalloc(scsiback_cachep, GFP_KERNEL);
+	if (!info)
+		return ERR_PTR(-ENOMEM);
+
+	info->domid = domid;
+	spin_lock_init(&info->ring_lock);
+	atomic_set(&info->nr_unreplied_reqs, 0);
+	init_waitqueue_head(&info->wq);
+	init_waitqueue_head(&info->waiting_to_free);
+
+	return info;
+}
+
+int scsiback_init_sring(struct vscsibk_info *info,
+		unsigned long ring_ref, unsigned int evtchn)
+{
+	struct vscsiif_sring *sring;
+	int err;
+
+	if (!info)
+		return -ENODEV;
+
+	if (info->irq) {
+		printk(KERN_ERR "scsiback: Already connected through?\n");
+		return -1;
+	}
+
+	err = xenbus_map_ring_valloc(info->dev, ring_ref, &info->ring_area);
+	if (err < 0)
+		return -ENOMEM;
+
+	sring = (struct vscsiif_sring *) info->ring_area;
+	BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+	err = bind_interdomain_evtchn_to_irqhandler(
+			info->domid, evtchn,
+			scsiback_intr, 0, "vscsiif-backend", info);
+	if (err < 0)
+		goto unmap_page;
+
+	info->irq = err;
+
+	return 0;
+
+unmap_page:
+	xenbus_unmap_ring_vfree(info->dev, info->ring_area);
+
+	return err;
+}
+
+void scsiback_disconnect(struct vscsibk_info *info)
+{
+	if (info->kthread) {
+		kthread_stop(info->kthread);
+		info->kthread = NULL;
+	}
+
+	wait_event(info->waiting_to_free,
+		atomic_read(&info->nr_unreplied_reqs) == 0);
+
+	if (info->irq) {
+		unbind_from_irqhandler(info->irq, info);
+		info->irq = 0;
+	}
+
+	if (info->ring.sring || info->ring_area) {
+		xenbus_unmap_ring_vfree(info->dev, info->ring_area);
+		info->ring.sring = NULL;
+		info->ring_area = NULL;
+	}
+}
+
+void scsiback_free(struct vscsibk_info *info)
+{
+	kmem_cache_free(scsiback_cachep, info);
+}
+
+int __init scsiback_interface_init(void)
+{
+	scsiback_cachep = kmem_cache_create("vscsiif_cache",
+		sizeof(struct vscsibk_info), 0, 0, NULL);
+	if (!scsiback_cachep) {
+		printk(KERN_ERR "scsiback: can't init scsi cache\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void scsiback_interface_exit(void)
+{
+	kmem_cache_destroy(scsiback_cachep);
+}
diff --git a/drivers/scsi/xen-scsiback/scsiback.c b/drivers/scsi/xen-scsiback/scsiback.c
new file mode 100644
index 0000000..a209f87
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/scsiback.c
@@ -0,0 +1,757 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <xen/balloon.h>
+#include <asm/hypervisor.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+
+#include "common.h"
+
+
+struct list_head pending_free;
+DEFINE_SPINLOCK(pending_free_lock);
+DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
+
+int vscsiif_reqs = VSCSIIF_BACK_MAX_PENDING_REQS;
+module_param_named(reqs, vscsiif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of scsiback requests to allocate");
+
+static unsigned int log_print_stat;
+module_param(log_print_stat, int, 0644);
+
+#define SCSIBACK_INVALID_HANDLE (~0)
+
+static pending_req_t *pending_reqs;
+static struct page **pending_pages;
+static grant_handle_t *pending_grant_handles;
+
+static int vaddr_pagenr(pending_req_t *req, int seg)
+{
+	return (req - pending_reqs) * VSCSIIF_SG_TABLESIZE + seg;
+}
+
+static unsigned long vaddr(pending_req_t *req, int seg)
+{
+	unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
+	return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+	(pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+void scsiback_fast_flush_area(pending_req_t *req)
+{
+	struct gnttab_unmap_grant_ref unmap[VSCSIIF_SG_TABLESIZE];
+	unsigned int i, invcount = 0;
+	grant_handle_t handle;
+	int err;
+
+	if (req->nr_segments) {
+		for (i = 0; i < req->nr_segments; i++) {
+			handle = pending_handle(req, i);
+			if (handle == SCSIBACK_INVALID_HANDLE)
+				continue;
+			gnttab_set_unmap_op(&unmap[i], vaddr(req, i),
+						GNTMAP_host_map, handle);
+			pending_handle(req, i) = SCSIBACK_INVALID_HANDLE;
+			invcount++;
+		}
+
+		err = HYPERVISOR_grant_table_op(
+			GNTTABOP_unmap_grant_ref, unmap, invcount);
+		BUG_ON(err);
+		for (i = 0; i <invcount; i++) {
+			err = m2p_remove_override(
+				virt_to_page(unmap[i].host_addr), false);
+			WARN_ON(err);
+		}
+		kfree(req->sgl);
+	}
+
+	return;
+}
+
+
+static pending_req_t * alloc_req(struct vscsibk_info *info)
+{
+	pending_req_t *req = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pending_free_lock, flags);
+	if (!list_empty(&pending_free)) {
+		req = list_entry(pending_free.next, pending_req_t, free_list);
+		list_del(&req->free_list);
+	}
+	spin_unlock_irqrestore(&pending_free_lock, flags);
+	return req;
+}
+
+
+static void free_req(pending_req_t *req)
+{
+	unsigned long flags;
+	int was_empty;
+
+	spin_lock_irqsave(&pending_free_lock, flags);
+	was_empty = list_empty(&pending_free);
+	list_add(&req->free_list, &pending_free);
+	spin_unlock_irqrestore(&pending_free_lock, flags);
+	if (was_empty)
+		wake_up(&pending_free_wq);
+}
+
+
+static void scsiback_notify_work(struct vscsibk_info *info)
+{
+	info->waiting_reqs = 1;
+	wake_up(&info->wq);
+}
+
+void scsiback_do_resp_with_sense(char *sense_buffer, int32_t result,
+			uint32_t resid, pending_req_t *pending_req)
+{
+	vscsiif_response_t *ring_res;
+	struct vscsibk_info *info = pending_req->info;
+	int notify;
+	int more_to_do = 1;
+	struct scsi_sense_hdr sshdr;
+	unsigned long flags;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	spin_lock_irqsave(&info->ring_lock, flags);
+
+	ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
+	info->ring.rsp_prod_pvt++;
+
+	ring_res->rslt   = result;
+	ring_res->rqid   = pending_req->rqid;
+
+	if (sense_buffer != NULL) {
+		if (scsi_normalize_sense(sense_buffer,
+			sizeof(sense_buffer), &sshdr)) {
+
+			int len = 8 + sense_buffer[7];
+
+			if (len > VSCSIIF_SENSE_BUFFERSIZE)
+				len = VSCSIIF_SENSE_BUFFERSIZE;
+
+			memcpy(ring_res->sense_buffer, sense_buffer, len);
+			ring_res->sense_len = len;
+		}
+	} else {
+		ring_res->sense_len = 0;
+	}
+
+	ring_res->residual_len = resid;
+
+	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info->ring, notify);
+	if (info->ring.rsp_prod_pvt == info->ring.req_cons) {
+		RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
+	} else if (RING_HAS_UNCONSUMED_REQUESTS(&info->ring)) {
+		more_to_do = 1;
+	}
+
+	spin_unlock_irqrestore(&info->ring_lock, flags);
+
+	if (more_to_do)
+		scsiback_notify_work(info);
+
+	if (notify)
+		notify_remote_via_irq(info->irq);
+
+	free_req(pending_req);
+}
+
+static void scsiback_print_status(char *sense_buffer, int errors,
+					pending_req_t *pending_req)
+{
+	struct scsi_device *sdev = pending_req->sdev;
+
+	printk(KERN_ERR "scsiback: %d:%d:%d:%d ",sdev->host->host_no,
+			sdev->channel, sdev->id, sdev->lun);
+	printk(KERN_ERR "status = 0x%02x, message = 0x%02x, host = 0x%02x, driver = 0x%02x\n",
+			status_byte(errors), msg_byte(errors),
+			host_byte(errors), driver_byte(errors));
+
+	printk(KERN_ERR "scsiback: cmnd[0]=0x%02X\n",
+			pending_req->cmnd[0]);
+
+	if (CHECK_CONDITION & status_byte(errors))
+		__scsi_print_sense("scsiback", sense_buffer, SCSI_SENSE_BUFFERSIZE);
+}
+
+
+static void scsiback_cmd_done(struct request *req, int uptodate)
+{
+	pending_req_t *pending_req = req->end_io_data;
+	unsigned char *sense_buffer;
+	unsigned int resid;
+	int errors;
+
+	sense_buffer = req->sense;
+	resid        = blk_rq_bytes(req);
+	errors       = req->errors;
+
+	if (errors != 0) {
+		if (log_print_stat)
+			scsiback_print_status(sense_buffer, errors, pending_req);
+	}
+
+	/* The Host mode is through as for Emulation. */
+	if (pending_req->info->feature != VSCSI_TYPE_HOST)
+		scsiback_rsp_emulation(pending_req);
+
+	scsiback_fast_flush_area(pending_req);
+	scsiback_do_resp_with_sense(sense_buffer, errors, resid, pending_req);
+	scsiback_put(pending_req->info);
+
+	__blk_put_request(req->q, req);
+}
+
+
+static int scsiback_gnttab_data_map(vscsiif_request_t *ring_req,
+					pending_req_t *pending_req)
+{
+	u32 flags;
+	int write;
+	int i, err = 0;
+	unsigned int data_len = 0;
+	struct gnttab_map_grant_ref map[VSCSIIF_SG_TABLESIZE];
+	struct vscsibk_info *info   = pending_req->info;
+
+	int data_dir = pending_req->sc_data_direction;
+	unsigned int nr_segments = (unsigned int)pending_req->nr_segments;
+
+	write = (data_dir == DMA_TO_DEVICE);
+
+	if (nr_segments) {
+		struct scatterlist *sg;
+
+		/* free of (sgl) in fast_flush_area()*/
+		pending_req->sgl = kmalloc(sizeof(struct scatterlist) * nr_segments,
+						GFP_KERNEL);
+		if (!pending_req->sgl) {
+			printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", __FUNCTION__);
+			return -ENOMEM;
+		}
+
+		sg_init_table(pending_req->sgl, nr_segments);
+
+		for (i = 0; i < nr_segments; i++) {
+			flags = GNTMAP_host_map;
+			if (write)
+				flags |= GNTMAP_readonly;
+
+			gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+						ring_req->seg[i].gref,
+						info->domid);
+		}
+
+		err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nr_segments);
+		BUG_ON(err);
+
+		/* Retry maps with GNTST_eagain */
+		for(i=0; i < nr_segments; i++) {
+		    while(unlikely(map[i].status == GNTST_eagain))
+		    {
+				msleep(10);
+				err = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
+							&map[i],
+							1);
+				BUG_ON(err);
+		    }
+		}
+
+		for_each_sg (pending_req->sgl, sg, nr_segments, i) {
+			struct page *pg;
+
+			if (unlikely(map[i].status != 0)) {
+				printk(KERN_ERR "scsiback: invalid buffer -- could not remap it: " \
+					"%d/%d, err:%d\n", i, nr_segments, map[i].status);
+				map[i].handle = SCSIBACK_INVALID_HANDLE;
+				err |= 1;
+			}
+
+			pending_handle(pending_req, i) = map[i].handle;
+
+			if (err)
+				continue;
+
+			pg = pending_pages[vaddr_pagenr(pending_req, i)];
+
+			m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), pg, false);
+			sg_set_page(sg, pg, ring_req->seg[i].length,
+				    ring_req->seg[i].offset);
+			data_len += sg->length;
+
+			barrier();
+			if (sg->offset >= PAGE_SIZE ||
+			    sg->length > PAGE_SIZE ||
+			    sg->offset + sg->length > PAGE_SIZE)
+				err |= 1;
+
+		}
+
+		if (err)
+			goto fail_flush;
+	}
+
+	pending_req->request_bufflen = data_len;
+
+	return 0;
+
+fail_flush:
+	scsiback_fast_flush_area(pending_req);
+	return -ENOMEM;
+}
+
+/* quoted scsi_lib.c/scsi_bi_endio */
+static void scsiback_bi_endio(struct bio *bio, int error)
+{
+	bio_put(bio);
+}
+
+
+
+/* quoted scsi_lib.c/scsi_req_map_sg . */
+static struct bio *request_map_sg(pending_req_t *pending_req)
+{
+	struct request_queue *q = pending_req->sdev->request_queue;
+	unsigned int nsegs = (unsigned int)pending_req->nr_segments;
+	unsigned int i, len, bytes, off, nr_pages, nr_vecs = 0;
+	struct scatterlist *sg;
+	struct page *page;
+	struct bio *bio = NULL, *bio_first = NULL, *bio_last = NULL;
+	int err;
+
+	for_each_sg (pending_req->sgl, sg, nsegs, i) {
+		page = sg_page(sg);
+		off = sg->offset;
+		len = sg->length;
+
+		nr_pages = (len + off + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		while (len > 0) {
+			bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+
+			if (!bio) {
+				nr_vecs = min_t(unsigned int, BIO_MAX_PAGES,
+					 	nr_pages);
+				nr_pages -= nr_vecs;
+				bio = bio_alloc(GFP_KERNEL, nr_vecs);
+				if (!bio) {
+					err = -ENOMEM;
+					goto free_bios;
+				}
+				bio->bi_end_io = scsiback_bi_endio;
+				if (bio_last)
+					bio_last->bi_next = bio;
+				else
+					bio_first = bio;
+				bio_last = bio;
+			}
+
+			if (bio_add_pc_page(q, bio, page, bytes, off) !=
+						bytes) {
+				bio_put(bio);
+				err = -EINVAL;
+				goto free_bios;
+			}
+
+			if (bio->bi_vcnt >= nr_vecs) {
+				bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+				if (pending_req->sc_data_direction == WRITE)
+					bio->bi_rw |= REQ_WRITE;
+				bio = NULL;
+			}
+
+			page++;
+			len -= bytes;
+			off = 0;
+		}
+	}
+
+	return bio_first;
+
+free_bios:
+	while ((bio = bio_first) != NULL) {
+		bio_first = bio->bi_next;
+		bio_put(bio);
+	}
+
+	return ERR_PTR(err);
+}
+
+
+void scsiback_cmd_exec(pending_req_t *pending_req)
+{
+	int cmd_len  = (int)pending_req->cmd_len;
+	int data_dir = (int)pending_req->sc_data_direction;
+	unsigned int timeout;
+	struct request *rq;
+	int write;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	/* because it doesn't timeout backend earlier than frontend.*/
+	if (pending_req->timeout_per_command)
+		timeout = pending_req->timeout_per_command * HZ;
+	else
+		timeout = VSCSIIF_TIMEOUT;
+
+	write = (data_dir == DMA_TO_DEVICE);
+	if (pending_req->nr_segments) {
+		struct bio *bio = request_map_sg(pending_req);
+
+		if (IS_ERR(bio)) {
+			printk(KERN_ERR "scsiback: SG Request Map Error\n");
+			return;
+		}
+
+		rq = blk_make_request(pending_req->sdev->request_queue, bio,
+				      GFP_KERNEL);
+		if (IS_ERR(rq)) {
+			printk(KERN_ERR "scsiback: Make Request Error\n");
+			return;
+		}
+
+		rq->buffer = NULL;
+	} else {
+		rq = blk_get_request(pending_req->sdev->request_queue, write,
+				     GFP_KERNEL);
+		if (unlikely(!rq)) {
+			printk(KERN_ERR "scsiback: Get Request Error\n");
+			return;
+		}
+	}
+
+	rq->cmd_type = REQ_TYPE_BLOCK_PC;
+	rq->cmd_len = cmd_len;
+	memcpy(rq->cmd, pending_req->cmnd, cmd_len);
+
+	memset(pending_req->sense_buffer, 0, VSCSIIF_SENSE_BUFFERSIZE);
+	rq->sense       = pending_req->sense_buffer;
+	rq->sense_len = 0;
+
+	/* not allowed to retry in backend.                   */
+	rq->retries   = 0;
+	rq->timeout   = timeout;
+	rq->end_io_data = pending_req;
+
+	scsiback_get(pending_req->info);
+	blk_execute_rq_nowait(rq->q, NULL, rq, 1, scsiback_cmd_done);
+
+	return ;
+}
+
+
+static void scsiback_device_reset_exec(pending_req_t *pending_req)
+{
+	struct vscsibk_info *info = pending_req->info;
+	int err;
+	struct scsi_device *sdev = pending_req->sdev;
+
+	scsiback_get(info);
+	err = scsi_reset_provider(sdev, SCSI_TRY_RESET_DEVICE);
+
+	scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
+	scsiback_put(info);
+
+	return;
+}
+
+
+irqreturn_t scsiback_intr(int irq, void *dev_id)
+{
+	scsiback_notify_work((struct vscsibk_info *)dev_id);
+	return IRQ_HANDLED;
+}
+
+static int prepare_pending_reqs(struct vscsibk_info *info,
+		vscsiif_request_t *ring_req, pending_req_t *pending_req)
+{
+	struct scsi_device *sdev;
+	struct ids_tuple vir;
+	int err = -EINVAL;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	pending_req->rqid       = ring_req->rqid;
+	pending_req->act        = ring_req->act;
+
+	pending_req->info       = info;
+
+	pending_req->v_chn = vir.chn = ring_req->channel;
+	pending_req->v_tgt = vir.tgt = ring_req->id;
+	vir.lun = ring_req->lun;
+
+	rmb();
+	sdev = scsiback_do_translation(info, &vir);
+	if (!sdev) {
+		pending_req->sdev = NULL;
+		DPRINTK("scsiback: doesn't exist.\n");
+		err = -ENODEV;
+		goto invalid_value;
+	}
+	pending_req->sdev = sdev;
+
+	/* request range check from frontend */
+	pending_req->sc_data_direction = ring_req->sc_data_direction;
+	barrier();
+	if ((pending_req->sc_data_direction != DMA_BIDIRECTIONAL) &&
+		(pending_req->sc_data_direction != DMA_TO_DEVICE) &&
+		(pending_req->sc_data_direction != DMA_FROM_DEVICE) &&
+		(pending_req->sc_data_direction != DMA_NONE)) {
+		DPRINTK("scsiback: invalid parameter data_dir = %d\n",
+			pending_req->sc_data_direction);
+		err = -EINVAL;
+		goto invalid_value;
+	}
+
+	pending_req->nr_segments = ring_req->nr_segments;
+	barrier();
+	if (pending_req->nr_segments > VSCSIIF_SG_TABLESIZE) {
+		DPRINTK("scsiback: invalid parameter nr_seg = %d\n",
+			pending_req->nr_segments);
+		err = -EINVAL;
+		goto invalid_value;
+	}
+
+	pending_req->cmd_len = ring_req->cmd_len;
+	barrier();
+	if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) {
+		DPRINTK("scsiback: invalid parameter cmd_len = %d\n",
+			pending_req->cmd_len);
+		err = -EINVAL;
+		goto invalid_value;
+	}
+	memcpy(pending_req->cmnd, ring_req->cmnd, pending_req->cmd_len);
+
+	pending_req->timeout_per_command = ring_req->timeout_per_command;
+
+	if(scsiback_gnttab_data_map(ring_req, pending_req)) {
+		DPRINTK("scsiback: invalid buffer\n");
+		err = -EINVAL;
+		goto invalid_value;
+	}
+
+	return 0;
+
+invalid_value:
+	return err;
+}
+
+
+static int scsiback_do_cmd_fn(struct vscsibk_info *info)
+{
+	struct vscsiif_back_ring *ring = &info->ring;
+	vscsiif_request_t  *ring_req;
+
+	pending_req_t *pending_req;
+	RING_IDX rc, rp;
+	int err, more_to_do = 0;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	rc = ring->req_cons;
+	rp = ring->sring->req_prod;
+	rmb();
+
+	while ((rc != rp)) {
+		if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
+			break;
+		pending_req = alloc_req(info);
+		if (NULL == pending_req) {
+			more_to_do = 1;
+			break;
+		}
+
+		ring_req = RING_GET_REQUEST(ring, rc);
+		ring->req_cons = ++rc;
+
+		err = prepare_pending_reqs(info, ring_req,
+						pending_req);
+		if (err == -EINVAL) {
+			scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
+				0, pending_req);
+			continue;
+		} else if (err == -ENODEV) {
+			scsiback_do_resp_with_sense(NULL, (DID_NO_CONNECT << 16),
+				0, pending_req);
+			continue;
+		}
+
+		if (pending_req->act == VSCSIIF_ACT_SCSI_CDB) {
+
+			/* The Host mode is through as for Emulation. */
+			if (info->feature == VSCSI_TYPE_HOST)
+				scsiback_cmd_exec(pending_req);
+			else
+				scsiback_req_emulation_or_cmdexec(pending_req);
+
+		} else if (pending_req->act == VSCSIIF_ACT_SCSI_RESET) {
+			scsiback_device_reset_exec(pending_req);
+		} else {
+			printk(KERN_ERR "scsiback: invalid parameter for request\n");
+			scsiback_do_resp_with_sense(NULL, (DRIVER_ERROR << 24),
+				0, pending_req);
+			continue;
+		}
+	}
+
+	if (RING_HAS_UNCONSUMED_REQUESTS(ring))
+		more_to_do = 1;
+
+	/* Yield point for this unbounded loop. */
+	cond_resched();
+
+	return more_to_do;
+}
+
+
+int scsiback_schedule(void *data)
+{
+	struct vscsibk_info *info = (struct vscsibk_info *)data;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(
+			info->wq,
+			info->waiting_reqs || kthread_should_stop());
+		wait_event_interruptible(
+			pending_free_wq,
+			!list_empty(&pending_free) || kthread_should_stop());
+
+		info->waiting_reqs = 0;
+		smp_mb();
+
+		if (scsiback_do_cmd_fn(info))
+			info->waiting_reqs = 1;
+	}
+
+	return 0;
+}
+
+
+static int __init scsiback_init(void)
+{
+	int i, mmap_pages;
+
+	if (!xen_domain())
+		return -ENODEV;
+
+	mmap_pages = vscsiif_reqs * VSCSIIF_SG_TABLESIZE;
+
+	pending_reqs          = kzalloc(sizeof(pending_reqs[0]) *
+					vscsiif_reqs, GFP_KERNEL);
+	pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
+					mmap_pages, GFP_KERNEL);
+	pending_pages         = kzalloc(sizeof(pending_pages[0]) *
+					mmap_pages, GFP_KERNEL);
+
+	if (!pending_reqs || !pending_grant_handles || !pending_pages)
+		goto out_of_memory;
+
+	for (i = 0; i < mmap_pages; i++) {
+		pending_grant_handles[i] = SCSIBACK_INVALID_HANDLE;
+		pending_pages[i] = alloc_page(GFP_KERNEL);
+		if (pending_pages[i] == NULL)
+			goto out_of_memory;
+	}
+	if (scsiback_interface_init() < 0)
+		goto out_of_kmem;
+
+	memset(pending_reqs, 0, sizeof(pending_reqs));
+	INIT_LIST_HEAD(&pending_free);
+
+	for (i = 0; i < vscsiif_reqs; i++)
+		list_add_tail(&pending_reqs[i].free_list, &pending_free);
+
+	if (scsiback_xenbus_init())
+		goto out_of_xenbus;
+
+	scsiback_emulation_init();
+
+	return 0;
+
+out_of_xenbus:
+	scsiback_xenbus_unregister();
+out_of_kmem:
+	scsiback_interface_exit();
+out_of_memory:
+	if (pending_pages) {
+		for (i = 0; i < mmap_pages; i++) {
+			if (pending_pages[i])
+				__free_page(pending_pages[i]);
+		}
+		kfree(pending_pages);
+	}
+	kfree(pending_reqs);
+	kfree(pending_grant_handles);
+	printk(KERN_ERR "scsiback: %s: out of memory\n", __FUNCTION__);
+	return -ENOMEM;
+}
+
+
+static void __exit scsiback_exit(void)
+{
+	scsiback_xenbus_unregister();
+	scsiback_interface_exit();
+	kfree(pending_reqs);
+	kfree(pending_grant_handles);
+	if (pending_pages) {
+		unsigned int i;
+		unsigned int mmap_pages = vscsiif_reqs * VSCSIIF_SG_TABLESIZE;
+		for (i = 0; i < mmap_pages; i++) {
+			if (pending_pages[i])
+				__free_page(pending_pages[i]);
+		}
+		kfree(pending_pages);
+	}
+}
+
+module_init(scsiback_init);
+module_exit(scsiback_exit);
+
+MODULE_DESCRIPTION("Xen SCSI backend driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/xen-scsiback/translate.c b/drivers/scsi/xen-scsiback/translate.c
new file mode 100644
index 0000000..36873cc
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/translate.c
@@ -0,0 +1,168 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <linux/gfp.h>
+
+#include "common.h"
+
+/*
+  Initialize the translation entry list
+*/
+void scsiback_init_translation_table(struct vscsibk_info *info)
+{
+	INIT_LIST_HEAD(&info->v2p_entry_lists);
+	spin_lock_init(&info->v2p_lock);
+}
+
+
+/*
+  Add a new translation entry
+*/
+int scsiback_add_translation_entry(struct vscsibk_info *info,
+			struct scsi_device *sdev, struct ids_tuple *v)
+{
+	int err = 0;
+	struct v2p_entry *entry;
+	struct v2p_entry *new;
+	struct list_head *head = &(info->v2p_entry_lists);
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->v2p_lock, flags);
+
+	/* Check double assignment to identical virtual ID */
+	list_for_each_entry(entry, head, l) {
+		if ((entry->v.chn == v->chn) &&
+		    (entry->v.tgt == v->tgt) &&
+		    (entry->v.lun == v->lun)) {
+			printk(KERN_WARNING "scsiback: Virtual ID is already used. "
+			       "Assignment was not performed.\n");
+			err = -EEXIST;
+			goto out;
+		}
+
+	}
+
+	/* Create a new translation entry and add to the list */
+	if ((new = kmalloc(sizeof(struct v2p_entry), GFP_ATOMIC)) == NULL) {
+		printk(KERN_ERR "scsiback: %s: kmalloc() error.\n", __FUNCTION__);
+		err = -ENOMEM;
+		goto out;
+	}
+	new->v = *v;
+	new->sdev = sdev;
+	list_add_tail(&new->l, head);
+
+out:
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+	return err;
+}
+
+
+/*
+  Delete the translation entry specfied
+*/
+int scsiback_del_translation_entry(struct vscsibk_info *info,
+				struct ids_tuple *v)
+{
+	struct v2p_entry *entry;
+	struct list_head *head = &(info->v2p_entry_lists);
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->v2p_lock, flags);
+	/* Find out the translation entry specified */
+	list_for_each_entry(entry, head, l) {
+		if ((entry->v.chn == v->chn) &&
+		    (entry->v.tgt == v->tgt) &&
+		    (entry->v.lun == v->lun)) {
+			goto found;
+		}
+	}
+
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+	return 1;
+
+found:
+	/* Delete the translation entry specfied */
+	scsi_device_put(entry->sdev);
+	list_del(&entry->l);
+	kfree(entry);
+
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+	return 0;
+}
+
+
+/*
+  Perform virtual to physical translation
+*/
+struct scsi_device *scsiback_do_translation(struct vscsibk_info *info,
+			struct ids_tuple *v)
+{
+	struct v2p_entry *entry;
+	struct list_head *head = &(info->v2p_entry_lists);
+	struct scsi_device *sdev = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->v2p_lock, flags);
+	list_for_each_entry(entry, head, l) {
+		if ((entry->v.chn == v->chn) &&
+		    (entry->v.tgt == v->tgt) &&
+		    (entry->v.lun == v->lun)) {
+			sdev = entry->sdev;
+			goto out;
+		}
+	}
+out:
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+	return sdev;
+}
+
+
+/*
+  Release the translation entry specfied
+*/
+void scsiback_release_translation_entry(struct vscsibk_info *info)
+{
+	struct v2p_entry *entry, *tmp;
+	struct list_head *head = &(info->v2p_entry_lists);
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->v2p_lock, flags);
+	list_for_each_entry_safe(entry, tmp, head, l) {
+		scsi_device_put(entry->sdev);
+		list_del(&entry->l);
+		kfree(entry);
+	}
+
+	spin_unlock_irqrestore(&info->v2p_lock, flags);
+	return;
+
+}
diff --git a/drivers/scsi/xen-scsiback/xenbus.c b/drivers/scsi/xen-scsiback/xenbus.c
new file mode 100644
index 0000000..0816c0e
--- /dev/null
+++ b/drivers/scsi/xen-scsiback/xenbus.c
@@ -0,0 +1,374 @@
+/*
+ * Xen SCSI backend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * Based on the blkback driver code.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+
+#include "common.h"
+
+struct backend_info
+{
+	struct xenbus_device *dev;
+	struct vscsibk_info *info;
+};
+
+
+static int __vscsiif_name(struct backend_info *be, char *buf)
+{
+	struct xenbus_device *dev = be->dev;
+	unsigned int domid, id;
+
+	sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
+	snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
+
+	return 0;
+}
+
+static int scsiback_map(struct backend_info *be)
+{
+	struct xenbus_device *dev = be->dev;
+	unsigned long ring_ref = 0;
+	unsigned int evtchn = 0;
+	int err;
+	char name[TASK_COMM_LEN];
+
+	err = xenbus_gather(XBT_NIL, dev->otherend,
+			"ring-ref", "%lu", &ring_ref,
+			"event-channel", "%u", &evtchn, NULL);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
+		return err;
+	}
+	err = scsiback_init_sring(be->info, ring_ref, evtchn);
+	if (err)
+		return err;
+
+	err = __vscsiif_name(be, name);
+	if (err) {
+		xenbus_dev_error(dev, err, "get scsiback dev name");
+		return err;
+	}
+
+	be->info->kthread = kthread_run(scsiback_schedule, be->info, name);
+	if (IS_ERR(be->info->kthread)) {
+		err = PTR_ERR(be->info->kthread);
+		be->info->kthread = NULL;
+		xenbus_dev_error(be->dev, err, "start vscsiif");
+		return err;
+	}
+
+	return 0;
+}
+
+
+struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
+{
+	struct Scsi_Host *shost;
+	struct scsi_device *sdev = NULL;
+
+	shost = scsi_host_lookup(phy->hst);
+	if (IS_ERR(shost)) {
+		printk(KERN_ERR "scsiback: host%d doesn't exist.\n",
+			phy->hst);
+		return NULL;
+	}
+	sdev   = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
+	if (!sdev) {
+		printk(KERN_ERR "scsiback: %d:%d:%d:%d doesn't exist.\n",
+			phy->hst, phy->chn, phy->tgt, phy->lun);
+		scsi_host_put(shost);
+		return NULL;
+	}
+
+	scsi_host_put(shost);
+	return (sdev);
+}
+
+#define VSCSIBACK_OP_ADD_OR_DEL_LUN	1
+#define VSCSIBACK_OP_UPDATEDEV_STATE	2
+
+
+static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
+{
+	int i, err = 0;
+	struct ids_tuple phy, vir;
+	int device_state;
+	char str[64], state_str[64];
+	char **dir;
+	unsigned int dir_n = 0;
+	struct xenbus_device *dev = be->dev;
+	struct scsi_device *sdev;
+
+	dir = xenbus_directory(XBT_NIL, dev->nodename, "vscsi-devs", &dir_n);
+	if (IS_ERR(dir))
+		return;
+
+	for (i = 0; i < dir_n; i++) {
+		/* read status */
+		snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
+		err = xenbus_scanf(XBT_NIL, dev->nodename, state_str, "%u",
+			&device_state);
+		if (XENBUS_EXIST_ERR(err))
+			continue;
+
+		/* physical SCSI device */
+		snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", dir[i]);
+		err = xenbus_scanf(XBT_NIL, dev->nodename, str,
+			"%u:%u:%u:%u", &phy.hst, &phy.chn, &phy.tgt, &phy.lun);
+		if (XENBUS_EXIST_ERR(err)) {
+			xenbus_printf(XBT_NIL, dev->nodename, state_str,
+					"%d", XenbusStateClosed);
+			continue;
+		}
+
+		/* virtual SCSI device */
+		snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
+		err = xenbus_scanf(XBT_NIL, dev->nodename, str,
+			"%u:%u:%u:%u", &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
+		if (XENBUS_EXIST_ERR(err)) {
+			xenbus_printf(XBT_NIL, dev->nodename, state_str,
+					"%d", XenbusStateClosed);
+			continue;
+		}
+
+		switch (op) {
+		case VSCSIBACK_OP_ADD_OR_DEL_LUN:
+			if (device_state == XenbusStateInitialising) {
+				sdev = scsiback_get_scsi_device(&phy);
+				if (!sdev)
+					xenbus_printf(XBT_NIL, dev->nodename, state_str,
+							    "%d", XenbusStateClosed);
+				else {
+					err = scsiback_add_translation_entry(be->info, sdev, &vir);
+					if (!err) {
+						if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
+								    "%d", XenbusStateInitialised)) {
+							printk(KERN_ERR "scsiback: xenbus_printf error %s\n", state_str);
+							scsiback_del_translation_entry(be->info, &vir);
+						}
+					} else {
+						scsi_device_put(sdev);
+						xenbus_printf(XBT_NIL, dev->nodename, state_str,
+								    "%d", XenbusStateClosed);
+					}
+				}
+			}
+
+			if (device_state == XenbusStateClosing) {
+				if (!scsiback_del_translation_entry(be->info, &vir)) {
+					if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
+							    "%d", XenbusStateClosed))
+						printk(KERN_ERR "scsiback: xenbus_printf error %s\n", state_str);
+				}
+			}
+			break;
+
+		case VSCSIBACK_OP_UPDATEDEV_STATE:
+			if (device_state == XenbusStateInitialised) {
+				/* modify vscsi-devs/dev-x/state */
+				if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
+						    "%d", XenbusStateConnected)) {
+					printk(KERN_ERR "scsiback: xenbus_printf error %s\n", state_str);
+					scsiback_del_translation_entry(be->info, &vir);
+					xenbus_printf(XBT_NIL, dev->nodename, state_str,
+							    "%d", XenbusStateClosed);
+				}
+			}
+			break;
+		/*When it is necessary, processing is added here.*/
+		default:
+			break;
+		}
+	}
+
+	kfree(dir);
+	return ;
+}
+
+
+static void scsiback_frontend_changed(struct xenbus_device *dev,
+					enum xenbus_state frontend_state)
+{
+	struct backend_info *be = dev_get_drvdata(&dev->dev);
+	int err;
+
+	switch (frontend_state) {
+	case XenbusStateInitialising:
+		break;
+	case XenbusStateInitialised:
+		err = scsiback_map(be);
+		if (err)
+			break;
+
+		scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+		xenbus_switch_state(dev, XenbusStateConnected);
+
+		break;
+	case XenbusStateConnected:
+
+		scsiback_do_lun_hotplug(be, VSCSIBACK_OP_UPDATEDEV_STATE);
+
+		if (dev->state == XenbusStateConnected)
+			break;
+
+		xenbus_switch_state(dev, XenbusStateConnected);
+
+		break;
+
+	case XenbusStateClosing:
+		scsiback_disconnect(be->info);
+		xenbus_switch_state(dev, XenbusStateClosing);
+		break;
+
+	case XenbusStateClosed:
+		xenbus_switch_state(dev, XenbusStateClosed);
+		if (xenbus_dev_is_online(dev))
+			break;
+		/* fall through if not online */
+	case XenbusStateUnknown:
+		device_unregister(&dev->dev);
+		break;
+
+	case XenbusStateReconfiguring:
+		scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
+
+		xenbus_switch_state(dev, XenbusStateReconfigured);
+
+		break;
+
+	default:
+		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+					frontend_state);
+		break;
+	}
+}
+
+
+static int scsiback_remove(struct xenbus_device *dev)
+{
+	struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+	if (be->info) {
+		scsiback_disconnect(be->info);
+		scsiback_release_translation_entry(be->info);
+		scsiback_free(be->info);
+		be->info = NULL;
+	}
+
+	kfree(be);
+	dev_set_drvdata(&dev->dev, NULL);
+
+	return 0;
+}
+
+
+static int scsiback_probe(struct xenbus_device *dev,
+			   const struct xenbus_device_id *id)
+{
+	int err;
+	unsigned val = 0;
+
+	struct backend_info *be = kzalloc(sizeof(struct backend_info),
+					  GFP_KERNEL);
+
+	if (!be) {
+		xenbus_dev_fatal(dev, -ENOMEM,
+				 "allocating backend structure");
+		return -ENOMEM;
+	}
+	be->dev = dev;
+	dev_set_drvdata(&dev->dev, be);
+
+	be->info = vscsibk_info_alloc(dev->otherend_id);
+	if (IS_ERR(be->info)) {
+		err = PTR_ERR(be->info);
+		be->info = NULL;
+		xenbus_dev_fatal(dev, err, "creating scsihost interface");
+		goto fail;
+	}
+
+	be->info->dev = dev;
+	be->info->irq = 0;
+	be->info->feature = 0;	/*default not HOSTMODE.*/
+
+	scsiback_init_translation_table(be->info);
+
+	err = xenbus_scanf(XBT_NIL, dev->nodename,
+				"feature-host", "%d", &val);
+	if (XENBUS_EXIST_ERR(err))
+		val = 0;
+
+	if (val)
+		be->info->feature = VSCSI_TYPE_HOST;
+
+	err = xenbus_switch_state(dev, XenbusStateInitWait);
+	if (err)
+		goto fail;
+
+	return 0;
+
+
+fail:
+	printk(KERN_WARNING "scsiback: %s failed\n",__func__);
+	scsiback_remove(dev);
+
+	return err;
+}
+
+
+static struct xenbus_device_id scsiback_ids[] = {
+	{ "vscsi" },
+	{ "" }
+};
+
+static struct xenbus_driver scsiback = {
+	.name			= "vscsi",
+	.owner			= THIS_MODULE,
+	.ids			= scsiback_ids,
+	.probe			= scsiback_probe,
+	.remove			= scsiback_remove,
+	.otherend_changed	= scsiback_frontend_changed
+};
+
+int scsiback_xenbus_init(void)
+{
+	return xenbus_register_backend(&scsiback);
+}
+
+void scsiback_xenbus_unregister(void)
+{
+	xenbus_unregister_driver(&scsiback);
+}
diff --git a/drivers/scsi/xen-scsifront/Makefile b/drivers/scsi/xen-scsifront/Makefile
new file mode 100644
index 0000000..18a5329
--- /dev/null
+++ b/drivers/scsi/xen-scsifront/Makefile
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_XEN_SCSI_FRONTEND)	:= xen-scsifront.o
+xen-scsifront-objs := scsifront.o xenbus.o
+
diff --git a/drivers/scsi/xen-scsifront/common.h b/drivers/scsi/xen-scsifront/common.h
new file mode 100644
index 0000000..cfa1c32
--- /dev/null
+++ b/drivers/scsi/xen-scsifront/common.h
@@ -0,0 +1,137 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_DRIVERS_SCSIFRONT_H__
+#define __XEN_DRIVERS_SCSIFRONT_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <asm/xen/page.h>
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/evtchn.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/vscsiif.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/protocols.h>
+#include <asm/delay.h>
+#include <asm/hypervisor.h>
+/*#include <asm/maddr.h>*/
+
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
+#include <xen/platform-compat.h>
+#endif
+
+#define GRANT_INVALID_REF	0
+#define VSCSI_IN_ABORT		1
+#define VSCSI_IN_RESET		2
+
+/* tuning point*/
+#define VSCSIIF_DEFAULT_CMD_PER_LUN 10
+#define VSCSIIF_MAX_TARGET          64
+#define VSCSIIF_MAX_LUN             255
+
+#define VSCSIIF_RING_SIZE	__CONST_RING_SIZE(vscsiif, PAGE_SIZE)
+#define VSCSIIF_MAX_REQS	VSCSIIF_RING_SIZE
+
+struct vscsifrnt_shadow {
+	uint16_t next_free;
+
+	/* command between backend and frontend
+	 * VSCSIIF_ACT_SCSI_CDB or VSCSIIF_ACT_SCSI_RESET */
+	unsigned char act;
+
+	/* do reset function */
+	wait_queue_head_t wq_reset;	/* reset work queue           */
+	int wait_reset;			/* reset work queue condition */
+	int32_t rslt_reset;		/* reset response status      */
+					/* (SUCESS or FAILED)         */
+
+	/* for DMA_TO_DEVICE(1), DMA_FROM_DEVICE(2), DMA_NONE(3)
+	   requests */
+	unsigned int sc_data_direction;
+
+	/* Number of pieces of scatter-gather */
+	unsigned int nr_segments;
+
+	/* requested struct scsi_cmnd is stored from kernel */
+	unsigned long req_scsi_cmnd;
+	int gref[VSCSIIF_SG_TABLESIZE];
+};
+
+struct vscsifrnt_info {
+	struct xenbus_device *dev;
+
+	struct Scsi_Host *host;
+
+	spinlock_t io_lock;
+	spinlock_t shadow_lock;
+	unsigned int evtchn;
+	unsigned int irq;
+
+	grant_ref_t ring_ref;
+	struct vscsiif_front_ring ring;
+	struct vscsiif_response	ring_res;
+
+	struct vscsifrnt_shadow shadow[VSCSIIF_MAX_REQS];
+	uint32_t shadow_free;
+
+	struct task_struct *kthread;
+	wait_queue_head_t wq;
+	unsigned int waiting_resp;
+
+};
+
+#define DPRINTK(_f, _a...)				\
+	pr_debug("(file=%s, line=%d) " _f,	\
+		 __FILE__ , __LINE__ , ## _a )
+
+int scsifront_xenbus_init(void);
+void scsifront_xenbus_unregister(void);
+int scsifront_schedule(void *data);
+irqreturn_t scsifront_intr(int irq, void *dev_id);
+int scsifront_cmd_done(struct vscsifrnt_info *info);
+
+
+#endif /* __XEN_DRIVERS_SCSIFRONT_H__  */
diff --git a/drivers/scsi/xen-scsifront/scsifront.c b/drivers/scsi/xen-scsifront/scsifront.c
new file mode 100644
index 0000000..2d5e25f
--- /dev/null
+++ b/drivers/scsi/xen-scsifront/scsifront.c
@@ -0,0 +1,469 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include "common.h"
+
+static int get_id_from_freelist(struct vscsifrnt_info *info)
+{
+	unsigned long flags;
+	uint32_t free;
+
+	spin_lock_irqsave(&info->shadow_lock, flags);
+
+	free = info->shadow_free;
+	BUG_ON(free > VSCSIIF_MAX_REQS);
+	info->shadow_free = info->shadow[free].next_free;
+	info->shadow[free].next_free = 0x0fff;
+
+	info->shadow[free].wait_reset = 0;
+
+	spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+	return free;
+}
+
+static void add_id_to_freelist(struct vscsifrnt_info *info, uint32_t id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->shadow_lock, flags);
+
+	info->shadow[id].next_free  = info->shadow_free;
+	info->shadow[id].req_scsi_cmnd = 0;
+	info->shadow_free = id;
+
+	spin_unlock_irqrestore(&info->shadow_lock, flags);
+}
+
+
+struct vscsiif_request * scsifront_pre_request(struct vscsifrnt_info *info)
+{
+	struct vscsiif_front_ring *ring = &(info->ring);
+	vscsiif_request_t *ring_req;
+	uint32_t id;
+
+	ring_req = RING_GET_REQUEST(&(info->ring), ring->req_prod_pvt);
+
+	ring->req_prod_pvt++;
+
+	id = get_id_from_freelist(info);	/* use id by response */
+	ring_req->rqid = (uint16_t)id;
+
+	return ring_req;
+}
+
+
+static void scsifront_notify_work(struct vscsifrnt_info *info)
+{
+	info->waiting_resp = 1;
+	wake_up(&info->wq);
+}
+
+
+static void scsifront_do_request(struct vscsifrnt_info *info)
+{
+	struct vscsiif_front_ring *ring = &(info->ring);
+	unsigned int irq = info->irq;
+	int notify;
+
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
+	if (notify)
+		notify_remote_via_irq(irq);
+}
+
+irqreturn_t scsifront_intr(int irq, void *dev_id)
+{
+	scsifront_notify_work((struct vscsifrnt_info *)dev_id);
+	return IRQ_HANDLED;
+}
+
+
+static void scsifront_gnttab_done(struct vscsifrnt_shadow *s, uint32_t id)
+{
+	int i;
+
+	if (s->sc_data_direction == DMA_NONE)
+		return;
+
+	if (s->nr_segments) {
+		for (i = 0; i < s->nr_segments; i++) {
+			if (unlikely(gnttab_query_foreign_access(
+				s->gref[i]) != 0)) {
+				printk(KERN_ALERT "scsifront: "
+					"grant still in use by backend.\n");
+				BUG();
+			}
+			gnttab_end_foreign_access(s->gref[i], 0, 0UL);
+		}
+	}
+
+	return;
+}
+
+
+static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
+		       vscsiif_response_t *ring_res)
+{
+	struct scsi_cmnd *sc;
+	uint32_t id;
+	uint8_t sense_len;
+
+	id = ring_res->rqid;
+	sc = (struct scsi_cmnd *)info->shadow[id].req_scsi_cmnd;
+
+	if (sc == NULL)
+		BUG();
+
+	scsifront_gnttab_done(&info->shadow[id], id);
+	add_id_to_freelist(info, id);
+
+	sc->result = ring_res->rslt;
+	scsi_set_resid(sc, ring_res->residual_len);
+
+	if (ring_res->sense_len > VSCSIIF_SENSE_BUFFERSIZE)
+		sense_len = VSCSIIF_SENSE_BUFFERSIZE;
+	else
+		sense_len = ring_res->sense_len;
+
+	if (sense_len)
+		memcpy(sc->sense_buffer, ring_res->sense_buffer, sense_len);
+
+	sc->scsi_done(sc);
+
+	return;
+}
+
+
+static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
+				vscsiif_response_t *ring_res)
+{
+	uint16_t id = ring_res->rqid;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->shadow_lock, flags);
+	info->shadow[id].wait_reset = 1;
+	info->shadow[id].rslt_reset = ring_res->rslt;
+	spin_unlock_irqrestore(&info->shadow_lock, flags);
+
+	wake_up(&(info->shadow[id].wq_reset));
+}
+
+
+int scsifront_cmd_done(struct vscsifrnt_info *info)
+{
+	vscsiif_response_t *ring_res;
+
+	RING_IDX i, rp;
+	int more_to_do = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->io_lock, flags);
+
+	rp = info->ring.sring->rsp_prod;
+	rmb();
+	for (i = info->ring.rsp_cons; i != rp; i++) {
+
+		ring_res = RING_GET_RESPONSE(&info->ring, i);
+
+		if (info->shadow[ring_res->rqid].act == VSCSIIF_ACT_SCSI_CDB)
+			scsifront_cdb_cmd_done(info, ring_res);
+		else
+			scsifront_sync_cmd_done(info, ring_res);
+	}
+
+	info->ring.rsp_cons = i;
+
+	if (i != info->ring.req_prod_pvt) {
+		RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+	} else {
+		info->ring.sring->rsp_event = i + 1;
+	}
+
+	spin_unlock_irqrestore(&info->io_lock, flags);
+
+
+	/* Yield point for this unbounded loop. */
+	cond_resched();
+
+	return more_to_do;
+}
+
+
+
+
+int scsifront_schedule(void *data)
+{
+	struct vscsifrnt_info *info = (struct vscsifrnt_info *)data;
+
+	while (!kthread_should_stop()) {
+		wait_event_interruptible(
+			info->wq,
+			info->waiting_resp || kthread_should_stop());
+
+		info->waiting_resp = 0;
+		smp_mb();
+
+		if (scsifront_cmd_done(info))
+			info->waiting_resp = 1;
+	}
+
+	return 0;
+}
+
+
+
+static int map_data_for_request(struct vscsifrnt_info *info,
+		struct scsi_cmnd *sc, vscsiif_request_t *ring_req, uint32_t id)
+{
+	grant_ref_t gref_head;
+	int err, ref, ref_cnt = 0;
+	int write = (sc->sc_data_direction == DMA_TO_DEVICE);
+	unsigned int i, nr_pages, off, len, bytes;
+	unsigned long buffer_mfn, buffer_pfn;
+
+	if (sc->sc_data_direction == DMA_NONE)
+		return 0;
+
+	err = gnttab_alloc_grant_references(VSCSIIF_SG_TABLESIZE, &gref_head);
+	if (err) {
+		printk(KERN_ERR "scsifront: gnttab_alloc_grant_references() error\n");
+		return -ENOMEM;
+	}
+
+	if (scsi_bufflen(sc)) {
+		/* quoted scsi_lib.c/scsi_req_map_sg . */
+		struct scatterlist *sg, *sgl = scsi_sglist(sc);
+		unsigned int data_len = scsi_bufflen(sc);
+
+		nr_pages = (data_len + sgl->offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+		if (nr_pages > VSCSIIF_SG_TABLESIZE) {
+			printk(KERN_ERR "scsifront: Unable to map request_buffer for command!\n");
+			ref_cnt = (-E2BIG);
+			goto big_to_sg;
+		}
+
+		for_each_sg (sgl, sg, scsi_sg_count(sc), i) {
+			off = sg->offset;
+			len = sg->length;
+
+			buffer_pfn = page_to_pfn(sg_page(sg));
+			while (len > 0 && data_len > 0) {
+				/*
+				 * sg sends a scatterlist that is larger than
+				 * the data_len it wants transferred for certain
+				 * IO sizes
+				 */
+				bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+				bytes = min(bytes, data_len);
+
+				ref = gnttab_claim_grant_reference(&gref_head);
+				BUG_ON(ref == -ENOSPC);
+
+				buffer_mfn = pfn_to_mfn(buffer_pfn);
+				gnttab_grant_foreign_access_ref(ref, info->dev->otherend_id,
+					buffer_mfn, write);
+
+				info->shadow[id].gref[ref_cnt]  = ref;
+				ring_req->seg[ref_cnt].gref     = ref;
+				ring_req->seg[ref_cnt].offset   = (uint16_t)off;
+				ring_req->seg[ref_cnt].length   = (uint16_t)bytes;
+
+				buffer_pfn ++;
+				len -= bytes;
+				data_len -= bytes;
+				off = 0;
+				ref_cnt++;
+			}
+		}
+	}
+
+big_to_sg:
+
+	gnttab_free_grant_references(gref_head);
+
+	return ref_cnt;
+}
+
+static int scsifront_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *sc)
+{
+	struct vscsifrnt_info *info =
+		(struct vscsifrnt_info *) sc->device->host->hostdata;
+	vscsiif_request_t *ring_req;
+	int ref_cnt;
+	uint16_t rqid;
+
+	if (RING_FULL(&info->ring)) {
+		goto out_host_busy;
+	}
+
+	sc->result    = 0;
+
+	ring_req          = scsifront_pre_request(info);
+	rqid              = ring_req->rqid;
+	ring_req->act     = VSCSIIF_ACT_SCSI_CDB;
+
+	ring_req->id      = sc->device->id;
+	ring_req->lun     = sc->device->lun;
+	ring_req->channel = sc->device->channel;
+	ring_req->cmd_len = sc->cmd_len;
+
+	BUG_ON(sc->cmd_len > VSCSIIF_MAX_COMMAND_SIZE);
+
+	if (sc->cmd_len)
+		memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+	else
+		memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
+
+	ring_req->sc_data_direction   = (uint8_t)sc->sc_data_direction;
+	ring_req->timeout_per_command = (sc->request->timeout / HZ);
+
+	info->shadow[rqid].req_scsi_cmnd     = (unsigned long)sc;
+	info->shadow[rqid].sc_data_direction = sc->sc_data_direction;
+	info->shadow[rqid].act               = ring_req->act;
+
+	ref_cnt = map_data_for_request(info, sc, ring_req, rqid);
+	if (ref_cnt < 0) {
+		add_id_to_freelist(info, rqid);
+		if (ref_cnt == (-ENOMEM))
+			goto out_host_busy;
+		else {
+			sc->result = (DID_ERROR << 16);
+			goto out_fail_command;
+		}
+	}
+
+	ring_req->nr_segments          = (uint8_t)ref_cnt;
+	info->shadow[rqid].nr_segments = ref_cnt;
+
+	scsifront_do_request(info);
+
+	return 0;
+
+out_host_busy:
+	return SCSI_MLQUEUE_HOST_BUSY;
+
+out_fail_command:
+	sc->scsi_done(sc);
+	return 0;
+}
+
+
+static int scsifront_eh_abort_handler(struct scsi_cmnd *sc)
+{
+	return (FAILED);
+}
+
+/* vscsi supports only device_reset, because it is each of LUNs */
+static int scsifront_dev_reset_handler(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct vscsifrnt_info *info =
+		(struct vscsifrnt_info *) sc->device->host->hostdata;
+
+	vscsiif_request_t *ring_req;
+	uint16_t rqid;
+	int err;
+
+	spin_lock_irq(host->host_lock);
+
+	ring_req      = scsifront_pre_request(info);
+	ring_req->act = VSCSIIF_ACT_SCSI_RESET;
+
+	rqid          = ring_req->rqid;
+	info->shadow[rqid].act = VSCSIIF_ACT_SCSI_RESET;
+
+	ring_req->channel = sc->device->channel;
+	ring_req->id      = sc->device->id;
+	ring_req->lun     = sc->device->lun;
+	ring_req->cmd_len = sc->cmd_len;
+
+	if ( sc->cmd_len )
+		memcpy(ring_req->cmnd, sc->cmnd, sc->cmd_len);
+	else
+		memset(ring_req->cmnd, 0, VSCSIIF_MAX_COMMAND_SIZE);
+
+	ring_req->sc_data_direction   = (uint8_t)sc->sc_data_direction;
+	ring_req->timeout_per_command = (sc->request->timeout / HZ);
+	ring_req->nr_segments         = 0;
+
+	scsifront_do_request(info);
+
+	spin_unlock_irq(host->host_lock);
+	wait_event_interruptible(info->shadow[rqid].wq_reset,
+			 info->shadow[rqid].wait_reset);
+	spin_lock_irq(host->host_lock);
+
+	err = info->shadow[rqid].rslt_reset;
+
+	add_id_to_freelist(info, rqid);
+
+	spin_unlock_irq(host->host_lock);
+	return (err);
+}
+
+
+struct scsi_host_template scsifront_sht = {
+	.module			= THIS_MODULE,
+	.name			= "Xen SCSI frontend driver",
+	.queuecommand		= scsifront_queuecommand,
+	.eh_abort_handler	= scsifront_eh_abort_handler,
+	.eh_device_reset_handler= scsifront_dev_reset_handler,
+	.cmd_per_lun		= VSCSIIF_DEFAULT_CMD_PER_LUN,
+	.can_queue		= VSCSIIF_MAX_REQS,
+	.this_id 		= -1,
+	.sg_tablesize		= VSCSIIF_SG_TABLESIZE,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "scsifront",
+};
+
+
+static int __init scsifront_init(void)
+{
+	int err;
+
+	if (!xen_domain())
+		return -ENODEV;
+
+	err = scsifront_xenbus_init();
+
+	return err;
+}
+
+static void __exit scsifront_exit(void)
+{
+	scsifront_xenbus_unregister();
+}
+
+module_init(scsifront_init);
+module_exit(scsifront_exit);
+
+MODULE_DESCRIPTION("Xen SCSI frontend driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/xen-scsifront/xenbus.c b/drivers/scsi/xen-scsifront/xenbus.c
new file mode 100644
index 0000000..3b9f04a
--- /dev/null
+++ b/drivers/scsi/xen-scsifront/xenbus.c
@@ -0,0 +1,414 @@
+/*
+ * Xen SCSI frontend driver
+ *
+ * Copyright (c) 2008, FUJITSU Limited
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/version.h>
+#include "common.h"
+
+extern struct scsi_host_template scsifront_sht;
+
+static void scsifront_free(struct vscsifrnt_info *info)
+{
+	struct Scsi_Host *host = info->host;
+
+	if (host->shost_state != SHOST_DEL)
+		scsi_remove_host(info->host);
+
+	if (info->ring_ref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->ring_ref,
+					0, (unsigned long)info->ring.sring);
+		info->ring_ref = GRANT_INVALID_REF;
+		info->ring.sring = NULL;
+	}
+
+	if (info->irq)
+		unbind_from_irqhandler(info->irq, info);
+	info->irq = 0;
+
+	scsi_host_put(info->host);
+}
+
+
+static int scsifront_alloc_ring(struct vscsifrnt_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct vscsiif_sring *sring;
+	int err = -ENOMEM;
+
+
+	info->ring_ref = GRANT_INVALID_REF;
+
+	/***** Frontend to Backend ring start *****/
+	sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL);
+	if (!sring) {
+		xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)");
+		return err;
+	}
+	SHARED_RING_INIT(sring);
+	FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(sring));
+	if (err < 0) {
+		free_page((unsigned long) sring);
+		info->ring.sring = NULL;
+		xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)");
+		goto free_sring;
+	}
+	info->ring_ref = err;
+
+	err = xenbus_alloc_evtchn(dev, &info->evtchn);
+	if (err)
+		goto free_sring;
+
+	err = bind_evtchn_to_irqhandler(
+			info->evtchn, scsifront_intr,
+			IRQF_SAMPLE_RANDOM, "scsifront", info);
+
+	if (err <= 0) {
+		xenbus_dev_fatal(dev, err, "bind_evtchn_to_irqhandler");
+		goto free_sring;
+	}
+	info->irq = err;
+
+	return 0;
+
+/* free resource */
+free_sring:
+	scsifront_free(info);
+
+	return err;
+}
+
+
+static int scsifront_init_ring(struct vscsifrnt_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct xenbus_transaction xbt;
+	int err;
+
+	DPRINTK("%s\n",__FUNCTION__);
+
+	err = scsifront_alloc_ring(info);
+	if (err)
+		return err;
+	DPRINTK("%u %u\n", info->ring_ref, info->evtchn);
+
+again:
+	err = xenbus_transaction_start(&xbt);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "starting transaction");
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
+				info->ring_ref);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
+		goto fail;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
+				info->evtchn);
+
+	if (err) {
+		xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
+		goto fail;
+	}
+
+	err = xenbus_transaction_end(xbt, 0);
+	if (err) {
+		if (err == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, err, "completing transaction");
+		goto free_sring;
+	}
+
+	return 0;
+
+fail:
+	xenbus_transaction_end(xbt, 1);
+free_sring:
+	/* free resource */
+	scsifront_free(info);
+
+	return err;
+}
+
+
+static int scsifront_probe(struct xenbus_device *dev,
+				const struct xenbus_device_id *id)
+{
+	struct vscsifrnt_info *info;
+	struct Scsi_Host *host;
+	int i, err = -ENOMEM;
+	char name[TASK_COMM_LEN];
+
+	host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
+	if (!host) {
+		xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
+		return err;
+	}
+	info = (struct vscsifrnt_info *) host->hostdata;
+	info->host = host;
+
+
+	dev_set_drvdata(&dev->dev, info);
+	info->dev  = dev;
+
+	for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
+		info->shadow[i].next_free = i + 1;
+		init_waitqueue_head(&(info->shadow[i].wq_reset));
+		info->shadow[i].wait_reset = 0;
+	}
+	info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff;
+
+	err = scsifront_init_ring(info);
+	if (err) {
+		scsi_host_put(host);
+		return err;
+	}
+
+	init_waitqueue_head(&info->wq);
+	spin_lock_init(&info->io_lock);
+	spin_lock_init(&info->shadow_lock);
+
+	snprintf(name, TASK_COMM_LEN, "vscsiif.%d", info->host->host_no);
+
+	info->kthread = kthread_run(scsifront_schedule, info, name);
+	if (IS_ERR(info->kthread)) {
+		err = PTR_ERR(info->kthread);
+		info->kthread = NULL;
+		printk(KERN_ERR "scsifront: kthread start err %d\n", err);
+		goto free_sring;
+	}
+
+	host->max_id      = VSCSIIF_MAX_TARGET;
+	host->max_channel = 0;
+	host->max_lun     = VSCSIIF_MAX_LUN;
+	host->max_sectors = (VSCSIIF_SG_TABLESIZE - 1) * PAGE_SIZE / 512;
+	host->max_cmd_len = VSCSIIF_MAX_COMMAND_SIZE;
+
+	err = scsi_add_host(host, &dev->dev);
+	if (err) {
+		printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
+		goto free_sring;
+	}
+
+	xenbus_switch_state(dev, XenbusStateInitialised);
+
+	return 0;
+
+free_sring:
+	/* free resource */
+	scsifront_free(info);
+	return err;
+}
+
+static int scsifront_remove(struct xenbus_device *dev)
+{
+	struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
+
+	DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
+
+	if (info->kthread) {
+		kthread_stop(info->kthread);
+		info->kthread = NULL;
+	}
+
+	scsifront_free(info);
+
+	return 0;
+}
+
+
+static int scsifront_disconnect(struct vscsifrnt_info *info)
+{
+	struct xenbus_device *dev = info->dev;
+	struct Scsi_Host *host = info->host;
+
+	DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename);
+
+	/*
+	  When this function is executed,  all devices of
+	  Frontend have been deleted.
+	  Therefore, it need not block I/O before remove_host.
+	*/
+
+	scsi_remove_host(host);
+	xenbus_frontend_closed(dev);
+
+	return 0;
+}
+
+#define VSCSIFRONT_OP_ADD_LUN	1
+#define VSCSIFRONT_OP_DEL_LUN	2
+
+static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
+{
+	struct xenbus_device *dev = info->dev;
+	int i, err = 0;
+	char str[64], state_str[64];
+	char **dir;
+	unsigned int dir_n = 0;
+	unsigned int device_state;
+	unsigned int hst, chn, tgt, lun;
+	struct scsi_device *sdev;
+
+	dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
+	if (IS_ERR(dir))
+		return;
+
+	for (i = 0; i < dir_n; i++) {
+		/* read status */
+		snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]);
+		err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u",
+			&device_state);
+		if (XENBUS_EXIST_ERR(err))
+			continue;
+
+		/* virtual SCSI device */
+		snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
+		err = xenbus_scanf(XBT_NIL, dev->otherend, str,
+			"%u:%u:%u:%u", &hst, &chn, &tgt, &lun);
+		if (XENBUS_EXIST_ERR(err))
+			continue;
+
+		/* front device state path */
+		snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
+
+		switch (op) {
+		case VSCSIFRONT_OP_ADD_LUN:
+			if (device_state == XenbusStateInitialised) {
+				sdev = scsi_device_lookup(info->host, chn, tgt, lun);
+				if (sdev) {
+					printk(KERN_ERR "scsifront: Device already in use.\n");
+					scsi_device_put(sdev);
+					xenbus_printf(XBT_NIL, dev->nodename,
+						state_str, "%d", XenbusStateClosed);
+				} else {
+					scsi_add_device(info->host, chn, tgt, lun);
+					xenbus_printf(XBT_NIL, dev->nodename,
+						state_str, "%d", XenbusStateConnected);
+				}
+			}
+			break;
+		case VSCSIFRONT_OP_DEL_LUN:
+			if (device_state == XenbusStateClosing) {
+				sdev = scsi_device_lookup(info->host, chn, tgt, lun);
+				if (sdev) {
+					scsi_remove_device(sdev);
+					scsi_device_put(sdev);
+					xenbus_printf(XBT_NIL, dev->nodename,
+						state_str, "%d", XenbusStateClosed);
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	kfree(dir);
+	return;
+}
+
+
+
+
+static void scsifront_backend_changed(struct xenbus_device *dev,
+				enum xenbus_state backend_state)
+{
+	struct vscsifrnt_info *info = dev_get_drvdata(&dev->dev);
+
+	DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
+
+	switch (backend_state) {
+	case XenbusStateUnknown:
+	case XenbusStateInitialising:
+	case XenbusStateInitWait:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateConnected:
+		if (xenbus_read_driver_state(dev->nodename) ==
+			XenbusStateInitialised) {
+			scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+		}
+
+		if (dev->state == XenbusStateConnected)
+			break;
+
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		scsifront_disconnect(info);
+		break;
+
+	case XenbusStateReconfiguring:
+		scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN);
+		xenbus_switch_state(dev, XenbusStateReconfiguring);
+		break;
+
+	case XenbusStateReconfigured:
+		scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+	}
+}
+
+
+static struct xenbus_device_id scsifront_ids[] = {
+	{ "vscsi" },
+	{ "" }
+};
+MODULE_ALIAS("xen:vscsi");
+
+static struct xenbus_driver scsifront_driver = {
+	.name			= "vscsi",
+	.owner			= THIS_MODULE,
+	.ids			= scsifront_ids,
+	.probe			= scsifront_probe,
+	.remove			= scsifront_remove,
+/* 	.resume			= scsifront_resume, */
+	.otherend_changed	= scsifront_backend_changed,
+};
+
+int scsifront_xenbus_init(void)
+{
+	return xenbus_register_frontend(&scsifront_driver);
+}
+
+void scsifront_xenbus_unregister(void)
+{
+	xenbus_unregister_driver(&scsifront_driver);
+}
+
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
index 39e5717..ef2b377 100644
--- a/include/xen/interface/grant_table.h
+++ b/include/xen/interface/grant_table.h
@@ -363,6 +363,8 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size);
 #define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
 #define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
 #define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
+#define GNTST_address_too_big (-11) /* transfer page address too large.      */
+#define GNTST_eagain          (-12) /* Could not map at the moment. Retry.   */
 
 #define GNTTABOP_error_msgs {                   \
     "okay",                                     \
@@ -376,6 +378,8 @@ DEFINE_GUEST_HANDLE_STRUCT(gnttab_query_size);
     "permission denied",                        \
     "bad page",                                 \
     "copy arguments cross page boundary"        \
+    "page address size too large",              \
+    "could not map at the moment, retry"        \
 }
 
 #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/include/xen/interface/io/vscsiif.h b/include/xen/interface/io/vscsiif.h
new file mode 100644
index 0000000..7fbe688
--- /dev/null
+++ b/include/xen/interface/io/vscsiif.h
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * vscsiif.h
+ *
+ * Based on the blkif.h code.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright(c) FUJITSU Limited 2008.
+ */
+
+#ifndef __XEN__PUBLIC_IO_SCSI_H__
+#define __XEN__PUBLIC_IO_SCSI_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/* command between backend and frontend */
+#define VSCSIIF_ACT_SCSI_CDB         1    /* SCSI CDB command */
+#define VSCSIIF_ACT_SCSI_ABORT       2    /* SCSI Device(Lun) Abort*/
+#define VSCSIIF_ACT_SCSI_RESET       3    /* SCSI Device(Lun) Reset*/
+
+
+#define VSCSIIF_BACK_MAX_PENDING_REQS    128
+
+/*
+ * Maximum scatter/gather segments per request.
+ *
+ * Considering balance between allocating al least 16 "vscsiif_request"
+ * structures on one page (4096bytes) and number of scatter gather
+ * needed, we decided to use 26 as a magic number.
+ */
+#define VSCSIIF_SG_TABLESIZE             26
+
+/*
+ * base on linux kernel 2.6.18
+ */
+#define VSCSIIF_MAX_COMMAND_SIZE         16
+#define VSCSIIF_SENSE_BUFFERSIZE         96
+
+
+struct vscsiif_request {
+    uint16_t rqid;          /* private guest value, echoed in resp  */
+    uint8_t act;            /* command between backend and frontend */
+    uint8_t cmd_len;
+
+    uint8_t cmnd[VSCSIIF_MAX_COMMAND_SIZE];
+    uint16_t timeout_per_command;     /* The command is issued by twice
+                                         the value in Backend. */
+    uint16_t channel, id, lun;
+    uint16_t padding;
+    uint8_t sc_data_direction;        /* for DMA_TO_DEVICE(1)
+                                         DMA_FROM_DEVICE(2)
+                                         DMA_NONE(3) requests  */
+    uint8_t nr_segments;              /* Number of pieces of scatter-gather */
+
+    struct scsiif_request_segment {
+        grant_ref_t gref;
+        uint16_t offset;
+        uint16_t length;
+    } seg[VSCSIIF_SG_TABLESIZE];
+    uint32_t reserved[3];
+};
+typedef struct vscsiif_request vscsiif_request_t;
+
+struct vscsiif_response {
+    uint16_t rqid;
+    uint8_t padding;
+    uint8_t sense_len;
+    uint8_t sense_buffer[VSCSIIF_SENSE_BUFFERSIZE];
+    int32_t rslt;
+    uint32_t residual_len;     /* request bufflen -
+                                  return the value from physical device */
+    uint32_t reserved[36];
+};
+typedef struct vscsiif_response vscsiif_response_t;
+
+DEFINE_RING_TYPES(vscsiif, struct vscsiif_request, struct vscsiif_response);
+
+
+#endif  /*__XEN__PUBLIC_IO_SCSI_H__*/
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

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

--3MwIy2ne0vdjdPXF--


