diff --git a/25833-32on64-bogus-pt_base-adjust.patch b/25833-32on64-bogus-pt_base-adjust.patch new file mode 100644 index 0000000..2035d2c --- /dev/null +++ b/25833-32on64-bogus-pt_base-adjust.patch @@ -0,0 +1,61 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347022899 -7200 +# Node ID bb85bbccb1c9d802c92dd3fe00841368966ff623 +# Parent e3b51948114ec1e2b2eece415b32e26ff857acde +x86/32-on-64: adjust Dom0 initial page table layout + +Drop the unnecessary reservation of the L4 page for 32on64 Dom0, and +allocate its L3 first (to match behavior when running identical bit- +width hypervisor and Dom0 kernel). + +Reported-by: Konrad Rzeszutek Wilk +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/arch/x86/domain_build.c ++++ b/xen/arch/x86/domain_build.c +@@ -510,7 +510,7 @@ int __init construct_dom0( + #define NR(_l,_h,_s) \ + (((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \ + ((_l) & ~((1UL<<(_s))-1))) >> (_s)) +- if ( (1 + /* # L4 */ ++ if ( (!is_pv_32on64_domain(d) + /* # L4 */ + NR(v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */ + (!is_pv_32on64_domain(d) ? + NR(v_start, v_end, L3_PAGETABLE_SHIFT) : /* # L2 */ +@@ -756,6 +756,8 @@ int __init construct_dom0( + panic("Not enough RAM for domain 0 PML4.\n"); + page->u.inuse.type_info = PGT_l4_page_table|PGT_validated|1; + l4start = l4tab = page_to_virt(page); ++ maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l3_page_table; ++ l3start = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; + } + copy_page(l4tab, idle_pg_table); + l4tab[0] = l4e_empty(); /* zap trampoline mapping */ +@@ -787,9 +789,13 @@ int __init construct_dom0( + l2tab += l2_table_offset(v_start); + if ( !((unsigned long)l3tab & (PAGE_SIZE-1)) ) + { +- maddr_to_page(mpt_alloc)->u.inuse.type_info = +- PGT_l3_page_table; +- l3start = l3tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; ++ if ( count || !l3start ) ++ { ++ maddr_to_page(mpt_alloc)->u.inuse.type_info = ++ PGT_l3_page_table; ++ l3start = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; ++ } ++ l3tab = l3start; + clear_page(l3tab); + if ( count == 0 ) + l3tab += l3_table_offset(v_start); +@@ -938,7 +944,7 @@ int __init construct_dom0( + if ( !vinitrd_start && initrd_len ) + si->flags |= SIF_MOD_START_PFN; + si->flags |= (xen_processor_pmbits << 8) & SIF_PM_MASK; +- si->pt_base = vpt_start + 2 * PAGE_SIZE * !!is_pv_32on64_domain(d); ++ si->pt_base = vpt_start; + si->nr_pt_frames = nr_pt_pages; + si->mfn_list = vphysmap_start; + snprintf(si->magic, sizeof(si->magic), "xen-3.0-x86_%d%s", diff --git a/25835-adjust-rcu-lock-domain.patch b/25835-adjust-rcu-lock-domain.patch new file mode 100644 index 0000000..57876dd --- /dev/null +++ b/25835-adjust-rcu-lock-domain.patch @@ -0,0 +1,274 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347033492 -7200 +# Node ID c70d70d85306b3e4a0538353be131100c5ee38d5 +# Parent 0376c85caaf34fe3cc8c3327f7a1d9ecd6f070b4 +adjust a few RCU domain locking calls + +x86's do_physdev_op() had a case where the locking was entirely +superfluous. Its physdev_map_pirq() further had a case where the lock +was being obtained too early, needlessly complicating early exit paths. + +Grant table code had two open coded instances of +rcu_lock_target_domain_by_id(), and a third code section could be +consolidated by using the newly introduced helper function. + +The memory hypercall code had two more instances of open coding +rcu_lock_target_domain_by_id(), but note that here this is not just +cleanup, but also fixes an error return path in memory_exchange() to +actually return an error. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/arch/x86/physdev.c ++++ b/xen/arch/x86/physdev.c +@@ -90,14 +90,10 @@ static int physdev_hvm_map_pirq( + int physdev_map_pirq(domid_t domid, int type, int *index, int *pirq_p, + struct msi_info *msi) + { +- struct domain *d; ++ struct domain *d = current->domain; + int pirq, irq, ret = 0; + void *map_data = NULL; + +- ret = rcu_lock_target_domain_by_id(domid, &d); +- if ( ret ) +- return ret; +- + if ( domid == DOMID_SELF && is_hvm_domain(d) ) + { + /* +@@ -105,14 +101,15 @@ int physdev_map_pirq(domid_t domid, int + * calls back into itself and deadlocks on hvm_domain.irq_lock. + */ + if ( !is_hvm_pv_evtchn_domain(d) ) +- { +- ret = -EINVAL; +- goto free_domain; +- } +- ret = physdev_hvm_map_pirq(d, type, index, pirq_p); +- goto free_domain; ++ return -EINVAL; ++ ++ return physdev_hvm_map_pirq(d, type, index, pirq_p); + } + ++ ret = rcu_lock_target_domain_by_id(domid, &d); ++ if ( ret ) ++ return ret; ++ + if ( !IS_PRIV_FOR(current->domain, d) ) + { + ret = -EPERM; +@@ -696,13 +693,12 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H + } + case PHYSDEVOP_get_free_pirq: { + struct physdev_get_free_pirq out; +- struct domain *d; ++ struct domain *d = v->domain; + + ret = -EFAULT; + if ( copy_from_guest(&out, arg, 1) != 0 ) + break; + +- d = rcu_lock_current_domain(); + spin_lock(&d->event_lock); + + ret = get_free_pirq(d, out.type); +@@ -717,7 +713,6 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H + } + + spin_unlock(&d->event_lock); +- rcu_unlock_domain(d); + + if ( ret >= 0 ) + { +--- a/xen/common/grant_table.c ++++ b/xen/common/grant_table.c +@@ -24,7 +24,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-#include ++#include + #include + #include + #include +@@ -195,6 +195,30 @@ double_gt_unlock(struct grant_table *lgt + spin_unlock(&rgt->lock); + } + ++static struct domain *gt_lock_target_domain_by_id(domid_t dom) ++{ ++ struct domain *d; ++ int rc = GNTST_general_error; ++ ++ switch ( rcu_lock_target_domain_by_id(dom, &d) ) ++ { ++ case 0: ++ return d; ++ ++ case -ESRCH: ++ gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); ++ rc = GNTST_bad_domain; ++ break; ++ ++ case -EPERM: ++ rc = GNTST_permission_denied; ++ break; ++ } ++ ++ ASSERT(rc < 0 && -rc <= MAX_ERRNO); ++ return ERR_PTR(rc); ++} ++ + static inline int + __get_maptrack_handle( + struct grant_table *t) +@@ -1261,7 +1285,6 @@ gnttab_setup_table( + struct grant_table *gt; + int i; + unsigned long gmfn; +- domid_t dom; + + if ( count != 1 ) + return -EINVAL; +@@ -1281,25 +1304,11 @@ gnttab_setup_table( + goto out1; + } + +- dom = op.dom; +- if ( dom == DOMID_SELF ) ++ d = gt_lock_target_domain_by_id(op.dom); ++ if ( IS_ERR(d) ) + { +- d = rcu_lock_current_domain(); +- } +- else +- { +- if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) +- { +- gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); +- op.status = GNTST_bad_domain; +- goto out1; +- } +- +- if ( unlikely(!IS_PRIV_FOR(current->domain, d)) ) +- { +- op.status = GNTST_permission_denied; +- goto out2; +- } ++ op.status = PTR_ERR(d); ++ goto out1; + } + + if ( xsm_grant_setup(current->domain, d) ) +@@ -1352,7 +1361,6 @@ gnttab_query_size( + { + struct gnttab_query_size op; + struct domain *d; +- domid_t dom; + int rc; + + if ( count != 1 ) +@@ -1364,25 +1372,11 @@ gnttab_query_size( + return -EFAULT; + } + +- dom = op.dom; +- if ( dom == DOMID_SELF ) +- { +- d = rcu_lock_current_domain(); +- } +- else ++ d = gt_lock_target_domain_by_id(op.dom); ++ if ( IS_ERR(d) ) + { +- if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) +- { +- gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom); +- op.status = GNTST_bad_domain; +- goto query_out; +- } +- +- if ( unlikely(!IS_PRIV_FOR(current->domain, d)) ) +- { +- op.status = GNTST_permission_denied; +- goto query_out_unlock; +- } ++ op.status = PTR_ERR(d); ++ goto query_out; + } + + rc = xsm_grant_query_size(current->domain, d); +@@ -2251,15 +2245,10 @@ gnttab_get_status_frames(XEN_GUEST_HANDL + return -EFAULT; + } + +- rc = rcu_lock_target_domain_by_id(op.dom, &d); +- if ( rc < 0 ) ++ d = gt_lock_target_domain_by_id(op.dom); ++ if ( IS_ERR(d) ) + { +- if ( rc == -ESRCH ) +- op.status = GNTST_bad_domain; +- else if ( rc == -EPERM ) +- op.status = GNTST_permission_denied; +- else +- op.status = GNTST_general_error; ++ op.status = PTR_ERR(d); + goto out1; + } + rc = xsm_grant_setup(current->domain, d); +--- a/xen/common/memory.c ++++ b/xen/common/memory.c +@@ -329,22 +329,9 @@ static long memory_exchange(XEN_GUEST_HA + out_chunk_order = exch.in.extent_order - exch.out.extent_order; + } + +- if ( likely(exch.in.domid == DOMID_SELF) ) +- { +- d = rcu_lock_current_domain(); +- } +- else +- { +- if ( (d = rcu_lock_domain_by_id(exch.in.domid)) == NULL ) +- goto fail_early; +- +- if ( !IS_PRIV_FOR(current->domain, d) ) +- { +- rcu_unlock_domain(d); +- rc = -EPERM; +- goto fail_early; +- } +- } ++ rc = rcu_lock_target_domain_by_id(exch.in.domid, &d); ++ if ( rc ) ++ goto fail_early; + + memflags |= MEMF_bits(domain_clamp_alloc_bitsize( + d, +@@ -583,20 +570,8 @@ long do_memory_op(unsigned long cmd, XEN + && (reservation.mem_flags & XENMEMF_populate_on_demand) ) + args.memflags |= MEMF_populate_on_demand; + +- if ( likely(reservation.domid == DOMID_SELF) ) +- { +- d = rcu_lock_current_domain(); +- } +- else +- { +- if ( (d = rcu_lock_domain_by_id(reservation.domid)) == NULL ) +- return start_extent; +- if ( !IS_PRIV_FOR(current->domain, d) ) +- { +- rcu_unlock_domain(d); +- return start_extent; +- } +- } ++ if ( unlikely(rcu_lock_target_domain_by_id(reservation.domid, &d)) ) ++ return start_extent; + args.domain = d; + + rc = xsm_memory_adjust_reservation(current->domain, d); diff --git a/25836-VT-d-S3-MSI-resume.patch b/25836-VT-d-S3-MSI-resume.patch new file mode 100644 index 0000000..0539c74 --- /dev/null +++ b/25836-VT-d-S3-MSI-resume.patch @@ -0,0 +1,52 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347263130 -7200 +# Node ID 7d216f026f71022186196a75244e97cf3864f50b +# Parent c70d70d85306b3e4a0538353be131100c5ee38d5 +VT-d: split .ack and .disable DMA-MSI actors + +Calling irq_complete_move() from .disable is wrong, breaking S3 resume. + +Comparing with all other .ack actors, it was also missing a call to +move_{native,masked}_irq(). As the actor is masking its interrupt +anyway (albeit it's not immediately obvious why), the latter is the +better choice. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser +Acked-by Xiantao Zhang + +--- a/xen/drivers/passthrough/vtd/iommu.c ++++ b/xen/drivers/passthrough/vtd/iommu.c +@@ -1040,8 +1040,6 @@ static void dma_msi_mask(struct irq_desc + unsigned long flags; + struct iommu *iommu = desc->action->dev_id; + +- irq_complete_move(desc); +- + /* mask it */ + spin_lock_irqsave(&iommu->register_lock, flags); + dmar_writel(iommu->reg, DMAR_FECTL_REG, DMA_FECTL_IM); +@@ -1054,6 +1052,13 @@ static unsigned int dma_msi_startup(stru + return 0; + } + ++static void dma_msi_ack(struct irq_desc *desc) ++{ ++ irq_complete_move(desc); ++ dma_msi_mask(desc); ++ move_masked_irq(desc); ++} ++ + static void dma_msi_end(struct irq_desc *desc, u8 vector) + { + dma_msi_unmask(desc); +@@ -1115,7 +1120,7 @@ static hw_irq_controller dma_msi_type = + .shutdown = dma_msi_mask, + .enable = dma_msi_unmask, + .disable = dma_msi_mask, +- .ack = dma_msi_mask, ++ .ack = dma_msi_ack, + .end = dma_msi_end, + .set_affinity = dma_msi_set_affinity, + }; diff --git a/25850-tmem-xsa-15-1.patch b/25850-tmem-xsa-15-1.patch new file mode 100644 index 0000000..77dcc6e --- /dev/null +++ b/25850-tmem-xsa-15-1.patch @@ -0,0 +1,27 @@ +# HG changeset patch +# User Ian Campbell +# Date 1347365190 -7200 +# Node ID 0dba5a8886556f1b92e59eb19c570ad1704037f6 +# Parent 90533f3b6babfda56edbbefda47c46b391204132 +tmem: only allow tmem control operations from privileged domains + +This is part of XSA-15 / CVE-2012-3497. + +Signed-off-by: Ian Campbell +Committed-by: Jan Beulich + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -2541,10 +2541,8 @@ static NOINLINE int do_tmem_control(stru + OID *oidp = (OID *)(&op->u.ctrl.oid[0]); + + if (!tmh_current_is_privileged()) +- { +- /* don't fail... mystery: sometimes dom0 fails here */ +- /* return -EPERM; */ +- } ++ return -EPERM; ++ + switch(subop) + { + case TMEMC_THAW: diff --git a/25851-tmem-xsa-15-2.patch b/25851-tmem-xsa-15-2.patch new file mode 100644 index 0000000..8824f6f --- /dev/null +++ b/25851-tmem-xsa-15-2.patch @@ -0,0 +1,45 @@ +# HG changeset patch +# User Ian Campbell +# Date 1347365203 -7200 +# Node ID fcf567acc92ae57f4adfbe967b01a2ba0390c08f +# Parent 0dba5a8886556f1b92e59eb19c570ad1704037f6 +tmem: consistently make pool_id a uint32_t + +Treating it as an int could allow a malicious guest to provide a +negative pool_Id, by passing the MAX_POOLS_PER_DOMAIN limit check and +allowing access to the negative offsets of the pool array. + +This is part of XSA-15 / CVE-2012-3497. + +Signed-off-by: Ian Campbell +Committed-by: Jan Beulich + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -2417,7 +2417,7 @@ static NOINLINE int tmemc_save_subop(int + return rc; + } + +-static NOINLINE int tmemc_save_get_next_page(int cli_id, int pool_id, ++static NOINLINE int tmemc_save_get_next_page(int cli_id, uint32_t pool_id, + tmem_cli_va_t buf, uint32_t bufsize) + { + client_t *client = tmh_client_from_cli_id(cli_id); +@@ -2509,7 +2509,7 @@ out: + return ret; + } + +-static int tmemc_restore_put_page(int cli_id, int pool_id, OID *oidp, ++static int tmemc_restore_put_page(int cli_id, uint32_t pool_id, OID *oidp, + uint32_t index, tmem_cli_va_t buf, uint32_t bufsize) + { + client_t *client = tmh_client_from_cli_id(cli_id); +@@ -2521,7 +2521,7 @@ static int tmemc_restore_put_page(int cl + return do_tmem_put(pool,oidp,index,0,0,0,bufsize,buf.p); + } + +-static int tmemc_restore_flush_page(int cli_id, int pool_id, OID *oidp, ++static int tmemc_restore_flush_page(int cli_id, uint32_t pool_id, OID *oidp, + uint32_t index) + { + client_t *client = tmh_client_from_cli_id(cli_id); diff --git a/25852-tmem-xsa-15-3.patch b/25852-tmem-xsa-15-3.patch new file mode 100644 index 0000000..6767de7 --- /dev/null +++ b/25852-tmem-xsa-15-3.patch @@ -0,0 +1,23 @@ +# HG changeset patch +# User Ian Campbell +# Date 1347365214 -7200 +# Node ID d189d99ef00c1e197321593d13282e1b57eb4a38 +# Parent fcf567acc92ae57f4adfbe967b01a2ba0390c08f +tmem: check the pool_id is valid when destroying a tmem pool + +This is part of XSA-15 / CVE-2012-3497. + +Signed-off-by: Ian Campbell +Committed-by: Jan Beulich + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1870,6 +1870,8 @@ static NOINLINE int do_tmem_destroy_pool + + if ( client->pools == NULL ) + return 0; ++ if ( pool_id >= MAX_POOLS_PER_DOMAIN ) ++ return 0; + if ( (pool = client->pools[pool_id]) == NULL ) + return 0; + client->pools[pool_id] = NULL; diff --git a/25853-tmem-xsa-15-4.patch b/25853-tmem-xsa-15-4.patch new file mode 100644 index 0000000..77509c8 --- /dev/null +++ b/25853-tmem-xsa-15-4.patch @@ -0,0 +1,44 @@ +# HG changeset patch +# User Ian Campbell +# Date 1347365847 -7200 +# Node ID f53c5aadbba9d389f4a7d83f308499e22d1d1eda +# Parent d189d99ef00c1e197321593d13282e1b57eb4a38 +tmem: check for a valid client ("domain") in the save subops + +This is part of XSA-15 / CVE-2012-3497. + +Signed-off-by: Ian Campbell +Acked-by: Jan Beulich +Acked-by: Dan Magenheimer +Committed-by: Jan Beulich + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -2379,12 +2379,18 @@ static NOINLINE int tmemc_save_subop(int + rc = MAX_POOLS_PER_DOMAIN; + break; + case TMEMC_SAVE_GET_CLIENT_WEIGHT: ++ if ( client == NULL ) ++ break; + rc = client->weight == -1 ? -2 : client->weight; + break; + case TMEMC_SAVE_GET_CLIENT_CAP: ++ if ( client == NULL ) ++ break; + rc = client->cap == -1 ? -2 : client->cap; + break; + case TMEMC_SAVE_GET_CLIENT_FLAGS: ++ if ( client == NULL ) ++ break; + rc = (client->compress ? TMEM_CLIENT_COMPRESS : 0 ) | + (client->was_frozen ? TMEM_CLIENT_FROZEN : 0 ); + break; +@@ -2408,6 +2414,8 @@ static NOINLINE int tmemc_save_subop(int + *uuid = pool->uuid[1]; + rc = 0; + case TMEMC_SAVE_END: ++ if ( client == NULL ) ++ break; + client->live_migrating = 0; + if ( !list_empty(&client->persistent_invalidated_list) ) + list_for_each_entry_safe(pgp,pgp2, diff --git a/25854-tmem-xsa-15-5.patch b/25854-tmem-xsa-15-5.patch new file mode 100644 index 0000000..602f016 --- /dev/null +++ b/25854-tmem-xsa-15-5.patch @@ -0,0 +1,556 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365869 -7200 +# Node ID ccd60ed6c555e1816cac448fcb20a84533977b43 +# Parent f53c5aadbba9d389f4a7d83f308499e22d1d1eda +tmem: don't access guest memory without using the accessors intended for this + +This is not permitted, not even for buffers coming from Dom0 (and it +would also break the moment Dom0 runs in HVM mode). An implication from +the changes here is that tmh_copy_page() can't be used anymore for +control operations calling tmh_copy_{from,to}_client() (as those pass +the buffer by virtual address rather than MFN). + +Note that tmemc_save_get_next_page() previously didn't set the returned +handle's pool_id field, while the new code does. It need to be +confirmed that this is not a problem (otherwise the copy-out operation +will require further tmh_...() abstractions to be added). + +Further note that the patch removes (rather than adjusts) an invalid +call to unmap_domain_page() (no matching map_domain_page()) from +tmh_compress_from_client() and adds a missing one to an error return +path in tmh_copy_from_client(). + +Finally note that the patch adds a previously missing return statement +to cli_get_page() (without which that function could de-reference a +NULL pointer, triggerable from guest mode). + +This is part of XSA-15 / CVE-2012-3497. + +Signed-off-by: Jan Beulich +Acked-by: Dan Magenheimer + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -388,11 +388,13 @@ static NOINLINE int pcd_copy_to_client(t + pcd = pgp->pcd; + if ( pgp->size < PAGE_SIZE && pgp->size != 0 && + pcd->size < PAGE_SIZE && pcd->size != 0 ) +- ret = tmh_decompress_to_client(cmfn, pcd->cdata, pcd->size, NULL); ++ ret = tmh_decompress_to_client(cmfn, pcd->cdata, pcd->size, ++ tmh_cli_buf_null); + else if ( tmh_tze_enabled() && pcd->size < PAGE_SIZE ) + ret = tmh_copy_tze_to_client(cmfn, pcd->tze, pcd->size); + else +- ret = tmh_copy_to_client(cmfn, pcd->pfp, 0, 0, PAGE_SIZE, NULL); ++ ret = tmh_copy_to_client(cmfn, pcd->pfp, 0, 0, PAGE_SIZE, ++ tmh_cli_buf_null); + tmem_read_unlock(&pcd_tree_rwlocks[firstbyte]); + return ret; + } +@@ -1444,7 +1446,7 @@ static inline void tmem_ensure_avail_pag + /************ TMEM CORE OPERATIONS ************************************/ + + static NOINLINE int do_tmem_put_compress(pgp_t *pgp, tmem_cli_mfn_t cmfn, +- void *cva) ++ tmem_cli_va_t clibuf) + { + void *dst, *p; + size_t size; +@@ -1463,7 +1465,7 @@ static NOINLINE int do_tmem_put_compress + if ( pgp->pfp != NULL ) + pgp_free_data(pgp, pgp->us.obj->pool); + START_CYC_COUNTER(compress); +- ret = tmh_compress_from_client(cmfn, &dst, &size, cva); ++ ret = tmh_compress_from_client(cmfn, &dst, &size, clibuf); + if ( (ret == -EFAULT) || (ret == 0) ) + goto out; + else if ( (size == 0) || (size >= tmem_subpage_maxsize()) ) { +@@ -1490,7 +1492,8 @@ out: + } + + static NOINLINE int do_tmem_dup_put(pgp_t *pgp, tmem_cli_mfn_t cmfn, +- pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, void *cva) ++ pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, ++ tmem_cli_va_t clibuf) + { + pool_t *pool; + obj_t *obj; +@@ -1512,7 +1515,7 @@ static NOINLINE int do_tmem_dup_put(pgp_ + /* can we successfully manipulate pgp to change out the data? */ + if ( len != 0 && client->compress && pgp->size != 0 ) + { +- ret = do_tmem_put_compress(pgp,cmfn,cva); ++ ret = do_tmem_put_compress(pgp, cmfn, clibuf); + if ( ret == 1 ) + goto done; + else if ( ret == 0 ) +@@ -1530,7 +1533,8 @@ copy_uncompressed: + goto failed_dup; + pgp->size = 0; + /* tmh_copy_from_client properly handles len==0 and offsets != 0 */ +- ret = tmh_copy_from_client(pgp->pfp,cmfn,tmem_offset,pfn_offset,len,0); ++ ret = tmh_copy_from_client(pgp->pfp, cmfn, tmem_offset, pfn_offset, len, ++ tmh_cli_buf_null); + if ( ret == -EFAULT ) + goto bad_copy; + if ( tmh_dedup_enabled() && !is_persistent(pool) ) +@@ -1582,7 +1586,7 @@ cleanup: + static NOINLINE int do_tmem_put(pool_t *pool, + OID *oidp, uint32_t index, + tmem_cli_mfn_t cmfn, pagesize_t tmem_offset, +- pagesize_t pfn_offset, pagesize_t len, void *cva) ++ pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t clibuf) + { + obj_t *obj = NULL, *objfound = NULL, *objnew = NULL; + pgp_t *pgp = NULL, *pgpdel = NULL; +@@ -1596,7 +1600,8 @@ static NOINLINE int do_tmem_put(pool_t * + { + ASSERT_SPINLOCK(&objfound->obj_spinlock); + if ((pgp = pgp_lookup_in_obj(objfound, index)) != NULL) +- return do_tmem_dup_put(pgp,cmfn,tmem_offset,pfn_offset,len,cva); ++ return do_tmem_dup_put(pgp, cmfn, tmem_offset, pfn_offset, len, ++ clibuf); + } + + /* no puts allowed into a frozen pool (except dup puts) */ +@@ -1631,7 +1636,7 @@ static NOINLINE int do_tmem_put(pool_t * + if ( len != 0 && client->compress ) + { + ASSERT(pgp->pfp == NULL); +- ret = do_tmem_put_compress(pgp,cmfn,cva); ++ ret = do_tmem_put_compress(pgp, cmfn, clibuf); + if ( ret == 1 ) + goto insert_page; + if ( ret == -ENOMEM ) +@@ -1655,7 +1660,8 @@ copy_uncompressed: + goto delete_and_free; + } + /* tmh_copy_from_client properly handles len==0 (TMEM_NEW_PAGE) */ +- ret = tmh_copy_from_client(pgp->pfp,cmfn,tmem_offset,pfn_offset,len,cva); ++ ret = tmh_copy_from_client(pgp->pfp, cmfn, tmem_offset, pfn_offset, len, ++ clibuf); + if ( ret == -EFAULT ) + goto bad_copy; + if ( tmh_dedup_enabled() && !is_persistent(pool) ) +@@ -1725,12 +1731,13 @@ free: + + static NOINLINE int do_tmem_get(pool_t *pool, OID *oidp, uint32_t index, + tmem_cli_mfn_t cmfn, pagesize_t tmem_offset, +- pagesize_t pfn_offset, pagesize_t len, void *cva) ++ pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t clibuf) + { + obj_t *obj; + pgp_t *pgp; + client_t *client = pool->client; + DECL_LOCAL_CYC_COUNTER(decompress); ++ int rc = -EFAULT; + + if ( !_atomic_read(pool->pgp_count) ) + return -EEMPTY; +@@ -1755,16 +1762,18 @@ static NOINLINE int do_tmem_get(pool_t * + if ( tmh_dedup_enabled() && !is_persistent(pool) && + pgp->firstbyte != NOT_SHAREABLE ) + { +- if ( pcd_copy_to_client(cmfn, pgp) == -EFAULT ) ++ rc = pcd_copy_to_client(cmfn, pgp); ++ if ( rc <= 0 ) + goto bad_copy; + } else if ( pgp->size != 0 ) { + START_CYC_COUNTER(decompress); +- if ( tmh_decompress_to_client(cmfn, pgp->cdata, +- pgp->size, cva) == -EFAULT ) ++ rc = tmh_decompress_to_client(cmfn, pgp->cdata, ++ pgp->size, clibuf); ++ if ( rc <= 0 ) + goto bad_copy; + END_CYC_COUNTER(decompress); + } else if ( tmh_copy_to_client(cmfn, pgp->pfp, tmem_offset, +- pfn_offset, len, cva) == -EFAULT) ++ pfn_offset, len, clibuf) == -EFAULT) + goto bad_copy; + if ( is_ephemeral(pool) ) + { +@@ -1804,8 +1813,7 @@ static NOINLINE int do_tmem_get(pool_t * + bad_copy: + /* this should only happen if the client passed a bad mfn */ + failed_copies++; +- return -EFAULT; +- ++ return rc; + } + + static NOINLINE int do_tmem_flush_page(pool_t *pool, OID *oidp, uint32_t index) +@@ -2345,7 +2353,6 @@ static NOINLINE int tmemc_save_subop(int + pool_t *pool = (client == NULL || pool_id >= MAX_POOLS_PER_DOMAIN) + ? NULL : client->pools[pool_id]; + uint32_t p; +- uint64_t *uuid; + pgp_t *pgp, *pgp2; + int rc = -1; + +@@ -2409,9 +2416,7 @@ static NOINLINE int tmemc_save_subop(int + case TMEMC_SAVE_GET_POOL_UUID: + if ( pool == NULL ) + break; +- uuid = (uint64_t *)buf.p; +- *uuid++ = pool->uuid[0]; +- *uuid = pool->uuid[1]; ++ tmh_copy_to_client_buf(buf, pool->uuid, 2); + rc = 0; + case TMEMC_SAVE_END: + if ( client == NULL ) +@@ -2436,7 +2441,7 @@ static NOINLINE int tmemc_save_get_next_ + pgp_t *pgp; + OID oid; + int ret = 0; +- struct tmem_handle *h; ++ struct tmem_handle h; + unsigned int pagesize = 1 << (pool->pageshift+12); + + if ( pool == NULL || is_ephemeral(pool) ) +@@ -2467,11 +2472,13 @@ static NOINLINE int tmemc_save_get_next_ + pgp_t,us.pool_pers_pages); + pool->cur_pgp = pgp; + oid = pgp->us.obj->oid; +- h = (struct tmem_handle *)buf.p; +- *(OID *)&h->oid[0] = oid; +- h->index = pgp->index; +- buf.p = (void *)(h+1); +- ret = do_tmem_get(pool, &oid, h->index,0,0,0,pagesize,buf.p); ++ h.pool_id = pool_id; ++ BUILD_BUG_ON(sizeof(h.oid) != sizeof(oid)); ++ memcpy(h.oid, oid.oid, sizeof(h.oid)); ++ h.index = pgp->index; ++ tmh_copy_to_client_buf(buf, &h, 1); ++ tmh_client_buf_add(buf, sizeof(h)); ++ ret = do_tmem_get(pool, &oid, pgp->index, 0, 0, 0, pagesize, buf); + + out: + tmem_spin_unlock(&pers_lists_spinlock); +@@ -2483,7 +2490,7 @@ static NOINLINE int tmemc_save_get_next_ + { + client_t *client = tmh_client_from_cli_id(cli_id); + pgp_t *pgp; +- struct tmem_handle *h; ++ struct tmem_handle h; + int ret = 0; + + if ( client == NULL ) +@@ -2509,10 +2516,11 @@ static NOINLINE int tmemc_save_get_next_ + pgp_t,client_inv_pages); + client->cur_pgp = pgp; + } +- h = (struct tmem_handle *)buf.p; +- h->pool_id = pgp->pool_id; +- *(OID *)&h->oid = pgp->inv_oid; +- h->index = pgp->index; ++ h.pool_id = pgp->pool_id; ++ BUILD_BUG_ON(sizeof(h.oid) != sizeof(pgp->inv_oid)); ++ memcpy(h.oid, pgp->inv_oid.oid, sizeof(h.oid)); ++ h.index = pgp->index; ++ tmh_copy_to_client_buf(buf, &h, 1); + ret = 1; + out: + tmem_spin_unlock(&pers_lists_spinlock); +@@ -2528,7 +2536,7 @@ static int tmemc_restore_put_page(int cl + + if ( pool == NULL ) + return -1; +- return do_tmem_put(pool,oidp,index,0,0,0,bufsize,buf.p); ++ return do_tmem_put(pool, oidp, index, 0, 0, 0, bufsize, buf); + } + + static int tmemc_restore_flush_page(int cli_id, uint32_t pool_id, OID *oidp, +@@ -2732,19 +2740,19 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + break; + case TMEM_NEW_PAGE: + tmem_ensure_avail_pages(); +- rc = do_tmem_put(pool, oidp, +- op.u.gen.index, op.u.gen.cmfn, 0, 0, 0, NULL); ++ rc = do_tmem_put(pool, oidp, op.u.gen.index, op.u.gen.cmfn, 0, 0, 0, ++ tmh_cli_buf_null); + break; + case TMEM_PUT_PAGE: + tmem_ensure_avail_pages(); +- rc = do_tmem_put(pool, oidp, +- op.u.gen.index, op.u.gen.cmfn, 0, 0, PAGE_SIZE, NULL); ++ rc = do_tmem_put(pool, oidp, op.u.gen.index, op.u.gen.cmfn, 0, 0, ++ PAGE_SIZE, tmh_cli_buf_null); + if (rc == 1) succ_put = 1; + else non_succ_put = 1; + break; + case TMEM_GET_PAGE: + rc = do_tmem_get(pool, oidp, op.u.gen.index, op.u.gen.cmfn, +- 0, 0, PAGE_SIZE, 0); ++ 0, 0, PAGE_SIZE, tmh_cli_buf_null); + if (rc == 1) succ_get = 1; + else non_succ_get = 1; + break; +@@ -2763,13 +2771,13 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + case TMEM_READ: + rc = do_tmem_get(pool, oidp, op.u.gen.index, op.u.gen.cmfn, + op.u.gen.tmem_offset, op.u.gen.pfn_offset, +- op.u.gen.len,0); ++ op.u.gen.len, tmh_cli_buf_null); + break; + case TMEM_WRITE: + rc = do_tmem_put(pool, oidp, + op.u.gen.index, op.u.gen.cmfn, + op.u.gen.tmem_offset, op.u.gen.pfn_offset, +- op.u.gen.len, NULL); ++ op.u.gen.len, tmh_cli_buf_null); + break; + case TMEM_XCHG: + /* need to hold global lock to ensure xchg is atomic */ +--- a/xen/common/tmem_xen.c ++++ b/xen/common/tmem_xen.c +@@ -51,6 +51,7 @@ DECL_CYC_COUNTER(pg_copy); + #define LZO_DSTMEM_PAGES 2 + static DEFINE_PER_CPU_READ_MOSTLY(unsigned char *, workmem); + static DEFINE_PER_CPU_READ_MOSTLY(unsigned char *, dstmem); ++static DEFINE_PER_CPU_READ_MOSTLY(void *, scratch_page); + + #ifdef COMPARE_COPY_PAGE_SSE2 + #include /* REMOVE ME AFTER TEST */ +@@ -115,6 +116,7 @@ static inline void *cli_get_page(tmem_cl + { + if ( page ) + put_page(page); ++ return NULL; + } + + if ( cli_write && !get_page_type(page, PGT_writable_page) ) +@@ -144,12 +146,12 @@ static inline void cli_put_page(tmem_cli + + EXPORT int tmh_copy_from_client(pfp_t *pfp, + tmem_cli_mfn_t cmfn, pagesize_t tmem_offset, +- pagesize_t pfn_offset, pagesize_t len, void *cli_va) ++ pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t clibuf) + { + unsigned long tmem_mfn, cli_mfn = 0; +- void *tmem_va; ++ char *tmem_va, *cli_va = NULL; + pfp_t *cli_pfp = NULL; +- bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */ ++ int rc = 1; + + ASSERT(pfp != NULL); + tmem_mfn = page_to_mfn(pfp); +@@ -160,62 +162,76 @@ EXPORT int tmh_copy_from_client(pfp_t *p + unmap_domain_page(tmem_va); + return 1; + } +- if ( !tmemc ) ++ if ( guest_handle_is_null(clibuf) ) + { + cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 0); + if ( cli_va == NULL ) ++ { ++ unmap_domain_page(tmem_va); + return -EFAULT; ++ } + } + mb(); +- if (len == PAGE_SIZE && !tmem_offset && !pfn_offset) ++ if ( len == PAGE_SIZE && !tmem_offset && !pfn_offset && cli_va ) + tmh_copy_page(tmem_va, cli_va); + else if ( (tmem_offset+len <= PAGE_SIZE) && + (pfn_offset+len <= PAGE_SIZE) ) +- memcpy((char *)tmem_va+tmem_offset,(char *)cli_va+pfn_offset,len); +- if ( !tmemc ) ++ { ++ if ( cli_va ) ++ memcpy(tmem_va + tmem_offset, cli_va + pfn_offset, len); ++ else if ( copy_from_guest_offset(tmem_va + tmem_offset, clibuf, ++ pfn_offset, len) ) ++ rc = -EFAULT; ++ } ++ if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0); + unmap_domain_page(tmem_va); +- return 1; ++ return rc; + } + + EXPORT int tmh_compress_from_client(tmem_cli_mfn_t cmfn, +- void **out_va, size_t *out_len, void *cli_va) ++ void **out_va, size_t *out_len, tmem_cli_va_t clibuf) + { + int ret = 0; + unsigned char *dmem = this_cpu(dstmem); + unsigned char *wmem = this_cpu(workmem); ++ char *scratch = this_cpu(scratch_page); + pfp_t *cli_pfp = NULL; + unsigned long cli_mfn = 0; +- bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */ ++ void *cli_va = NULL; + + if ( dmem == NULL || wmem == NULL ) + return 0; /* no buffer, so can't compress */ +- if ( !tmemc ) ++ if ( guest_handle_is_null(clibuf) ) + { + cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 0); + if ( cli_va == NULL ) + return -EFAULT; + } ++ else if ( !scratch ) ++ return 0; ++ else if ( copy_from_guest(scratch, clibuf, PAGE_SIZE) ) ++ return -EFAULT; + mb(); +- ret = lzo1x_1_compress(cli_va, PAGE_SIZE, dmem, out_len, wmem); ++ ret = lzo1x_1_compress(cli_va ?: scratch, PAGE_SIZE, dmem, out_len, wmem); + ASSERT(ret == LZO_E_OK); + *out_va = dmem; +- if ( !tmemc ) ++ if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0); +- unmap_domain_page(cli_va); + return 1; + } + + EXPORT int tmh_copy_to_client(tmem_cli_mfn_t cmfn, pfp_t *pfp, +- pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, void *cli_va) ++ pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, ++ tmem_cli_va_t clibuf) + { + unsigned long tmem_mfn, cli_mfn = 0; +- void *tmem_va; ++ char *tmem_va, *cli_va = NULL; + pfp_t *cli_pfp = NULL; +- bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */ ++ int rc = 1; + + ASSERT(pfp != NULL); +- if ( !tmemc ) ++ if ( guest_handle_is_null(clibuf) ) + { + cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 1); + if ( cli_va == NULL ) +@@ -223,37 +239,48 @@ EXPORT int tmh_copy_to_client(tmem_cli_m + } + tmem_mfn = page_to_mfn(pfp); + tmem_va = map_domain_page(tmem_mfn); +- if (len == PAGE_SIZE && !tmem_offset && !pfn_offset) ++ if ( len == PAGE_SIZE && !tmem_offset && !pfn_offset && cli_va ) + tmh_copy_page(cli_va, tmem_va); + else if ( (tmem_offset+len <= PAGE_SIZE) && (pfn_offset+len <= PAGE_SIZE) ) +- memcpy((char *)cli_va+pfn_offset,(char *)tmem_va+tmem_offset,len); ++ { ++ if ( cli_va ) ++ memcpy(cli_va + pfn_offset, tmem_va + tmem_offset, len); ++ else if ( copy_to_guest_offset(clibuf, pfn_offset, ++ tmem_va + tmem_offset, len) ) ++ rc = -EFAULT; ++ } + unmap_domain_page(tmem_va); +- if ( !tmemc ) ++ if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); + mb(); +- return 1; ++ return rc; + } + + EXPORT int tmh_decompress_to_client(tmem_cli_mfn_t cmfn, void *tmem_va, +- size_t size, void *cli_va) ++ size_t size, tmem_cli_va_t clibuf) + { + unsigned long cli_mfn = 0; + pfp_t *cli_pfp = NULL; ++ void *cli_va = NULL; ++ char *scratch = this_cpu(scratch_page); + size_t out_len = PAGE_SIZE; +- bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */ + int ret; + +- if ( !tmemc ) ++ if ( guest_handle_is_null(clibuf) ) + { + cli_va = cli_get_page(cmfn, &cli_mfn, &cli_pfp, 1); + if ( cli_va == NULL ) + return -EFAULT; + } +- ret = lzo1x_decompress_safe(tmem_va, size, cli_va, &out_len); ++ else if ( !scratch ) ++ return 0; ++ ret = lzo1x_decompress_safe(tmem_va, size, cli_va ?: scratch, &out_len); + ASSERT(ret == LZO_E_OK); + ASSERT(out_len == PAGE_SIZE); +- if ( !tmemc ) ++ if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); ++ else if ( copy_to_guest(clibuf, scratch, PAGE_SIZE) ) ++ return -EFAULT; + mb(); + return 1; + } +@@ -423,6 +450,11 @@ static int cpu_callback( + struct page_info *p = alloc_domheap_pages(0, workmem_order, 0); + per_cpu(workmem, cpu) = p ? page_to_virt(p) : NULL; + } ++ if ( per_cpu(scratch_page, cpu) == NULL ) ++ { ++ struct page_info *p = alloc_domheap_page(NULL, 0); ++ per_cpu(scratch_page, cpu) = p ? page_to_virt(p) : NULL; ++ } + break; + } + case CPU_DEAD: +@@ -439,6 +471,11 @@ static int cpu_callback( + free_domheap_pages(p, workmem_order); + per_cpu(workmem, cpu) = NULL; + } ++ if ( per_cpu(scratch_page, cpu) != NULL ) ++ { ++ free_domheap_page(virt_to_page(per_cpu(scratch_page, cpu))); ++ per_cpu(scratch_page, cpu) = NULL; ++ } + break; + } + default: +--- a/xen/include/xen/tmem_xen.h ++++ b/xen/include/xen/tmem_xen.h +@@ -482,27 +482,33 @@ static inline int tmh_get_tmemop_from_cl + return copy_from_guest(op, uops, 1); + } + ++#define tmh_cli_buf_null guest_handle_from_ptr(NULL, char) ++ + static inline void tmh_copy_to_client_buf_offset(tmem_cli_va_t clibuf, int off, + char *tmembuf, int len) + { + copy_to_guest_offset(clibuf,off,tmembuf,len); + } + ++#define tmh_copy_to_client_buf(clibuf, tmembuf, cnt) \ ++ copy_to_guest(guest_handle_cast(clibuf, void), tmembuf, cnt) ++ ++#define tmh_client_buf_add guest_handle_add_offset ++ + #define TMH_CLI_ID_NULL ((cli_id_t)((domid_t)-1L)) + + #define tmh_cli_id_str "domid" + #define tmh_client_str "domain" + +-extern int tmh_decompress_to_client(tmem_cli_mfn_t,void*,size_t,void*); ++int tmh_decompress_to_client(tmem_cli_mfn_t, void *, size_t, tmem_cli_va_t); + +-extern int tmh_compress_from_client(tmem_cli_mfn_t,void**,size_t *,void*); ++int tmh_compress_from_client(tmem_cli_mfn_t, void **, size_t *, tmem_cli_va_t); + +-extern int tmh_copy_from_client(pfp_t *pfp, +- tmem_cli_mfn_t cmfn, pagesize_t tmem_offset, +- pagesize_t pfn_offset, pagesize_t len, void *cva); ++int tmh_copy_from_client(pfp_t *, tmem_cli_mfn_t, pagesize_t tmem_offset, ++ pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t); + +-extern int tmh_copy_to_client(tmem_cli_mfn_t cmfn, pfp_t *pfp, +- pagesize_t tmem_offset, pagesize_t pfn_offset, pagesize_t len, void *cva); ++int tmh_copy_to_client(tmem_cli_mfn_t, pfp_t *, pagesize_t tmem_offset, ++ pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t); + + extern int tmh_copy_tze_to_client(tmem_cli_mfn_t cmfn, void *tmem_va, pagesize_t len); + diff --git a/25855-tmem-xsa-15-6.patch b/25855-tmem-xsa-15-6.patch new file mode 100644 index 0000000..4cb199a --- /dev/null +++ b/25855-tmem-xsa-15-6.patch @@ -0,0 +1,137 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365879 -7200 +# Node ID 33b8c42a87ec2fa6e6533dd9ee7603f732b168f5 +# Parent ccd60ed6c555e1816cac448fcb20a84533977b43 +tmem: detect arithmetic overflow in tmh_copy_{from,to}_client() + +This implies adjusting callers to deal with errors other than -EFAULT +and removing some comments which would otherwise become stale. + +Reported-by: Tim Deegan +Signed-off-by: Jan Beulich +Acked-by: Dan Magenheimer + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1535,7 +1535,7 @@ copy_uncompressed: + /* tmh_copy_from_client properly handles len==0 and offsets != 0 */ + ret = tmh_copy_from_client(pgp->pfp, cmfn, tmem_offset, pfn_offset, len, + tmh_cli_buf_null); +- if ( ret == -EFAULT ) ++ if ( ret < 0 ) + goto bad_copy; + if ( tmh_dedup_enabled() && !is_persistent(pool) ) + { +@@ -1556,9 +1556,7 @@ done: + return 1; + + bad_copy: +- /* this should only happen if the client passed a bad mfn */ + failed_copies++; +- ret = -EFAULT; + goto cleanup; + + failed_dup: +@@ -1662,7 +1660,7 @@ copy_uncompressed: + /* tmh_copy_from_client properly handles len==0 (TMEM_NEW_PAGE) */ + ret = tmh_copy_from_client(pgp->pfp, cmfn, tmem_offset, pfn_offset, len, + clibuf); +- if ( ret == -EFAULT ) ++ if ( ret < 0 ) + goto bad_copy; + if ( tmh_dedup_enabled() && !is_persistent(pool) ) + { +@@ -1702,8 +1700,6 @@ insert_page: + return 1; + + bad_copy: +- /* this should only happen if the client passed a bad mfn */ +- ret = -EFAULT; + failed_copies++; + + delete_and_free: +@@ -1737,7 +1733,7 @@ static NOINLINE int do_tmem_get(pool_t * + pgp_t *pgp; + client_t *client = pool->client; + DECL_LOCAL_CYC_COUNTER(decompress); +- int rc = -EFAULT; ++ int rc; + + if ( !_atomic_read(pool->pgp_count) ) + return -EEMPTY; +@@ -1761,20 +1757,20 @@ static NOINLINE int do_tmem_get(pool_t * + ASSERT(pgp->size != -1); + if ( tmh_dedup_enabled() && !is_persistent(pool) && + pgp->firstbyte != NOT_SHAREABLE ) +- { + rc = pcd_copy_to_client(cmfn, pgp); +- if ( rc <= 0 ) +- goto bad_copy; +- } else if ( pgp->size != 0 ) { ++ else if ( pgp->size != 0 ) ++ { + START_CYC_COUNTER(decompress); + rc = tmh_decompress_to_client(cmfn, pgp->cdata, + pgp->size, clibuf); +- if ( rc <= 0 ) +- goto bad_copy; + END_CYC_COUNTER(decompress); +- } else if ( tmh_copy_to_client(cmfn, pgp->pfp, tmem_offset, +- pfn_offset, len, clibuf) == -EFAULT) ++ } ++ else ++ rc = tmh_copy_to_client(cmfn, pgp->pfp, tmem_offset, ++ pfn_offset, len, clibuf); ++ if ( rc <= 0 ) + goto bad_copy; ++ + if ( is_ephemeral(pool) ) + { + if ( is_private(pool) ) +@@ -1811,7 +1807,6 @@ static NOINLINE int do_tmem_get(pool_t * + return 1; + + bad_copy: +- /* this should only happen if the client passed a bad mfn */ + failed_copies++; + return rc; + } +--- a/xen/common/tmem_xen.c ++++ b/xen/common/tmem_xen.c +@@ -153,6 +153,8 @@ EXPORT int tmh_copy_from_client(pfp_t *p + pfp_t *cli_pfp = NULL; + int rc = 1; + ++ if ( tmem_offset > PAGE_SIZE || pfn_offset > PAGE_SIZE || len > PAGE_SIZE ) ++ return -EINVAL; + ASSERT(pfp != NULL); + tmem_mfn = page_to_mfn(pfp); + tmem_va = map_domain_page(tmem_mfn); +@@ -183,6 +185,8 @@ EXPORT int tmh_copy_from_client(pfp_t *p + pfn_offset, len) ) + rc = -EFAULT; + } ++ else if ( len ) ++ rc = -EINVAL; + if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0); + unmap_domain_page(tmem_va); +@@ -230,6 +234,8 @@ EXPORT int tmh_copy_to_client(tmem_cli_m + pfp_t *cli_pfp = NULL; + int rc = 1; + ++ if ( tmem_offset > PAGE_SIZE || pfn_offset > PAGE_SIZE || len > PAGE_SIZE ) ++ return -EINVAL; + ASSERT(pfp != NULL); + if ( guest_handle_is_null(clibuf) ) + { +@@ -249,6 +255,8 @@ EXPORT int tmh_copy_to_client(tmem_cli_m + tmem_va + tmem_offset, len) ) + rc = -EFAULT; + } ++ else if ( len ) ++ rc = -EINVAL; + unmap_domain_page(tmem_va); + if ( cli_va ) + cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); diff --git a/25856-tmem-xsa-15-7.patch b/25856-tmem-xsa-15-7.patch new file mode 100644 index 0000000..7663506 --- /dev/null +++ b/25856-tmem-xsa-15-7.patch @@ -0,0 +1,32 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365888 -7200 +# Node ID 83b97a59888b6d2d0f984b8403bd5764dd55c10c +# Parent 33b8c42a87ec2fa6e6533dd9ee7603f732b168f5 +tmem: properly drop lock on error path in do_tmem_get() + +Also remove a bogus assertion. + +Reported-by: Tim Deegan +Signed-off-by: Jan Beulich +Acked-by: Dan Magenheimer + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1790,7 +1790,6 @@ static NOINLINE int do_tmem_get(pool_t * + list_del(&pgp->us.client_eph_pages); + list_add_tail(&pgp->us.client_eph_pages,&client->ephemeral_page_list); + tmem_spin_unlock(&eph_lists_spinlock); +- ASSERT(obj != NULL); + obj->last_client = tmh_get_cli_id_from_current(); + } + } +@@ -1807,6 +1806,8 @@ static NOINLINE int do_tmem_get(pool_t * + return 1; + + bad_copy: ++ obj->no_evict = 0; ++ tmem_spin_unlock(&obj->obj_spinlock); + failed_copies++; + return rc; + } diff --git a/25857-tmem-xsa-15-8.patch b/25857-tmem-xsa-15-8.patch new file mode 100644 index 0000000..32fba23 --- /dev/null +++ b/25857-tmem-xsa-15-8.patch @@ -0,0 +1,34 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365906 -7200 +# Node ID 109ea6a0c23aa0c5df79e3f5658162aed959ffcf +# Parent 83b97a59888b6d2d0f984b8403bd5764dd55c10c +tmem: properly drop lock on error path in do_tmem_op() + +Reported-by: Tim Deegan +Signed-off-by: Jan Beulich +Acked-by: Dan Magenheimer + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -2659,13 +2659,19 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + if ( client != NULL && tmh_client_is_dying(client) ) + { + rc = -ENODEV; +- goto out; ++ if ( tmh_lock_all ) ++ goto out; ++ simple_error: ++ errored_tmem_ops++; ++ return rc; + } + + if ( unlikely(tmh_get_tmemop_from_client(&op, uops) != 0) ) + { + printk("tmem: can't get tmem struct from %s\n",client_str); + rc = -EFAULT; ++ if ( !tmh_lock_all ) ++ goto simple_error; + goto out; + } + diff --git a/25858-tmem-xsa-15-9.patch b/25858-tmem-xsa-15-9.patch new file mode 100644 index 0000000..4d31543 --- /dev/null +++ b/25858-tmem-xsa-15-9.patch @@ -0,0 +1,305 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365916 -7200 +# Node ID 0520982a602a3ac06dd5bc573ddaff5edc9c6987 +# Parent 109ea6a0c23aa0c5df79e3f5658162aed959ffcf +tmem: reduce severity of log messages + +Otherwise they can be used by a guest to spam the hypervisor log with +all settings at their defaults. + +Signed-off-by: Jan Beulich +Acked-by: Zhenzhong Duan + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1107,7 +1107,7 @@ static int shared_pool_join(pool_t *pool + sl->client = new_client; + list_add_tail(&sl->share_list, &pool->share_list); + if ( new_client->cli_id != pool->client->cli_id ) +- printk("adding new %s %d to shared pool owned by %s %d\n", ++ tmh_client_info("adding new %s %d to shared pool owned by %s %d\n", + client_str, new_client->cli_id, client_str, pool->client->cli_id); + return ++pool->shared_count; + } +@@ -1137,7 +1137,7 @@ static NOINLINE void shared_pool_reassig + old_client->eph_count -= _atomic_read(pool->pgp_count); + list_splice_init(&old_client->ephemeral_page_list, + &new_client->ephemeral_page_list); +- printk("reassigned shared pool from %s=%d to %s=%d pool_id=%d\n", ++ tmh_client_info("reassigned shared pool from %s=%d to %s=%d pool_id=%d\n", + cli_id_str, old_client->cli_id, cli_id_str, new_client->cli_id, poolid); + pool->pool_id = poolid; + } +@@ -1173,7 +1173,7 @@ static NOINLINE int shared_pool_quit(poo + } + return 0; + } +- printk("tmem: no match unsharing pool, %s=%d\n", ++ tmh_client_warn("tmem: no match unsharing pool, %s=%d\n", + cli_id_str,pool->client->cli_id); + return -1; + } +@@ -1184,17 +1184,18 @@ static void pool_flush(pool_t *pool, cli + ASSERT(pool != NULL); + if ( (is_shared(pool)) && (shared_pool_quit(pool,cli_id) > 0) ) + { +- printk("tmem: %s=%d no longer using shared pool %d owned by %s=%d\n", ++ tmh_client_warn("tmem: %s=%d no longer using shared pool %d owned by %s=%d\n", + cli_id_str, cli_id, pool->pool_id, cli_id_str,pool->client->cli_id); + return; + } +- printk("%s %s-%s tmem pool ",destroy?"destroying":"flushing", +- is_persistent(pool) ? "persistent" : "ephemeral" , +- is_shared(pool) ? "shared" : "private"); +- printk("%s=%d pool_id=%d\n", cli_id_str,pool->client->cli_id,pool->pool_id); ++ tmh_client_info("%s %s-%s tmem pool %s=%d pool_id=%d\n", ++ destroy ? "destroying" : "flushing", ++ is_persistent(pool) ? "persistent" : "ephemeral" , ++ is_shared(pool) ? "shared" : "private", ++ cli_id_str, pool->client->cli_id, pool->pool_id); + if ( pool->client->live_migrating ) + { +- printk("can't %s pool while %s is live-migrating\n", ++ tmh_client_warn("can't %s pool while %s is live-migrating\n", + destroy?"destroy":"flush", client_str); + return; + } +@@ -1213,21 +1214,22 @@ static client_t *client_create(cli_id_t + client_t *client = tmh_alloc_infra(sizeof(client_t),__alignof__(client_t)); + int i; + +- printk("tmem: initializing tmem capability for %s=%d...",cli_id_str,cli_id); ++ tmh_client_info("tmem: initializing tmem capability for %s=%d...", ++ cli_id_str, cli_id); + if ( client == NULL ) + { +- printk("failed... out of memory\n"); ++ tmh_client_err("failed... out of memory\n"); + goto fail; + } + memset(client,0,sizeof(client_t)); + if ( (client->tmh = tmh_client_init(cli_id)) == NULL ) + { +- printk("failed... can't allocate host-dependent part of client\n"); ++ tmh_client_err("failed... can't allocate host-dependent part of client\n"); + goto fail; + } + if ( !tmh_set_client_from_id(client, client->tmh, cli_id) ) + { +- printk("failed... can't set client\n"); ++ tmh_client_err("failed... can't set client\n"); + goto fail; + } + client->cli_id = cli_id; +@@ -1249,7 +1251,7 @@ static client_t *client_create(cli_id_t + client->eph_count = client->eph_count_max = 0; + client->total_cycles = 0; client->succ_pers_puts = 0; + client->succ_eph_gets = 0; client->succ_pers_gets = 0; +- printk("ok\n"); ++ tmh_client_info("ok\n"); + return client; + + fail: +@@ -1903,32 +1905,33 @@ static NOINLINE int do_tmem_new_pool(cli + cli_id = tmh_get_cli_id_from_current(); + else + cli_id = this_cli_id; +- printk("tmem: allocating %s-%s tmem pool for %s=%d...", ++ tmh_client_info("tmem: allocating %s-%s tmem pool for %s=%d...", + persistent ? "persistent" : "ephemeral" , + shared ? "shared" : "private", cli_id_str, cli_id); + if ( specversion != TMEM_SPEC_VERSION ) + { +- printk("failed... unsupported spec version\n"); ++ tmh_client_err("failed... unsupported spec version\n"); + return -EPERM; + } + if ( pagebits != (PAGE_SHIFT - 12) ) + { +- printk("failed... unsupported pagesize %d\n",1<<(pagebits+12)); ++ tmh_client_err("failed... unsupported pagesize %d\n", ++ 1 << (pagebits + 12)); + return -EPERM; + } + if ( flags & TMEM_POOL_PRECOMPRESSED ) + { +- printk("failed... precompression flag set but unsupported\n"); ++ tmh_client_err("failed... precompression flag set but unsupported\n"); + return -EPERM; + } + if ( flags & TMEM_POOL_RESERVED_BITS ) + { +- printk("failed... reserved bits must be zero\n"); ++ tmh_client_err("failed... reserved bits must be zero\n"); + return -EPERM; + } + if ( (pool = pool_alloc()) == NULL ) + { +- printk("failed... out of memory\n"); ++ tmh_client_err("failed... out of memory\n"); + return -ENOMEM; + } + if ( this_cli_id != CLI_ID_NULL ) +@@ -1947,7 +1950,7 @@ static NOINLINE int do_tmem_new_pool(cli + break; + if ( d_poolid >= MAX_POOLS_PER_DOMAIN ) + { +- printk("failed... no more pool slots available for this %s\n", ++ tmh_client_err("failed... no more pool slots available for this %s\n", + client_str); + goto fail; + } +@@ -1977,9 +1980,8 @@ static NOINLINE int do_tmem_new_pool(cli + { + if ( shpool->uuid[0] == uuid_lo && shpool->uuid[1] == uuid_hi ) + { +- printk("(matches shared pool uuid=%"PRIx64".%"PRIx64") ", +- uuid_hi, uuid_lo); +- printk("pool_id=%d\n",d_poolid); ++ tmh_client_info("(matches shared pool uuid=%"PRIx64".%"PRIx64") pool_id=%d\n", ++ uuid_hi, uuid_lo, d_poolid); + client->pools[d_poolid] = global_shared_pools[s_poolid]; + shared_pool_join(global_shared_pools[s_poolid], client); + pool_free(pool); +@@ -1991,7 +1993,7 @@ static NOINLINE int do_tmem_new_pool(cli + } + if ( first_unused_s_poolid == MAX_GLOBAL_SHARED_POOLS ) + { +- printk("tmem: failed... no global shared pool slots available\n"); ++ tmh_client_warn("tmem: failed... no global shared pool slots available\n"); + goto fail; + } + else +@@ -2007,7 +2009,7 @@ static NOINLINE int do_tmem_new_pool(cli + pool->pool_id = d_poolid; + pool->persistent = persistent; + pool->uuid[0] = uuid_lo; pool->uuid[1] = uuid_hi; +- printk("pool_id=%d\n",d_poolid); ++ tmh_client_info("pool_id=%d\n", d_poolid); + return d_poolid; + + fail: +@@ -2030,14 +2032,15 @@ static int tmemc_freeze_pools(cli_id_t c + { + list_for_each_entry(client,&global_client_list,client_list) + client_freeze(client,freeze); +- printk("tmem: all pools %s for all %ss\n",s,client_str); ++ tmh_client_info("tmem: all pools %s for all %ss\n", s, client_str); + } + else + { + if ( (client = tmh_client_from_cli_id(cli_id)) == NULL) + return -1; + client_freeze(client,freeze); +- printk("tmem: all pools %s for %s=%d\n",s,cli_id_str,cli_id); ++ tmh_client_info("tmem: all pools %s for %s=%d\n", ++ s, cli_id_str, cli_id); + } + return 0; + } +@@ -2048,7 +2051,7 @@ static int tmemc_flush_mem(cli_id_t cli_ + + if ( cli_id != CLI_ID_NULL ) + { +- printk("tmem: %s-specific flush not supported yet, use --all\n", ++ tmh_client_warn("tmem: %s-specific flush not supported yet, use --all\n", + client_str); + return -1; + } +@@ -2261,13 +2264,15 @@ static int tmemc_set_var_one(client_t *c + case TMEMC_SET_WEIGHT: + old_weight = client->weight; + client->weight = arg1; +- printk("tmem: weight set to %d for %s=%d\n",arg1,cli_id_str,cli_id); ++ tmh_client_info("tmem: weight set to %d for %s=%d\n", ++ arg1, cli_id_str, cli_id); + atomic_sub(old_weight,&client_weight_total); + atomic_add(client->weight,&client_weight_total); + break; + case TMEMC_SET_CAP: + client->cap = arg1; +- printk("tmem: cap set to %d for %s=%d\n",arg1,cli_id_str,cli_id); ++ tmh_client_info("tmem: cap set to %d for %s=%d\n", ++ arg1, cli_id_str, cli_id); + break; + case TMEMC_SET_COMPRESS: + #ifdef __i386__ +@@ -2275,17 +2280,17 @@ static int tmemc_set_var_one(client_t *c + #endif + if ( tmh_dedup_enabled() ) + { +- printk("tmem: compression %s for all %ss, cannot be changed " +- "when tmem_dedup is enabled\n", +- tmh_compression_enabled() ? "enabled" : "disabled",client_str); ++ tmh_client_warn("tmem: compression %s for all %ss, cannot be changed when tmem_dedup is enabled\n", ++ tmh_compression_enabled() ? "enabled" : "disabled", ++ client_str); + return -1; + } + client->compress = arg1 ? 1 : 0; +- printk("tmem: compression %s for %s=%d\n", ++ tmh_client_info("tmem: compression %s for %s=%d\n", + arg1 ? "enabled" : "disabled",cli_id_str,cli_id); + break; + default: +- printk("tmem: unknown subop %d for tmemc_set_var\n",subop); ++ tmh_client_warn("tmem: unknown subop %d for tmemc_set_var\n", subop); + return -1; + } + return 0; +@@ -2668,7 +2673,7 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + + if ( unlikely(tmh_get_tmemop_from_client(&op, uops) != 0) ) + { +- printk("tmem: can't get tmem struct from %s\n",client_str); ++ tmh_client_err("tmem: can't get tmem struct from %s\n", client_str); + rc = -EFAULT; + if ( !tmh_lock_all ) + goto simple_error; +@@ -2702,7 +2707,8 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + tmem_write_lock_set = 1; + if ( (client = client_create(tmh_get_cli_id_from_current())) == NULL ) + { +- printk("tmem: can't create tmem structure for %s\n",client_str); ++ tmh_client_err("tmem: can't create tmem structure for %s\n", ++ client_str); + rc = -ENOMEM; + goto out; + } +@@ -2726,8 +2732,8 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + if ( ((uint32_t)op.pool_id >= MAX_POOLS_PER_DOMAIN) || + ((pool = client->pools[op.pool_id]) == NULL) ) + { ++ tmh_client_err("tmem: operation requested on uncreated pool\n"); + rc = -ENODEV; +- printk("tmem: operation requested on uncreated pool\n"); + goto out; + } + ASSERT_SENTINEL(pool,POOL); +@@ -2783,11 +2789,11 @@ EXPORT long do_tmem_op(tmem_cli_op_t uop + break; + case TMEM_XCHG: + /* need to hold global lock to ensure xchg is atomic */ +- printk("tmem_xchg op not implemented yet\n"); ++ tmh_client_warn("tmem_xchg op not implemented yet\n"); + rc = 0; + break; + default: +- printk("tmem: op %d not implemented\n", op.cmd); ++ tmh_client_warn("tmem: op %d not implemented\n", op.cmd); + rc = 0; + break; + } +--- a/xen/include/xen/tmem_xen.h ++++ b/xen/include/xen/tmem_xen.h +@@ -512,6 +512,9 @@ int tmh_copy_to_client(tmem_cli_mfn_t, p + + extern int tmh_copy_tze_to_client(tmem_cli_mfn_t cmfn, void *tmem_va, pagesize_t len); + ++#define tmh_client_err(fmt, args...) printk(XENLOG_G_ERR fmt, ##args) ++#define tmh_client_warn(fmt, args...) printk(XENLOG_G_WARNING fmt, ##args) ++#define tmh_client_info(fmt, args...) printk(XENLOG_G_INFO fmt, ##args) + + #define TMEM_PERF + #ifdef TMEM_PERF diff --git a/25859-tmem-missing-break.patch b/25859-tmem-missing-break.patch new file mode 100644 index 0000000..2212c08 --- /dev/null +++ b/25859-tmem-missing-break.patch @@ -0,0 +1,41 @@ +# HG changeset patch +# User Dan Magenheimer +# Date 1347365943 -7200 +# Node ID 16e0392c6594b1757bbaa82076630a73d843229b +# Parent 0520982a602a3ac06dd5bc573ddaff5edc9c6987 +tmem: fixup 2010 cleanup patch that breaks tmem save/restore + +20918:a3fa6d444b25 "Fix domain reference leaks" (in Feb 2010, by Jan) +does some cleanup in addition to the leak fixes. Unfortunately, that +cleanup inadvertently resulted in an incorrect fallthrough in a switch +statement which breaks tmem save/restore. + +That broken patch was apparently applied to 4.0-testing and 4.1-testing +so those are broken as well. + +What is the process now for requesting back-patches to 4.0 and 4.1? + +(Side note: This does not by itself entirely fix save/restore in 4.2.) + +Signed-off-by: Dan Magenheimer +Signed-off-by: Jan Beulich +Committed-by: Jan Beulich + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -2419,6 +2419,7 @@ static NOINLINE int tmemc_save_subop(int + break; + tmh_copy_to_client_buf(buf, pool->uuid, 2); + rc = 0; ++ break; + case TMEMC_SAVE_END: + if ( client == NULL ) + break; +@@ -2429,6 +2430,7 @@ static NOINLINE int tmemc_save_subop(int + pgp_free_from_inv_list(client,pgp); + client->frozen = client->was_frozen; + rc = 0; ++ break; + } + return rc; + } diff --git a/25860-tmem-cleanup.patch b/25860-tmem-cleanup.patch new file mode 100644 index 0000000..97f4ae8 --- /dev/null +++ b/25860-tmem-cleanup.patch @@ -0,0 +1,106 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347365969 -7200 +# Node ID e4cb8411161043c726f699252cc761e77853e820 +# Parent 16e0392c6594b1757bbaa82076630a73d843229b +tmem: cleanup + +- one more case of checking for a specific rather than any error +- drop no longer needed first parameter from cli_put_page() +- drop a redundant cast + +Signed-off-by: Jan Beulich +Acked-by: Dan Magenheimer + +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1468,7 +1468,7 @@ static NOINLINE int do_tmem_put_compress + pgp_free_data(pgp, pgp->us.obj->pool); + START_CYC_COUNTER(compress); + ret = tmh_compress_from_client(cmfn, &dst, &size, clibuf); +- if ( (ret == -EFAULT) || (ret == 0) ) ++ if ( ret <= 0 ) + goto out; + else if ( (size == 0) || (size >= tmem_subpage_maxsize()) ) { + ret = 0; +--- a/xen/common/tmem_xen.c ++++ b/xen/common/tmem_xen.c +@@ -97,7 +97,7 @@ static inline void *cli_get_page(tmem_cl + return NULL; + } + +-static inline void cli_put_page(tmem_cli_mfn_t cmfn, void *cli_va, pfp_t *cli_pfp, ++static inline void cli_put_page(void *cli_va, pfp_t *cli_pfp, + unsigned long cli_mfn, bool_t mark_dirty) + { + ASSERT(0); +@@ -126,20 +126,20 @@ static inline void *cli_get_page(tmem_cl + } + + *pcli_mfn = page_to_mfn(page); +- *pcli_pfp = (pfp_t *)page; ++ *pcli_pfp = page; + return map_domain_page(*pcli_mfn); + } + +-static inline void cli_put_page(tmem_cli_mfn_t cmfn, void *cli_va, pfp_t *cli_pfp, ++static inline void cli_put_page(void *cli_va, pfp_t *cli_pfp, + unsigned long cli_mfn, bool_t mark_dirty) + { + if ( mark_dirty ) + { +- put_page_and_type((struct page_info *)cli_pfp); ++ put_page_and_type(cli_pfp); + paging_mark_dirty(current->domain,cli_mfn); + } + else +- put_page((struct page_info *)cli_pfp); ++ put_page(cli_pfp); + unmap_domain_page(cli_va); + } + #endif +@@ -188,7 +188,7 @@ EXPORT int tmh_copy_from_client(pfp_t *p + else if ( len ) + rc = -EINVAL; + if ( cli_va ) +- cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0); ++ cli_put_page(cli_va, cli_pfp, cli_mfn, 0); + unmap_domain_page(tmem_va); + return rc; + } +@@ -221,7 +221,7 @@ EXPORT int tmh_compress_from_client(tmem + ASSERT(ret == LZO_E_OK); + *out_va = dmem; + if ( cli_va ) +- cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0); ++ cli_put_page(cli_va, cli_pfp, cli_mfn, 0); + return 1; + } + +@@ -259,7 +259,7 @@ EXPORT int tmh_copy_to_client(tmem_cli_m + rc = -EINVAL; + unmap_domain_page(tmem_va); + if ( cli_va ) +- cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); ++ cli_put_page(cli_va, cli_pfp, cli_mfn, 1); + mb(); + return rc; + } +@@ -286,7 +286,7 @@ EXPORT int tmh_decompress_to_client(tmem + ASSERT(ret == LZO_E_OK); + ASSERT(out_len == PAGE_SIZE); + if ( cli_va ) +- cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); ++ cli_put_page(cli_va, cli_pfp, cli_mfn, 1); + else if ( copy_to_guest(clibuf, scratch, PAGE_SIZE) ) + return -EFAULT; + mb(); +@@ -310,7 +310,7 @@ EXPORT int tmh_copy_tze_to_client(tmem_c + memcpy((char *)cli_va,(char *)tmem_va,len); + if ( len < PAGE_SIZE ) + memset((char *)cli_va+len,0,PAGE_SIZE-len); +- cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1); ++ cli_put_page(cli_va, cli_pfp, cli_mfn, 1); + mb(); + return 1; + } diff --git a/25861-x86-early-fixmap.patch b/25861-x86-early-fixmap.patch new file mode 100644 index 0000000..32eae6f --- /dev/null +++ b/25861-x86-early-fixmap.patch @@ -0,0 +1,218 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371120 -7200 +# Node ID 51c2d7c83cbc2a0357ce112a463f91d354dcdba9 +# Parent e4cb8411161043c726f699252cc761e77853e820 +x86: allow early use of fixmaps + +As a prerequisite for adding an EHCI debug port based console +implementation, set up the page tables needed for (a sub-portion of) +the fixmaps together with other boot time page table construction. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/arch/x86/boot/head.S ++++ b/xen/arch/x86/boot/head.S +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -136,6 +137,9 @@ __start: + add $8,%edx + add $(1< + #include + #include ++#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ ++#include ++#undef __ASSEMBLY__ + #include + #include + #include +@@ -1123,14 +1126,19 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY + slot &= L2_PAGETABLE_ENTRIES - 1; + l2_bootmap[slot] = l2e_from_paddr(addr, __PAGE_HYPERVISOR|_PAGE_PSE); + } ++ /* Initialise L2 fixmap page directory entry. */ ++ l2_fixmap[l2_table_offset(FIXADDR_TOP - 1)] = ++ l2e_from_paddr((UINTN)l1_fixmap, __PAGE_HYPERVISOR); + /* Initialise L3 identity-map page directory entries. */ + for ( i = 0; i < ARRAY_SIZE(l2_identmap) / L2_PAGETABLE_ENTRIES; ++i ) + l3_identmap[i] = l3e_from_paddr((UINTN)(l2_identmap + + i * L2_PAGETABLE_ENTRIES), + __PAGE_HYPERVISOR); +- /* Initialise L3 xen-map page directory entry. */ ++ /* Initialise L3 xen-map and fixmap page directory entries. */ + l3_xenmap[l3_table_offset(XEN_VIRT_START)] = + l3e_from_paddr((UINTN)l2_xenmap, __PAGE_HYPERVISOR); ++ l3_xenmap[l3_table_offset(FIXADDR_TOP - 1)] = ++ l3e_from_paddr((UINTN)l2_fixmap, __PAGE_HYPERVISOR); + /* Initialise L3 boot-map page directory entries. */ + l3_bootmap[l3_table_offset(xen_phys_start)] = + l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -130,6 +130,10 @@ + l1_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) + l1_identmap[L1_PAGETABLE_ENTRIES]; + ++/* Mapping of the fixmap space needed early. */ ++l1_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) ++ l1_fixmap[L1_PAGETABLE_ENTRIES]; ++ + #define MEM_LOG(_f, _a...) gdprintk(XENLOG_WARNING , _f "\n" , ## _a) + + /* +--- a/xen/arch/x86/x86_64/mm.c ++++ b/xen/arch/x86/x86_64/mm.c +@@ -65,6 +65,10 @@ l3_pgentry_t __attribute__ ((__section__ + l2_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) + l2_xenmap[L2_PAGETABLE_ENTRIES]; + ++/* Enough page directories to map the early fixmap space. */ ++l2_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) ++ l2_fixmap[L2_PAGETABLE_ENTRIES]; ++ + /* Enough page directories to map into the bottom 1GB. */ + l3_pgentry_t __attribute__ ((__section__ (".bss.page_aligned"))) + l3_bootmap[L3_PAGETABLE_ENTRIES]; +--- a/xen/include/asm-x86/config.h ++++ b/xen/include/asm-x86/config.h +@@ -315,7 +315,7 @@ extern unsigned char boot_edid_info[128] + #define MACHPHYS_MBYTES 16 /* 1 MB needed per 1 GB memory */ + #define FRAMETABLE_MBYTES (MACHPHYS_MBYTES * 6) + +-#define IOREMAP_VIRT_END 0UL ++#define IOREMAP_VIRT_END _AC(0,UL) + #define IOREMAP_VIRT_START (IOREMAP_VIRT_END - (IOREMAP_MBYTES<<20)) + #define DIRECTMAP_VIRT_END IOREMAP_VIRT_START + #define DIRECTMAP_VIRT_START (DIRECTMAP_VIRT_END - (DIRECTMAP_MBYTES<<20)) +--- a/xen/include/asm-x86/fixmap.h ++++ b/xen/include/asm-x86/fixmap.h +@@ -13,12 +13,17 @@ + #define _ASM_FIXMAP_H + + #include ++#include ++ ++#define FIXADDR_TOP (IOREMAP_VIRT_END - PAGE_SIZE) ++ ++#ifndef __ASSEMBLY__ ++ + #include + #include + #include + #include + #include +-#include + #include + #include + #include +@@ -66,7 +71,6 @@ enum fixed_addresses { + __end_of_fixed_addresses + }; + +-#define FIXADDR_TOP (IOREMAP_VIRT_END - PAGE_SIZE) + #define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) + #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) + +@@ -90,4 +94,6 @@ static inline unsigned long virt_to_fix( + return __virt_to_fix(vaddr); + } + ++#endif /* __ASSEMBLY__ */ ++ + #endif +--- a/xen/include/asm-x86/page.h ++++ b/xen/include/asm-x86/page.h +@@ -1,6 +1,8 @@ + #ifndef __X86_PAGE_H__ + #define __X86_PAGE_H__ + ++#include ++ + /* + * It is important that the masks are signed quantities. This ensures that + * the compiler sign-extends a 32-bit mask to 64 bits if that is required. +@@ -306,13 +308,15 @@ extern l2_pgentry_t idle_pg_table_l2[ + extern l2_pgentry_t *compat_idle_pg_table_l2; + extern unsigned int m2p_compat_vstart; + extern l2_pgentry_t l2_xenmap[L2_PAGETABLE_ENTRIES], ++ l2_fixmap[L2_PAGETABLE_ENTRIES], + l2_bootmap[L2_PAGETABLE_ENTRIES]; + extern l3_pgentry_t l3_xenmap[L3_PAGETABLE_ENTRIES], + l3_identmap[L3_PAGETABLE_ENTRIES], + l3_bootmap[L3_PAGETABLE_ENTRIES]; + #endif + extern l2_pgentry_t l2_identmap[4*L2_PAGETABLE_ENTRIES]; +-extern l1_pgentry_t l1_identmap[L1_PAGETABLE_ENTRIES]; ++extern l1_pgentry_t l1_identmap[L1_PAGETABLE_ENTRIES], ++ l1_fixmap[L1_PAGETABLE_ENTRIES]; + void paging_init(void); + void setup_idle_pagetable(void); + #endif /* !defined(__ASSEMBLY__) */ +--- /dev/null ++++ b/xen/include/xen/const.h +@@ -0,0 +1,24 @@ ++/* const.h: Macros for dealing with constants. */ ++ ++#ifndef __XEN_CONST_H__ ++#define __XEN_CONST_H__ ++ ++/* Some constant macros are used in both assembler and ++ * C code. Therefore we cannot annotate them always with ++ * 'UL' and other type specifiers unilaterally. We ++ * use the following macros to deal with this. ++ * ++ * Similarly, _AT() will cast an expression with a type in C, but ++ * leave it unchanged in asm. ++ */ ++ ++#ifdef __ASSEMBLY__ ++#define _AC(X,Y) X ++#define _AT(T,X) X ++#else ++#define __AC(X,Y) (X##Y) ++#define _AC(X,Y) __AC(X,Y) ++#define _AT(T,X) ((T)(X)) ++#endif ++ ++#endif /* __XEN_CONST_H__ */ diff --git a/25862-sercon-non-com.patch b/25862-sercon-non-com.patch new file mode 100644 index 0000000..5b0c9d5 --- /dev/null +++ b/25862-sercon-non-com.patch @@ -0,0 +1,144 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371236 -7200 +# Node ID 776a23fa0e938e4cf3307fc2e3b3f1a9488a5927 +# Parent 51c2d7c83cbc2a0357ce112a463f91d354dcdba9 +console: prepare for non-COMn port support + +Widen SERHND_IDX (and use it where needed), introduce a flush low level +driver method, and remove unnecessary peeking of the common code at the +(driver specific) serial port identification string in the "console=" +command line option value. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -1017,7 +1017,7 @@ void __init smp_intr_init(void) + * Also ensure serial interrupts are high priority. We do not + * want them to be blocked by unacknowledged guest-bound interrupts. + */ +- for ( seridx = 0; seridx < 2; seridx++ ) ++ for ( seridx = 0; seridx <= SERHND_IDX; seridx++ ) + { + if ( (irq = serial_irq(seridx)) < 0 ) + continue; +--- a/xen/drivers/char/console.c ++++ b/xen/drivers/char/console.c +@@ -539,6 +539,7 @@ void printk(const char *fmt, ...) + void __init console_init_preirq(void) + { + char *p; ++ int sh; + + serial_init_preirq(); + +@@ -551,8 +552,9 @@ void __init console_init_preirq(void) + vga_init(); + else if ( !strncmp(p, "none", 4) ) + continue; +- else if ( strncmp(p, "com", 3) || +- (sercon_handle = serial_parse_handle(p)) == -1 ) ++ else if ( (sh = serial_parse_handle(p)) >= 0 ) ++ sercon_handle = sh; ++ else + { + char *q = strchr(p, ','); + if ( q != NULL ) +--- a/xen/drivers/char/serial.c ++++ b/xen/drivers/char/serial.c +@@ -22,9 +22,11 @@ size_param("serial_tx_buffer", serial_tx + #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1)) + #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1)) + +-static struct serial_port com[2] = { +- { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }, +- { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED } ++static struct serial_port com[SERHND_IDX + 1] = { ++ [0 ... SERHND_IDX] = { ++ .rx_lock = SPIN_LOCK_UNLOCKED, ++ .tx_lock = SPIN_LOCK_UNLOCKED ++ } + }; + + void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) +@@ -81,6 +83,8 @@ void serial_tx_interrupt(struct serial_p + port->driver->putc( + port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); + } ++ if ( i && port->driver->flush ) ++ port->driver->flush(port); + } + + spin_unlock(&port->tx_lock); +@@ -175,6 +179,9 @@ void serial_putc(int handle, char c) + + __serial_putc(port, c); + ++ if ( port->driver->flush ) ++ port->driver->flush(port); ++ + spin_unlock_irqrestore(&port->tx_lock, flags); + } + +@@ -206,6 +213,9 @@ void serial_puts(int handle, const char + __serial_putc(port, c); + } + ++ if ( port->driver->flush ) ++ port->driver->flush(port); ++ + spin_unlock_irqrestore(&port->tx_lock, flags); + } + +@@ -261,10 +271,10 @@ int __init serial_parse_handle(char *con + switch ( conf[3] ) + { + case '1': +- handle = 0; ++ handle = SERHND_COM1; + break; + case '2': +- handle = 1; ++ handle = SERHND_COM2; + break; + default: + goto fail; +@@ -365,6 +375,8 @@ void serial_start_sync(int handle) + port->driver->putc( + port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); + } ++ if ( port->driver->flush ) ++ port->driver->flush(port); + } + + spin_unlock_irqrestore(&port->tx_lock, flags); +--- a/xen/include/xen/serial.h ++++ b/xen/include/xen/serial.h +@@ -60,6 +60,8 @@ struct uart_driver { + int (*tx_empty)(struct serial_port *); + /* Put a character onto the serial line. */ + void (*putc)(struct serial_port *, char); ++ /* Flush accumulated characters. */ ++ void (*flush)(struct serial_port *); + /* Get a character from the serial line: returns 0 if none available. */ + int (*getc)(struct serial_port *, char *); + /* Get IRQ number for this port's serial line: returns -1 if none. */ +@@ -67,10 +69,12 @@ struct uart_driver { + }; + + /* 'Serial handles' are composed from the following fields. */ +-#define SERHND_IDX (1<<0) /* COM1 or COM2? */ +-#define SERHND_HI (1<<1) /* Mux/demux each transferred char by MSB. */ +-#define SERHND_LO (1<<2) /* Ditto, except that the MSB is cleared. */ +-#define SERHND_COOKED (1<<3) /* Newline/carriage-return translation? */ ++#define SERHND_IDX (3<<0) /* COM1 or COM2? */ ++# define SERHND_COM1 (0<<0) ++# define SERHND_COM2 (1<<0) ++#define SERHND_HI (1<<2) /* Mux/demux each transferred char by MSB. */ ++#define SERHND_LO (1<<3) /* Ditto, except that the MSB is cleared. */ ++#define SERHND_COOKED (1<<4) /* Newline/carriage-return translation? */ + + /* Two-stage initialisation (before/after IRQ-subsystem initialisation). */ + void serial_init_preirq(void); diff --git a/25863-sercon-ehci-dbgp.patch b/25863-sercon-ehci-dbgp.patch new file mode 100644 index 0000000..f176e05 --- /dev/null +++ b/25863-sercon-ehci-dbgp.patch @@ -0,0 +1,1778 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371392 -7200 +# Node ID 0d0c55a1975db9c6cac2e9259b5ebea7a7bdbaec +# Parent 776a23fa0e938e4cf3307fc2e3b3f1a9488a5927 +console: add EHCI debug port based serial console + +Low level hardware interface pieces adapted from Linux. + +For setup information, see Linux'es Documentation/x86/earlyprintk.txt +and/or http://www.coreboot.org/EHCI_Debug_Port. + +Signed-off-by: Jan Beulich +Reviewed-by: Konrad Rzeszutek Wilk +Acked-by: Keir Fraser + +--- a/docs/misc/xen-command-line.markdown ++++ b/docs/misc/xen-command-line.markdown +@@ -244,7 +244,7 @@ A typical setup for most situations migh + Specify the size of the console ring buffer. + + ### console +-> `= List of [ vga | com1[H,L] | com2[H,L] | none ]` ++> `= List of [ vga | com1[H,L] | com2[H,L] | dbgp | none ]` + + > Default: `console=com1,vga` + +@@ -260,6 +260,8 @@ the converse; transmitted and received c + cleared. This allows a single port to be shared by two subsystems + (e.g. console and debugger). + ++`dbgp` indicates that Xen should use a USB debug port. ++ + `none` indicates that Xen should not use a console. This option only + makes sense on its own. + +@@ -352,6 +354,12 @@ combination with the `low_crashinfo` com + ### credit2\_load\_window\_shift + > `= ` + ++### dbgp ++> `= ehci[ | @pci:. ]` ++ ++Specify the USB controller to use, either by instance number (when going ++over the PCI busses sequentially) or by PCI device (must be on segment 0). ++ + ### debug\_stack\_lines + > `= ` + +--- a/xen/arch/x86/Rules.mk ++++ b/xen/arch/x86/Rules.mk +@@ -7,6 +7,7 @@ HAS_CPUFREQ := y + HAS_PCI := y + HAS_PASSTHROUGH := y + HAS_NS16550 := y ++HAS_EHCI := y + HAS_KEXEC := y + HAS_GDBSX := y + xenoprof := y +--- a/xen/arch/x86/physdev.c ++++ b/xen/arch/x86/physdev.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -722,6 +723,19 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H + + break; + } ++ ++ case PHYSDEVOP_dbgp_op: { ++ struct physdev_dbgp_op op; ++ ++ if ( !IS_PRIV(v->domain) ) ++ ret = -EPERM; ++ else if ( copy_from_guest(&op, arg, 1) ) ++ ret = -EFAULT; ++ else ++ ret = dbgp_op(&op); ++ break; ++ } ++ + default: + ret = -ENOSYS; + break; +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -606,6 +606,7 @@ void __init __start_xen(unsigned long mb + ns16550.io_base = 0x2f8; + ns16550.irq = 3; + ns16550_init(1, &ns16550); ++ ehci_dbgp_init(); + console_init_preirq(); + + printk("Bootloader: %s\n", loader); +--- a/xen/drivers/char/Makefile ++++ b/xen/drivers/char/Makefile +@@ -1,4 +1,5 @@ + obj-y += console.o + obj-$(HAS_NS16550) += ns16550.o + obj-$(HAS_PL011) += pl011.o ++obj-$(HAS_EHCI) += ehci-dbgp.o + obj-y += serial.o +--- /dev/null ++++ b/xen/drivers/char/ehci-dbgp.c +@@ -0,0 +1,1577 @@ ++/* ++ * Standalone EHCI USB debug driver ++ * ++ * Hardware interface code based on the respective early console driver in ++ * Linux; see the Linux source for authorship and copyrights. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* #define DBGP_DEBUG */ ++ ++/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ ++ ++/* Section 2.2 Host Controller Capability Registers */ ++struct ehci_caps { ++ /* ++ * These fields are specified as 8 and 16 bit registers, ++ * but some hosts can't perform 8 or 16 bit PCI accesses. ++ * some hosts treat caplength and hciversion as parts of a 32-bit ++ * register, others treat them as two separate registers, this ++ * affects the memory map for big endian controllers. ++ */ ++ u32 hc_capbase; ++#define HC_LENGTH(p) (0x00ff & (p)) /* bits 7:0 / offset 0x00 */ ++#define HC_VERSION(p) (0xffff & ((p) >> 16)) /* bits 31:16 / offset 0x02 */ ++ ++ u32 hcs_params; /* HCSPARAMS - offset 0x04 */ ++#define HCS_DEBUG_PORT(p) (((p) >> 20) & 0xf) /* bits 23:20, debug port? */ ++#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */ ++#define HCS_N_CC(p) (((p) >> 12) & 0xf) /* bits 15:12, #companion HCs */ ++#define HCS_N_PCC(p) (((p) >> 8) & 0xf) /* bits 11:8, ports per CC */ ++#define HCS_PORTROUTED(p) ((p) & (1 << 7)) /* true: port routing */ ++#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */ ++#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */ ++ ++ u32 hcc_params; /* HCCPARAMS - offset 0x08 */ ++/* EHCI 1.1 addendum */ ++#define HCC_32FRAME_PERIODIC_LIST(p) ((p) & (1 << 19)) ++#define HCC_PER_PORT_CHANGE_EVENT(p) ((p) & (1 << 18)) ++#define HCC_LPM(p) ((p) & (1 << 17)) ++#define HCC_HW_PREFETCH(p) ((p) & (1 << 16)) ++#define HCC_EXT_CAPS(p) (((p) >> 8) & 0xff) /* for pci extended caps */ ++#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */ ++#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */ ++#define HCC_CANPARK(p) ((p) & (1 << 2)) /* true: can park on async qh */ ++#define HCC_PGM_FRAMELISTLEN(p) ((p) & (1 << 1)) /* true: periodic_size changes */ ++#define HCC_64BIT_ADDR(p) ((p) & 1) /* true: can use 64-bit addr */ ++ ++ u8 portroute[8]; /* nibbles for routing - offset 0x0C */ ++}; ++ ++/* Section 2.3 Host Controller Operational Registers */ ++struct ehci_regs { ++ /* USBCMD: offset 0x00 */ ++ u32 command; ++ ++/* EHCI 1.1 addendum */ ++#define CMD_HIRD (0xf << 24) /* host initiated resume duration */ ++#define CMD_PPCEE (1 << 15) /* per port change event enable */ ++#define CMD_FSP (1 << 14) /* fully synchronized prefetch */ ++#define CMD_ASPE (1 << 13) /* async schedule prefetch enable */ ++#define CMD_PSPE (1 << 12) /* periodic schedule prefetch enable */ ++/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ ++#define CMD_PARK (1 << 11) /* enable "park" on async qh */ ++#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park for */ ++#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */ ++#define CMD_IAAD (1 << 6) /* "doorbell" interrupt async advance */ ++#define CMD_ASE (1 << 5) /* async schedule enable */ ++#define CMD_PSE (1 << 4) /* periodic schedule enable */ ++/* 3:2 is periodic frame list size */ ++#define CMD_RESET (1 << 1) /* reset HC not bus */ ++#define CMD_RUN (1 << 0) /* start/stop HC */ ++ ++ /* USBSTS: offset 0x04 */ ++ u32 status; ++#define STS_PPCE_MASK (0xff << 16) /* Per-Port change event 1-16 */ ++#define STS_ASS (1 << 15) /* Async Schedule Status */ ++#define STS_PSS (1 << 14) /* Periodic Schedule Status */ ++#define STS_RECL (1 << 13) /* Reclamation */ ++#define STS_HALT (1 << 12) /* Not running (any reason) */ ++/* some bits reserved */ ++ /* these STS_* flags are also intr_enable bits (USBINTR) */ ++#define STS_IAA (1 << 5) /* Interrupted on async advance */ ++#define STS_FATAL (1 << 4) /* such as some PCI access errors */ ++#define STS_FLR (1 << 3) /* frame list rolled over */ ++#define STS_PCD (1 << 2) /* port change detect */ ++#define STS_ERR (1 << 1) /* "error" completion (overflow, ...) */ ++#define STS_INT (1 << 0) /* "normal" completion (short, ...) */ ++ ++ /* USBINTR: offset 0x08 */ ++ u32 intr_enable; ++ ++ /* FRINDEX: offset 0x0C */ ++ u32 frame_index; /* current microframe number */ ++ /* CTRLDSSEGMENT: offset 0x10 */ ++ u32 segment; /* address bits 63:32 if needed */ ++ /* PERIODICLISTBASE: offset 0x14 */ ++ u32 frame_list; /* points to periodic list */ ++ /* ASYNCLISTADDR: offset 0x18 */ ++ u32 async_next; /* address of next async queue head */ ++ ++ u32 reserved[9]; ++ ++ /* CONFIGFLAG: offset 0x40 */ ++ u32 configured_flag; ++#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */ ++ ++ /* PORTSC: offset 0x44 */ ++ u32 port_status[0]; /* up to N_PORTS */ ++/* EHCI 1.1 addendum */ ++#define PORTSC_SUSPEND_STS_ACK 0 ++#define PORTSC_SUSPEND_STS_NYET 1 ++#define PORTSC_SUSPEND_STS_STALL 2 ++#define PORTSC_SUSPEND_STS_ERR 3 ++ ++#define PORT_DEV_ADDR (0x7f << 25) /* device address */ ++#define PORT_SSTS (0x3 << 23) /* suspend status */ ++/* 31:23 reserved */ ++#define PORT_WKOC_E (1 << 22) /* wake on overcurrent (enable) */ ++#define PORT_WKDISC_E (1 << 21) /* wake on disconnect (enable) */ ++#define PORT_WKCONN_E (1 << 20) /* wake on connect (enable) */ ++/* 19:16 for port testing */ ++#define PORT_TEST(x) (((x) & 0xf) << 16) /* Port Test Control */ ++#define PORT_TEST_PKT PORT_TEST(0x4) /* Port Test Control - packet test */ ++#define PORT_TEST_FORCE PORT_TEST(0x5) /* Port Test Control - force enable */ ++#define PORT_LED_OFF (0 << 14) ++#define PORT_LED_AMBER (1 << 14) ++#define PORT_LED_GREEN (2 << 14) ++#define PORT_LED_MASK (3 << 14) ++#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */ ++#define PORT_POWER (1 << 12) /* true: has power (see PPC) */ ++#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ ++/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ ++/* 9 reserved */ ++#define PORT_LPM (1 << 9) /* LPM transaction */ ++#define PORT_RESET (1 << 8) /* reset port */ ++#define PORT_SUSPEND (1 << 7) /* suspend port */ ++#define PORT_RESUME (1 << 6) /* resume it */ ++#define PORT_OCC (1 << 5) /* over current change */ ++#define PORT_OC (1 << 4) /* over current active */ ++#define PORT_PEC (1 << 3) /* port enable change */ ++#define PORT_PE (1 << 2) /* port enable */ ++#define PORT_CSC (1 << 1) /* connect status change */ ++#define PORT_CONNECT (1 << 0) /* device connected */ ++#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) ++}; ++ ++/* ++ * Appendix C, Debug port ... intended for use with special "debug devices" ++ * that can help if there's no serial console. (nonstandard enumeration.) ++ */ ++struct ehci_dbg_port { ++ u32 control; ++#define DBGP_OWNER (1 << 30) ++#define DBGP_ENABLED (1 << 28) ++#define DBGP_DONE (1 << 16) ++#define DBGP_INUSE (1 << 10) ++#define DBGP_ERRCODE(x) (((x) >> 7) & 0x07) ++# define DBGP_ERR_BAD 1 ++# define DBGP_ERR_SIGNAL 2 ++#define DBGP_ERROR (1 << 6) ++#define DBGP_GO (1 << 5) ++#define DBGP_OUT (1 << 4) ++#define DBGP_LEN (0xf << 0) ++#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) ++ u32 pids; ++#define DBGP_PID_GET(x) (((x) >> 16) & 0xff) ++#define DBGP_PID_SET(data, tok) (((data) << 8) | (tok)) ++ u32 data03; ++ u32 data47; ++ u32 address; ++#define DBGP_EPADDR(dev, ep) (((dev) << 8) | (ep)) ++}; ++ ++/* CONTROL REQUEST SUPPORT */ ++ ++/* ++ * USB directions ++ * ++ * This bit flag is used in endpoint descriptors' bEndpointAddress field. ++ * It's also one of three fields in control requests bRequestType. ++ */ ++#define USB_DIR_OUT 0 /* to device */ ++#define USB_DIR_IN 0x80 /* to host */ ++ ++/* ++ * USB types, the second of three bRequestType fields ++ */ ++#define USB_TYPE_MASK (0x03 << 5) ++#define USB_TYPE_STANDARD (0x00 << 5) ++#define USB_TYPE_CLASS (0x01 << 5) ++#define USB_TYPE_VENDOR (0x02 << 5) ++#define USB_TYPE_RESERVED (0x03 << 5) ++ ++/* ++ * USB recipients, the third of three bRequestType fields ++ */ ++#define USB_RECIP_MASK 0x1f ++#define USB_RECIP_DEVICE 0x00 ++#define USB_RECIP_INTERFACE 0x01 ++#define USB_RECIP_ENDPOINT 0x02 ++#define USB_RECIP_OTHER 0x03 ++/* From Wireless USB 1.0 */ ++#define USB_RECIP_PORT 0x04 ++#define USB_RECIP_RPIPE 0x05 ++ ++/* ++ * Standard requests, for the bRequest field of a SETUP packet. ++ * ++ * These are qualified by the bRequestType field, so that for example ++ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved ++ * by a GET_STATUS request. ++ */ ++#define USB_REQ_GET_STATUS 0x00 ++#define USB_REQ_CLEAR_FEATURE 0x01 ++#define USB_REQ_SET_FEATURE 0x03 ++#define USB_REQ_SET_ADDRESS 0x05 ++#define USB_REQ_GET_DESCRIPTOR 0x06 ++#define USB_REQ_SET_DESCRIPTOR 0x07 ++#define USB_REQ_GET_CONFIGURATION 0x08 ++#define USB_REQ_SET_CONFIGURATION 0x09 ++#define USB_REQ_GET_INTERFACE 0x0A ++#define USB_REQ_SET_INTERFACE 0x0B ++#define USB_REQ_SYNCH_FRAME 0x0C ++ ++#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ ++ ++/** ++ * struct usb_ctrlrequest - SETUP data for a USB device control request ++ * @bRequestType: matches the USB bmRequestType field ++ * @bRequest: matches the USB bRequest field ++ * @wValue: matches the USB wValue field (le16 byte order) ++ * @wIndex: matches the USB wIndex field (le16 byte order) ++ * @wLength: matches the USB wLength field (le16 byte order) ++ * ++ * This structure is used to send control requests to a USB device. It matches ++ * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the ++ * USB spec for a fuller description of the different fields, and what they are ++ * used for. ++ * ++ * Note that the driver for any interface can issue control requests. ++ * For most devices, interfaces don't coordinate with each other, so ++ * such requests may be made at any time. ++ */ ++struct usb_ctrlrequest { ++ u8 bRequestType; ++ u8 bRequest; ++ __le16 wValue; ++ __le16 wIndex; ++ __le16 wLength; ++} __attribute__ ((packed)); ++ ++/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ ++ ++#define USB_DT_DEBUG 0x0a ++ ++struct usb_debug_descriptor { ++ u8 bLength; ++ u8 bDescriptorType; ++ /* bulk endpoints with 8 byte maxpacket */ ++ u8 bDebugInEndpoint; ++ u8 bDebugOutEndpoint; ++} __attribute__((packed)); ++ ++#define USB_DEBUG_DEVNUM 127 ++ ++/* ++ * USB Packet IDs (PIDs) ++ */ ++ ++/* token */ ++#define USB_PID_OUT 0xe1 ++#define USB_PID_IN 0x69 ++#define USB_PID_SOF 0xa5 ++#define USB_PID_SETUP 0x2d ++/* handshake */ ++#define USB_PID_ACK 0xd2 ++#define USB_PID_NAK 0x5a ++#define USB_PID_STALL 0x1e ++#define USB_PID_NYET 0x96 ++/* data */ ++#define USB_PID_DATA0 0xc3 ++#define USB_PID_DATA1 0x4b ++#define USB_PID_DATA2 0x87 ++#define USB_PID_MDATA 0x0f ++/* Special */ ++#define USB_PID_PREAMBLE 0x3c ++#define USB_PID_ERR 0x3c ++#define USB_PID_SPLIT 0x78 ++#define USB_PID_PING 0xb4 ++#define USB_PID_UNDEF_0 0xf0 ++ ++#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320 ++#define PCI_CAP_ID_EHCI_DEBUG 0x0a ++ ++#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ ++#define HUB_SHORT_RESET_TIME 10 ++#define HUB_LONG_RESET_TIME 200 ++#define HUB_RESET_TIMEOUT 500 ++ ++#define DBGP_MAX_PACKET 8 ++#define DBGP_LOOPS 1000 ++#define DBGP_TIMEOUT (250 * 1000) /* us */ ++#define DBGP_CHECK_INTERVAL 100 /* us */ ++/* This one can be set arbitrarily - only affects input responsiveness: */ ++#define DBGP_IDLE_INTERVAL 100 /* ms */ ++ ++struct ehci_dbgp { ++ struct ehci_dbg_port __iomem *ehci_debug; ++ enum dbgp_state { ++ dbgp_idle, ++ dbgp_out, ++ dbgp_in, ++ dbgp_ctrl, ++ dbgp_unsafe /* cannot use debug device during EHCI reset */ ++ } state; ++ unsigned int phys_port; ++ struct { ++ unsigned int endpoint; ++ unsigned int chunk; ++ char buf[DBGP_MAX_PACKET]; ++ } out, in; ++ unsigned long timeout; ++ struct timer timer; ++ spinlock_t *lock; ++ bool_t reset_run; ++ u8 bus, slot, func, bar; ++ u16 pci_cr; ++ u32 bar_val; ++ unsigned int cap; ++ struct ehci_regs __iomem *ehci_regs; ++ struct ehci_caps __iomem *ehci_caps; ++}; ++ ++static int ehci_dbgp_external_startup(struct ehci_dbgp *); ++ ++static void ehci_dbgp_status(struct ehci_dbgp *dbgp, const char *str) ++{ ++#ifdef DBGP_DEBUG ++#define dbgp_printk printk ++ if ( !dbgp->ehci_debug ) ++ return; ++ dbgp_printk("dbgp: %s\n", str); ++ dbgp_printk(" debug control: %08x\n", readl(&dbgp->ehci_debug->control)); ++ dbgp_printk(" EHCI cmd : %08x\n", readl(&dbgp->ehci_regs->command)); ++ dbgp_printk(" EHCI conf flg: %08x\n", ++ readl(&dbgp->ehci_regs->configured_flag)); ++ dbgp_printk(" EHCI status : %08x\n", readl(&dbgp->ehci_regs->status)); ++ dbgp_printk(" EHCI portsc : %08x\n", ++ readl(&dbgp->ehci_regs->port_status[dbgp->phys_port - 1])); ++#endif ++} ++ ++#ifndef DBGP_DEBUG ++static inline __attribute__ ((format (printf, 1, 2))) void ++dbgp_printk(const char *fmt, ...) { } ++#endif ++ ++static inline u32 dbgp_len_update(u32 x, u32 len) ++{ ++ return (x & ~DBGP_LEN) | (len & DBGP_LEN) | DBGP_OUT; ++} ++ ++static inline u32 dbgp_pid_write_update(u32 x, u32 tok) ++{ ++ static u8 data0 = USB_PID_DATA1; ++ ++ data0 ^= USB_PID_DATA0 ^ USB_PID_DATA1; ++ return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff); ++} ++ ++static inline u32 dbgp_pid_read_update(u32 x, u32 tok) ++{ ++ return (x & 0xffffff00) | (tok & 0xff); ++} ++ ++static inline void dbgp_set_data(struct ehci_dbg_port __iomem *ehci_debug, ++ const void *buf, unsigned int size) ++{ ++ const unsigned char *bytes = buf; ++ u32 lo = 0, hi = 0; ++ unsigned int i; ++ ++ for ( i = 0; i < 4 && i < size; i++ ) ++ lo |= bytes[i] << (8 * i); ++ for ( ; i < 8 && i < size; i++ ) ++ hi |= bytes[i] << (8 * (i - 4)); ++ writel(lo, &ehci_debug->data03); ++ writel(hi, &ehci_debug->data47); ++} ++ ++static inline void dbgp_get_data(struct ehci_dbg_port __iomem *ehci_debug, ++ void *buf, int size) ++{ ++ unsigned char *bytes = buf; ++ u32 lo = readl(&ehci_debug->data03); ++ u32 hi = readl(&ehci_debug->data47); ++ unsigned int i; ++ ++ for ( i = 0; i < 4 && i < size; i++ ) ++ bytes[i] = (lo >> (8 * i)) & 0xff; ++ for ( ; i < 8 && i < size; i++ ) ++ bytes[i] = (hi >> (8 * (i - 4))) & 0xff; ++} ++ ++static void dbgp_issue_command(struct ehci_dbgp *dbgp, u32 ctrl, ++ enum dbgp_state state) ++{ ++ u32 cmd = readl(&dbgp->ehci_regs->command); ++ ++ if ( unlikely(!(cmd & CMD_RUN)) ) ++ { ++ /* ++ * If the EHCI controller is not in the run state do extended ++ * checks to see if ACPI or some other initialization also ++ * reset the EHCI debug port. ++ */ ++ u32 ctrl = readl(&dbgp->ehci_debug->control); ++ ++ if ( ctrl & DBGP_ENABLED ) ++ { ++ cmd |= CMD_RUN; ++ writel(cmd, &dbgp->ehci_regs->command); ++ dbgp->reset_run = 1; ++ } ++ else if ( dbgp->state != dbgp_unsafe ) ++ { ++ dbgp->state = dbgp_unsafe; ++ ehci_dbgp_external_startup(dbgp); ++ } ++ } ++ ++ writel(ctrl | DBGP_GO, &dbgp->ehci_debug->control); ++ dbgp->timeout = DBGP_TIMEOUT; ++ if ( dbgp->state != dbgp_unsafe ) ++ dbgp->state = state; ++} ++ ++static int dbgp_check_for_completion(struct ehci_dbgp *dbgp, ++ unsigned int interval, u8 *ppid) ++{ ++ u32 ctrl; ++ int ret; ++ ++ if ( dbgp->state == dbgp_idle ) ++ return 0; ++ ++ ctrl = readl(&dbgp->ehci_debug->control) & ~DBGP_GO; ++ if ( !(ctrl & DBGP_DONE) ) ++ { ++ if ( dbgp->timeout > interval ) ++ dbgp->timeout -= interval; ++ else if ( interval ) ++ { ++ /* See the timeout related comment in dbgp_wait_until_done(). */ ++ dbgp->state = dbgp_unsafe; ++ dbgp->timeout = 0; ++ } ++ return -DBGP_TIMEOUT; ++ } ++ ++ if ( ctrl & DBGP_ERROR ) ++ { ++ ret = -DBGP_ERRCODE(ctrl); ++ if ( ret == -DBGP_ERR_BAD && dbgp->timeout > interval ) ++ ctrl |= DBGP_GO; ++ } ++ else ++ { ++ u8 pid = DBGP_PID_GET(readl(&dbgp->ehci_debug->pids)); ++ ++ ret = ctrl & DBGP_LEN; ++ if ( ppid ) ++ *ppid = pid; ++ else if ( dbgp->state == dbgp_in ) ++ { ++ dbgp_get_data(dbgp->ehci_debug, dbgp->in.buf, ret); ++ dbgp->in.chunk = ret; ++ } ++ else if ( pid == USB_PID_NAK && dbgp->timeout > interval ) ++ ctrl |= DBGP_GO; ++ } ++ ++ writel(ctrl, &dbgp->ehci_debug->control); ++ if ( ctrl & DBGP_GO ) ++ { ++ dbgp->timeout -= interval; ++ return -DBGP_TIMEOUT; ++ } ++ ++ if ( unlikely(dbgp->reset_run) ) ++ { ++ writel(readl(&dbgp->ehci_regs->command) & ~CMD_RUN, ++ &dbgp->ehci_regs->command); ++ dbgp->reset_run = 0; ++ } ++ ++ if ( dbgp->state != dbgp_unsafe ) ++ dbgp->state = dbgp_idle; ++ ++ return ret; ++} ++ ++static int dbgp_wait_until_complete(struct ehci_dbgp *dbgp, u8 *ppid) ++{ ++ unsigned int loop = DBGP_TIMEOUT; ++ int ret; ++ ++ do { ++ ret = dbgp_check_for_completion(dbgp, 0, ppid); ++ if ( ret != -DBGP_TIMEOUT ) ++ break; ++ udelay(1); ++ } while ( --loop ); ++ ++ if ( !ppid && !loop ) ++ dbgp->state = dbgp_unsafe; ++ ++ return ret; ++} ++ ++static inline void dbgp_mdelay(unsigned int ms) ++{ ++ while ( ms-- ) ++ { ++ unsigned int i; ++ ++ for ( i = 0; i < 1000; i++ ) ++ outb(0x1, 0x80); ++ } ++} ++ ++static void dbgp_breathe(void) ++{ ++ /* Sleep to give the debug port a chance to breathe. */ ++ dbgp_mdelay(1); ++} ++ ++static int dbgp_wait_until_done(struct ehci_dbgp *dbgp, u32 ctrl, ++ unsigned int loop) ++{ ++ int ret; ++ ++ dbgp->timeout = 0; ++ ++ for ( ; ; writel(ctrl | DBGP_GO, &dbgp->ehci_debug->control) ) ++ { ++ u8 pid; ++ ++ ret = dbgp_wait_until_complete(dbgp, &pid); ++ if ( ret < 0 ) ++ { ++ /* ++ * A -DBGP_TIMEOUT failure here means the device has failed, ++ * perhaps because it was unplugged, in which case we do not ++ * want to hang the system so the dbgp will be marked as unsafe ++ * to use. EHCI reset is the only way to recover if you unplug ++ * the dbgp device. ++ */ ++ if ( ret == -DBGP_TIMEOUT ) ++ dbgp->state = dbgp_unsafe; ++ if ( ret != -DBGP_ERR_BAD || !--loop ) ++ break; ++ } ++ else ++ { ++ /* ++ * If the port is getting full or it has dropped data ++ * start pacing ourselves, not necessary but it's friendly. ++ */ ++ if ( pid == USB_PID_NAK || pid == USB_PID_NYET ) ++ dbgp_breathe(); ++ ++ /* If we got a NACK, reissue the transmission. */ ++ if ( pid != USB_PID_NAK || !--loop ) ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++static int dbgp_bulk_write(struct ehci_dbgp *dbgp, ++ unsigned int devnum, unsigned int endpoint, ++ const void *bytes, unsigned int size, u32 *pctrl) ++{ ++ u32 addr, pids, ctrl; ++ ++ if ( size > DBGP_MAX_PACKET ) ++ return -EINVAL; ++ ++ addr = DBGP_EPADDR(devnum, endpoint); ++ pids = dbgp_pid_write_update(readl(&dbgp->ehci_debug->pids), USB_PID_OUT); ++ ctrl = dbgp_len_update(readl(&dbgp->ehci_debug->control), size); ++ if ( pctrl ) ++ *pctrl = ctrl; ++ ++ dbgp_set_data(dbgp->ehci_debug, bytes, size); ++ writel(addr, &dbgp->ehci_debug->address); ++ writel(pids, &dbgp->ehci_debug->pids); ++ dbgp_issue_command(dbgp, ctrl, dbgp_out); ++ ++ return 0; ++} ++ ++static int dbgp_bulk_read(struct ehci_dbgp *dbgp, ++ unsigned int devnum, unsigned int endpoint, ++ unsigned int size, u32 *pctrl) ++{ ++ u32 addr, pids, ctrl; ++ ++ if ( size > DBGP_MAX_PACKET ) ++ return -EINVAL; ++ ++ addr = DBGP_EPADDR(devnum, endpoint); ++ pids = dbgp_pid_read_update(readl(&dbgp->ehci_debug->pids), USB_PID_IN); ++ ctrl = readl(&dbgp->ehci_debug->control) & ~DBGP_OUT; ++ ++ writel(addr, &dbgp->ehci_debug->address); ++ writel(pids, &dbgp->ehci_debug->pids); ++ if ( likely(!pctrl) ) ++ dbgp_issue_command(dbgp, ctrl, dbgp_in); ++ else ++ dbgp_issue_command(dbgp, *pctrl = ctrl, dbgp_ctrl); ++ ++ return 0; ++} ++ ++static int dbgp_control_msg(struct ehci_dbgp *dbgp, unsigned int devnum, ++ int requesttype, int request, int value, ++ int index, void *data, unsigned int size) ++{ ++ u32 addr, pids, ctrl; ++ struct usb_ctrlrequest req; ++ bool_t read = (requesttype & USB_DIR_IN) != 0; ++ int ret; ++ ++ if ( size > (read ? DBGP_MAX_PACKET : 0) ) ++ return -EINVAL; ++ ++ /* Compute the control message */ ++ req.bRequestType = requesttype; ++ req.bRequest = request; ++ req.wValue = cpu_to_le16(value); ++ req.wIndex = cpu_to_le16(index); ++ req.wLength = cpu_to_le16(size); ++ ++ pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); ++ addr = DBGP_EPADDR(devnum, 0); ++ ctrl = dbgp_len_update(readl(&dbgp->ehci_debug->control), sizeof(req)); ++ ++ /* Send the setup message */ ++ dbgp_set_data(dbgp->ehci_debug, &req, sizeof(req)); ++ writel(addr, &dbgp->ehci_debug->address); ++ writel(pids, &dbgp->ehci_debug->pids); ++ dbgp_issue_command(dbgp, ctrl, dbgp_ctrl); ++ ret = dbgp_wait_until_done(dbgp, ctrl, DBGP_LOOPS); ++ if ( ret < 0 ) ++ return ret; ++ ++ /* Read the result */ ++ ret = dbgp_bulk_read(dbgp, devnum, 0, size, &ctrl); ++ if ( !ret ) ++ ret = dbgp_wait_until_done(dbgp, ctrl, DBGP_LOOPS); ++ if ( ret > 0 ) ++ { ++ if ( size > ret ) ++ size = ret; ++ dbgp_get_data(dbgp->ehci_debug, data, size); ++ } ++ ++ return ret; ++} ++ ++static unsigned int __init __find_dbgp(u8 bus, u8 slot, u8 func) ++{ ++ u32 class = pci_conf_read32(0, bus, slot, func, PCI_CLASS_REVISION); ++ ++ if ( (class >> 8) != PCI_CLASS_SERIAL_USB_EHCI ) ++ return 0; ++ ++ return pci_find_cap_offset(0, bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); ++} ++ ++static unsigned int __init find_dbgp(struct ehci_dbgp *dbgp, ++ unsigned int ehci_num) ++{ ++ unsigned int bus, slot, func; ++ ++ for ( bus = 0; bus < 256; bus++ ) ++ { ++ for ( slot = 0; slot < 32; slot++ ) ++ { ++ for ( func = 0; func < 8; func++ ) ++ { ++ unsigned int cap; ++ ++ if ( !pci_device_detect(0, bus, slot, func) ) ++ { ++ if ( !func ) ++ break; ++ continue; ++ } ++ ++ cap = __find_dbgp(bus, slot, func); ++ if ( !cap || ehci_num-- ) ++ { ++ if ( !func && !(pci_conf_read8(0, bus, slot, func, ++ PCI_HEADER_TYPE) & 0x80) ) ++ break; ++ continue; ++ } ++ ++ dbgp->bus = bus; ++ dbgp->slot = slot; ++ dbgp->func = func; ++ return cap; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int ehci_dbgp_startup(struct ehci_dbgp *dbgp) ++{ ++ u32 ctrl, cmd, status; ++ unsigned int loop; ++ ++ /* Claim ownership, but do not enable yet */ ++ ctrl = readl(&dbgp->ehci_debug->control); ++ ctrl |= DBGP_OWNER; ++ ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); ++ writel(ctrl, &dbgp->ehci_debug->control); ++ udelay(1); ++ ++ ehci_dbgp_status(dbgp, "EHCI startup"); ++ /* Start the EHCI. */ ++ cmd = readl(&dbgp->ehci_regs->command); ++ cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); ++ cmd |= CMD_RUN; ++ writel(cmd, &dbgp->ehci_regs->command); ++ ++ /* Ensure everything is routed to the EHCI */ ++ writel(FLAG_CF, &dbgp->ehci_regs->configured_flag); ++ ++ /* Wait until the controller is no longer halted. */ ++ loop = 1000; ++ do { ++ status = readl(&dbgp->ehci_regs->status); ++ if ( !(status & STS_HALT) ) ++ break; ++ udelay(1); ++ } while ( --loop ); ++ ++ if ( !loop ) ++ { ++ dbgp_printk("EHCI cannot be started\n"); ++ return -ENODEV; ++ } ++ dbgp_printk("EHCI started\n"); ++ ++ return 0; ++} ++ ++static int ehci_dbgp_controller_reset(struct ehci_dbgp *dbgp) ++{ ++ unsigned int loop = 250 * 1000; ++ u32 cmd; ++ ++ /* Reset the EHCI controller */ ++ cmd = readl(&dbgp->ehci_regs->command); ++ cmd |= CMD_RESET; ++ writel(cmd, &dbgp->ehci_regs->command); ++ do { ++ cmd = readl(&dbgp->ehci_regs->command); ++ } while ( (cmd & CMD_RESET) && --loop ); ++ ++ if ( !loop ) ++ { ++ dbgp_printk("cannot reset EHCI\n"); ++ return -1; ++ } ++ ehci_dbgp_status(dbgp, "ehci reset done"); ++ ++ return 0; ++} ++ ++static int ehci_reset_port(struct ehci_dbgp *dbgp, unsigned int port) ++{ ++ u32 portsc, delay_time, delay; ++ ++ ehci_dbgp_status(dbgp, "reset port"); ++ /* Reset the USB debug port. */ ++ portsc = readl(&dbgp->ehci_regs->port_status[port - 1]); ++ portsc &= ~PORT_PE; ++ portsc |= PORT_RESET; ++ writel(portsc, &dbgp->ehci_regs->port_status[port - 1]); ++ ++ delay = HUB_ROOT_RESET_TIME; ++ for ( delay_time = 0; delay_time < HUB_RESET_TIMEOUT; ++ delay_time += delay ) ++ { ++ dbgp_mdelay(delay); ++ portsc = readl(&dbgp->ehci_regs->port_status[port - 1]); ++ if (!(portsc & PORT_RESET)) ++ break; ++ } ++ ++ if ( portsc & PORT_RESET ) ++ { ++ /* force reset to complete */ ++ unsigned int loop = 100 * 1000; ++ ++ writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), ++ &dbgp->ehci_regs->port_status[port - 1]); ++ do { ++ udelay(1); ++ portsc = readl(&dbgp->ehci_regs->port_status[port-1]); ++ } while ( (portsc & PORT_RESET) && --loop ); ++ } ++ ++ /* Device went away? */ ++ if ( !(portsc & PORT_CONNECT) ) ++ return -ENOTCONN; ++ ++ /* bomb out completely if something weird happened */ ++ if ( portsc & PORT_CSC ) ++ return -EINVAL; ++ ++ /* If we've finished resetting, then break out of the loop */ ++ if ( !(portsc & PORT_RESET) && (portsc & PORT_PE) ) ++ return 0; ++ ++ return -EBUSY; ++} ++ ++static int ehci_wait_for_port(struct ehci_dbgp *dbgp, unsigned int port) ++{ ++ u32 status; ++ unsigned int reps; ++ ++ for ( reps = 0; reps < 300; reps++ ) ++ { ++ status = readl(&dbgp->ehci_regs->status); ++ if ( status & STS_PCD ) ++ break; ++ dbgp_mdelay(1); ++ } ++ ++ return ehci_reset_port(dbgp, port) == 0 ? 0 : -ENOTCONN; ++} ++ ++/* Return 0 on success ++ * Return -ENODEV for any general failure ++ * Return -EIO if wait for port fails ++ */ ++static int ehci_dbgp_external_startup(struct ehci_dbgp *dbgp) ++{ ++ unsigned int devnum; ++ struct usb_debug_descriptor dbgp_desc; ++ int ret; ++ u32 ctrl, portsc, cmd; ++ unsigned int dbg_port = dbgp->phys_port; ++ unsigned int tries = 3; ++ unsigned int reset_port_tries = 1; ++ bool_t try_hard_once = 1; ++ ++try_port_reset_again: ++ ret = ehci_dbgp_startup(dbgp); ++ if ( ret ) ++ return ret; ++ ++ /* Wait for a device to show up in the debug port */ ++ ret = ehci_wait_for_port(dbgp, dbg_port); ++ if ( ret < 0 ) ++ { ++ portsc = readl(&dbgp->ehci_regs->port_status[dbg_port - 1]); ++ if ( !(portsc & PORT_CONNECT) && try_hard_once ) ++ { ++ /* ++ * Last ditch effort to try to force enable the debug device by ++ * using the packet test EHCI command to try and wake it up. ++ */ ++ try_hard_once = 0; ++ cmd = readl(&dbgp->ehci_regs->command); ++ cmd &= ~CMD_RUN; ++ writel(cmd, &dbgp->ehci_regs->command); ++ portsc = readl(&dbgp->ehci_regs->port_status[dbg_port - 1]); ++ portsc |= PORT_TEST_PKT; ++ writel(portsc, &dbgp->ehci_regs->port_status[dbg_port - 1]); ++ ehci_dbgp_status(dbgp, "Trying to force debug port online"); ++ mdelay(50); ++ ehci_dbgp_controller_reset(dbgp); ++ goto try_port_reset_again; ++ } ++ else if ( reset_port_tries-- ) ++ goto try_port_reset_again; ++ dbgp_printk("no device found in debug port\n"); ++ return -EIO; ++ } ++ ehci_dbgp_status(dbgp, "wait for port done"); ++ ++ /* Enable the debug port */ ++ ctrl = readl(&dbgp->ehci_debug->control); ++ ctrl |= DBGP_CLAIM; ++ writel(ctrl, &dbgp->ehci_debug->control); ++ ctrl = readl(&dbgp->ehci_debug->control); ++ if ( (ctrl & DBGP_CLAIM) != DBGP_CLAIM ) ++ { ++ dbgp_printk("no device in debug port\n"); ++ writel(ctrl & ~DBGP_CLAIM, &dbgp->ehci_debug->control); ++ return -ENODEV; ++ } ++ ehci_dbgp_status(dbgp, "debug port enabled"); ++ ++ /* Completely transfer the debug device to the debug controller */ ++ portsc = readl(&dbgp->ehci_regs->port_status[dbg_port - 1]); ++ portsc &= ~PORT_PE; ++ writel(portsc, &dbgp->ehci_regs->port_status[dbg_port - 1]); ++ ++ dbgp_mdelay(100); ++ ++try_again: ++ /* Find the debug device and make it device number 127 */ ++ for ( devnum = 0; devnum <= 127; devnum++ ) ++ { ++ ret = dbgp_control_msg(dbgp, devnum, ++ USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, ++ &dbgp_desc, sizeof(dbgp_desc)); ++ if ( ret > 0 ) ++ break; ++ } ++ if ( devnum > 127 ) ++ { ++ dbgp_printk("could not find attached debug device\n"); ++ goto err; ++ } ++ if ( ret < 0 ) ++ { ++ dbgp_printk("attached device is not a debug device\n"); ++ goto err; ++ } ++ dbgp->out.endpoint = dbgp_desc.bDebugOutEndpoint; ++ dbgp->in.endpoint = dbgp_desc.bDebugInEndpoint; ++ ++ /* Move the device to 127 if it isn't already there. */ ++ if ( devnum != USB_DEBUG_DEVNUM ) ++ { ++ ret = dbgp_control_msg(dbgp, devnum, ++ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); ++ if ( ret < 0 ) ++ { ++ dbgp_printk("could not move attached device to %d\n", ++ USB_DEBUG_DEVNUM); ++ goto err; ++ } ++ devnum = USB_DEBUG_DEVNUM; ++ dbgp_printk("debug device renamed to 127\n"); ++ } ++ ++ /* Enable the debug interface */ ++ ret = dbgp_control_msg(dbgp, USB_DEBUG_DEVNUM, ++ USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, ++ USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, ++ 0, NULL, 0); ++ if ( ret < 0 ) ++ { ++ dbgp_printk("could not enable the debug device\n"); ++ goto err; ++ } ++ dbgp_printk("debug interface enabled\n"); ++ ++ /* Perform a small write to get the even/odd data state in sync. */ ++ ret = dbgp_bulk_write(dbgp, USB_DEBUG_DEVNUM, dbgp->out.endpoint, ++ "\n", 1, &ctrl); ++ if ( !ret ) ++ ret = dbgp_wait_until_done(dbgp, ctrl, DBGP_LOOPS); ++ if ( ret < 0 ) ++ { ++ dbgp_printk("dbgp_bulk_write failed: %d\n", ret); ++ goto err; ++ } ++ dbgp_printk("small write done\n"); ++ dbgp->state = dbgp_idle; ++ ++ return 0; ++err: ++ if ( tries-- ) ++ goto try_again; ++ return -ENODEV; ++} ++ ++typedef void (*set_debug_port_t)(struct ehci_dbgp *, unsigned int); ++ ++static void default_set_debug_port(struct ehci_dbgp *dbgp, unsigned int port) ++{ ++} ++ ++static set_debug_port_t __read_mostly set_debug_port = default_set_debug_port; ++ ++static void nvidia_set_debug_port(struct ehci_dbgp *dbgp, unsigned int port) ++{ ++ u32 dword = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, 0x74); ++ ++ dword &= ~(0x0f << 12); ++ dword |= (port & 0x0f) << 12; ++ pci_conf_write32(0, dbgp->bus, dbgp->slot, dbgp->func, 0x74, dword); ++ dbgp_printk("set debug port to %u\n", port); ++} ++ ++static void __init detect_set_debug_port(struct ehci_dbgp *dbgp) ++{ ++ if ( pci_conf_read16(0, dbgp->bus, dbgp->slot, dbgp->func, ++ PCI_VENDOR_ID) == 0x10de ) ++ { ++ dbgp_printk("using nvidia set_debug_port\n"); ++ set_debug_port = nvidia_set_debug_port; ++ } ++} ++ ++/* ++ * The code in ehci_dbgp_bios_handoff() is derived from the USB PCI ++ * quirk initialization in Linux. ++ */ ++#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ ++#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ ++static void ehci_dbgp_bios_handoff(struct ehci_dbgp *dbgp, u32 hcc_params) ++{ ++ u32 cap; ++ unsigned int offset = HCC_EXT_CAPS(hcc_params); ++ int msec; ++ ++ if ( !offset ) ++ return; ++ ++ cap = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, offset); ++ dbgp_printk("dbgp: EHCI BIOS state %08x\n", cap); ++ ++ if ( (cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS) ) ++ { ++ dbgp_printk("dbgp: BIOS handoff\n"); ++ pci_conf_write8(0, dbgp->bus, dbgp->slot, dbgp->func, offset + 3, 1); ++ } ++ ++ /* if boot firmware now owns EHCI, spin till it hands it over. */ ++ msec = 1000; ++ while ( (cap & EHCI_USBLEGSUP_BIOS) && (msec > 0) ) ++ { ++ mdelay(10); ++ msec -= 10; ++ cap = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, offset); ++ } ++ ++ if ( cap & EHCI_USBLEGSUP_BIOS ) ++ { ++ /* well, possibly buggy BIOS... try to shut it down, ++ * and hope nothing goes too wrong */ ++ dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap); ++ pci_conf_write8(0, dbgp->bus, dbgp->slot, dbgp->func, offset + 2, 0); ++ } ++ ++ /* just in case, always disable EHCI SMIs */ ++ pci_conf_write8(0, dbgp->bus, dbgp->slot, dbgp->func, ++ offset + EHCI_USBLEGCTLSTS, 0); ++} ++ ++static int ehci_dbgp_setup(struct ehci_dbgp *dbgp) ++{ ++ u32 ctrl, portsc, hcs_params; ++ unsigned int i, debug_port, new_debug_port = 0, n_ports; ++ unsigned int port_map_tried, playtimes = 3; ++ int ret; ++ ++ ehci_dbgp_bios_handoff(dbgp, readl(&dbgp->ehci_caps->hcc_params)); ++ ++try_next_time: ++ port_map_tried = 0; ++ ++try_next_port: ++ ++ hcs_params = readl(&dbgp->ehci_caps->hcs_params); ++ debug_port = HCS_DEBUG_PORT(hcs_params); ++ dbgp->phys_port = debug_port; ++ n_ports = HCS_N_PORTS(hcs_params); ++ ++ dbgp_printk("debug_port: %u\n", debug_port); ++ dbgp_printk("n_ports: %u\n", n_ports); ++ ehci_dbgp_status(dbgp, ""); ++ ++ for ( i = 1; i <= n_ports; i++ ) ++ { ++ portsc = readl(&dbgp->ehci_regs->port_status[i-1]); ++ dbgp_printk("portstatus%d: %08x\n", i, portsc); ++ } ++ ++ if ( port_map_tried && (new_debug_port != debug_port) ) ++ { ++ if ( --playtimes ) ++ { ++ set_debug_port(dbgp, new_debug_port); ++ goto try_next_time; ++ } ++ return -1; ++ } ++ ++ /* Only reset the controller if it is not already in the ++ * configured state */ ++ if ( readl(&dbgp->ehci_regs->configured_flag) & FLAG_CF ) ++ ehci_dbgp_status(dbgp, "ehci skip - already configured"); ++ else if ( ehci_dbgp_controller_reset(dbgp) != 0 ) ++ return -1; ++ ++ ret = ehci_dbgp_external_startup(dbgp); ++ if (ret == -EIO) ++ goto next_debug_port; ++ ++ if ( ret < 0 ) ++ { ++ /* Things didn't work so remove my claim */ ++ ctrl = readl(&dbgp->ehci_debug->control); ++ ctrl &= ~(DBGP_CLAIM | DBGP_OUT); ++ writel(ctrl, &dbgp->ehci_debug->control); ++ return -1; ++ } ++ ++ return 0; ++ ++next_debug_port: ++ port_map_tried |= 1 << (debug_port - 1); ++ new_debug_port = (debug_port % n_ports) + 1; ++ if ( port_map_tried != ((1 << n_ports) - 1) ) ++ { ++ set_debug_port(dbgp, new_debug_port); ++ goto try_next_port; ++ } ++ if ( --playtimes ) ++ { ++ set_debug_port(dbgp, new_debug_port); ++ goto try_next_time; ++ } ++ ++ return -1; ++} ++ ++static inline void _ehci_dbgp_flush(struct ehci_dbgp *dbgp) ++{ ++ if ( dbgp_bulk_write(dbgp, USB_DEBUG_DEVNUM, dbgp->out.endpoint, ++ dbgp->out.buf, dbgp->out.chunk, NULL) ) ++ BUG(); ++ dbgp->out.chunk = 0; ++} ++ ++static void ehci_dbgp_flush(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ s_time_t goal; ++ ++ if ( !dbgp->out.chunk || !dbgp->ehci_debug || dbgp->state == dbgp_unsafe ) ++ return; ++ ++ if ( dbgp->state == dbgp_idle || !port->sync ) ++ dbgp_check_for_completion(dbgp, 1, NULL); ++ else ++ dbgp_wait_until_complete(dbgp, NULL); ++ ++ if ( dbgp->state == dbgp_idle ) ++ { ++ _ehci_dbgp_flush(dbgp); ++ ++ if ( port->sync ) ++ { ++ dbgp_wait_until_complete(dbgp, NULL); ++ return; ++ } ++ } ++ ++ goal = NOW() + MICROSECS(DBGP_CHECK_INTERVAL); ++ if ( dbgp->timer.expires > goal ) ++ set_timer(&dbgp->timer, goal); ++} ++ ++static void ehci_dbgp_putc(struct serial_port *port, char c) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( unlikely(dbgp->out.chunk >= DBGP_MAX_PACKET) ) ++ return; ++ ++ dbgp->out.buf[dbgp->out.chunk++] = c; ++ ++ if ( dbgp->out.chunk == DBGP_MAX_PACKET ) ++ ehci_dbgp_flush(port); ++} ++ ++static int ehci_dbgp_tx_empty(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( unlikely(!dbgp->ehci_debug) || unlikely(dbgp->state == dbgp_unsafe) ) ++ return port->sync || port->tx_log_everything || !port->txbuf; ++ ++ if ( dbgp->out.chunk == DBGP_MAX_PACKET ) ++ ehci_dbgp_flush(port); ++ else ++ dbgp_check_for_completion(dbgp, 1, NULL); ++ ++ if ( dbgp->state != dbgp_idle && dbgp->out.chunk >= DBGP_MAX_PACKET ) ++ return 0; ++ ++ port->tx_fifo_size = DBGP_MAX_PACKET - dbgp->out.chunk; ++ if ( dbgp->state == dbgp_idle ) ++ port->tx_fifo_size += DBGP_MAX_PACKET; ++ ++ return 1; ++} ++ ++static int ehci_dbgp_getc(struct serial_port *port, char *pc) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( !dbgp->in.chunk ) ++ return 0; ++ ++ *pc = *dbgp->in.buf; ++ if ( --dbgp->in.chunk ) ++ memmove(dbgp->in.buf, dbgp->in.buf + 1, dbgp->in.chunk); ++ ++ return 1; ++} ++ ++/* Safe: ehci_dbgp_poll() runs as timer handler, so not reentrant. */ ++static struct serial_port *poll_port; ++ ++static void _ehci_dbgp_poll(struct cpu_user_regs *regs) ++{ ++ struct serial_port *port = poll_port; ++ struct ehci_dbgp *dbgp = port->uart; ++ unsigned long flags; ++ unsigned int timeout = MICROSECS(DBGP_CHECK_INTERVAL); ++ bool_t empty = 0; ++ ++ if ( !dbgp->ehci_debug ) ++ return; ++ ++ if ( spin_trylock_irqsave(&port->tx_lock, flags) ) ++ { ++ if ( dbgp->state != dbgp_unsafe ) ++ dbgp_check_for_completion(dbgp, DBGP_CHECK_INTERVAL, NULL); ++ if ( dbgp->state == dbgp_idle && dbgp->out.chunk ) ++ _ehci_dbgp_flush(dbgp); ++ if ( dbgp->state == dbgp_idle || dbgp->out.chunk < DBGP_MAX_PACKET ) ++ empty = 1; ++ spin_unlock_irqrestore(&port->tx_lock, flags); ++ } ++ ++ if ( dbgp->in.chunk ) ++ serial_rx_interrupt(port, regs); ++ ++ if ( empty ) ++ serial_tx_interrupt(port, regs); ++ ++ if ( spin_trylock_irqsave(&port->tx_lock, flags) ) ++ { ++ if ( dbgp->state == dbgp_idle && !dbgp->in.chunk && ++ !dbgp->out.chunk && port->txbufp == port->txbufc ) ++ { ++ if ( dbgp_bulk_read(dbgp, USB_DEBUG_DEVNUM, dbgp->in.endpoint, ++ DBGP_MAX_PACKET, NULL) ) ++ BUG(); ++ timeout = MILLISECS(DBGP_IDLE_INTERVAL); ++ } ++ spin_unlock_irqrestore(&port->tx_lock, flags); ++ } ++ ++ set_timer(&dbgp->timer, NOW() + timeout); ++} ++ ++static void ehci_dbgp_poll(void *data) ++{ ++ poll_port = data; ++#ifdef run_in_exception_handler ++ run_in_exception_handler(_ehci_dbgp_poll); ++#else ++ _ehci_dbgp_poll(guest_cpu_user_regs()); ++#endif ++} ++ ++static bool_t ehci_dbgp_setup_preirq(struct ehci_dbgp *dbgp) ++{ ++ if ( !ehci_dbgp_setup(dbgp) ) ++ return 1; ++ ++ dbgp_printk("ehci_dbgp_setup failed\n"); ++ dbgp->ehci_debug = NULL; ++ return 0; ++} ++ ++static void __init ehci_dbgp_init_preirq(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ u32 debug_port, offset; ++ void __iomem *ehci_bar; ++ ++ debug_port = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, ++ dbgp->cap); ++ offset = (debug_port >> 16) & 0xfff; ++ ++ /* double check if the mem space is enabled */ ++ dbgp->pci_cr = pci_conf_read8(0, dbgp->bus, dbgp->slot, dbgp->func, ++ PCI_COMMAND); ++ if ( !(dbgp->pci_cr & PCI_COMMAND_MEMORY) ) ++ { ++ dbgp->pci_cr |= PCI_COMMAND_MEMORY; ++ pci_conf_write16(0, dbgp->bus, dbgp->slot, dbgp->func, PCI_COMMAND, ++ dbgp->pci_cr); ++ dbgp_printk("MMIO for EHCI enabled\n"); ++ } ++ ++ /* ++ * FIXME I don't have the bar size so just guess PAGE_SIZE is more ++ * than enough. 1k is the biggest that was seen. ++ */ ++ set_fixmap_nocache(FIX_EHCI_DBGP, dbgp->bar_val); ++ ehci_bar = (void __iomem *)fix_to_virt(FIX_EHCI_DBGP); ++ ehci_bar += dbgp->bar_val & ~PAGE_MASK; ++ dbgp_printk("ehci_bar: %p\n", ehci_bar); ++ ++ dbgp->ehci_caps = ehci_bar; ++ dbgp->ehci_regs = ehci_bar + ++ HC_LENGTH(readl(&dbgp->ehci_caps->hc_capbase)); ++ dbgp->ehci_debug = ehci_bar + offset; ++ ++ detect_set_debug_port(dbgp); ++ ++ if ( ehci_dbgp_setup_preirq(dbgp) ) ++ ehci_dbgp_status(dbgp, "ehci_dbgp_init_preirq complete"); ++ ++ port->tx_fifo_size = DBGP_MAX_PACKET; ++ dbgp->lock = &port->tx_lock; ++} ++ ++static void ehci_dbgp_setup_postirq(struct ehci_dbgp *dbgp) ++{ ++ set_timer(&dbgp->timer, NOW() + MILLISECS(1)); ++} ++ ++static void __init ehci_dbgp_init_postirq(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( !dbgp->ehci_debug ) ++ return; ++ ++ serial_async_transmit(port); ++ ++ init_timer(&dbgp->timer, ehci_dbgp_poll, port, 0); ++ ++ ehci_dbgp_setup_postirq(dbgp); ++} ++ ++static int ehci_dbgp_check_release(struct ehci_dbgp *dbgp) ++{ ++ struct ehci_dbg_port __iomem *ehci_debug = dbgp->ehci_debug; ++ u32 ctrl; ++ unsigned int i; ++ ++ if ( !ehci_debug ) ++ return 0; ++ ++ for ( i = 0; i < DBGP_MAX_PACKET; ++i ) ++ if ( dbgp->out.buf[i] ) ++ return 1; ++ ++ /* ++ * This means the console is not initialized, or should get shutdown ++ * so as to allow for reuse of the USB device, which means it is time ++ * to shutdown the USB debug port. ++ */ ++ printk(XENLOG_INFO "Releasing EHCI debug port at %02x:%02x.%u\n", ++ dbgp->bus, dbgp->slot, dbgp->func); ++ ++ kill_timer(&dbgp->timer); ++ dbgp->ehci_debug = NULL; ++ ++ ctrl = readl(&ehci_debug->control); ++ if ( ctrl & DBGP_ENABLED ) ++ { ++ ctrl &= ~DBGP_CLAIM; ++ writel(ctrl, &ehci_debug->control); ++ } ++ ++ return 0; ++} ++ ++static void __init ehci_dbgp_endboot(struct serial_port *port) ++{ ++ ehci_dbgp_check_release(port->uart); ++} ++ ++static void ehci_dbgp_suspend(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( !dbgp->ehci_debug ) ++ return; ++ ++ stop_timer(&dbgp->timer); ++ dbgp->timer.expires = 0; ++ ++ dbgp->pci_cr = pci_conf_read16(0, dbgp->bus, dbgp->slot, dbgp->func, ++ PCI_COMMAND); ++ ++ dbgp->state = dbgp_unsafe; ++} ++ ++static void ehci_dbgp_resume(struct serial_port *port) ++{ ++ struct ehci_dbgp *dbgp = port->uart; ++ ++ if ( !dbgp->ehci_debug ) ++ return; ++ ++ pci_conf_write32(0, dbgp->bus, dbgp->slot, dbgp->func, dbgp->bar, ++ dbgp->bar_val); ++ pci_conf_write16(0, dbgp->bus, dbgp->slot, dbgp->func, ++ PCI_COMMAND, dbgp->pci_cr); ++ ++ ehci_dbgp_setup_preirq(dbgp); ++ ehci_dbgp_setup_postirq(dbgp); ++} ++ ++static struct uart_driver __read_mostly ehci_dbgp_driver = { ++ .init_preirq = ehci_dbgp_init_preirq, ++ .init_postirq = ehci_dbgp_init_postirq, ++ .endboot = ehci_dbgp_endboot, ++ .suspend = ehci_dbgp_suspend, ++ .resume = ehci_dbgp_resume, ++ .tx_empty = ehci_dbgp_tx_empty, ++ .putc = ehci_dbgp_putc, ++ .flush = ehci_dbgp_flush, ++ .getc = ehci_dbgp_getc ++}; ++ ++static struct ehci_dbgp ehci_dbgp = { .state = dbgp_unsafe, .phys_port = 1 }; ++ ++static char __initdata opt_dbgp[30]; ++string_param("dbgp", opt_dbgp); ++ ++void __init ehci_dbgp_init(void) ++{ ++ struct ehci_dbgp *dbgp = &ehci_dbgp; ++ u32 debug_port, offset, bar_val; ++ const char *e; ++ ++ if ( strncmp(opt_dbgp, "ehci", 4) ) ++ return; ++ ++ if ( isdigit(opt_dbgp[4]) || !opt_dbgp[4] ) ++ { ++ unsigned int num = 0; ++ ++ if ( opt_dbgp[4] ) ++ simple_strtoul(opt_dbgp + 4, &e, 10); ++ ++ dbgp->cap = find_dbgp(dbgp, num); ++ if ( !dbgp->cap ) ++ return; ++ ++ dbgp_printk("Found EHCI debug port on %02x:%02x.%u\n", ++ dbgp->bus, dbgp->slot, dbgp->func); ++ } ++ else if ( strncmp(opt_dbgp + 4, "@pci", 4) == 0 ) ++ { ++ unsigned long val = simple_strtoul(opt_dbgp + 8, &e, 16); ++ ++ dbgp->bus = val; ++ if ( dbgp->bus != val || *e != ':' ) ++ return; ++ ++ val = simple_strtoul(e + 1, &e, 16); ++ if ( PCI_SLOT(PCI_DEVFN(val, 0)) != val || *e != '.' ) ++ return; ++ dbgp->slot = val; ++ ++ val = simple_strtoul(e + 1, &e, 16); ++ if ( PCI_FUNC(PCI_DEVFN(0, val)) != val || *e ) ++ return; ++ dbgp->func = val; ++ ++ if ( !pci_device_detect(0, dbgp->bus, dbgp->slot, dbgp->func) ) ++ return; ++ ++ dbgp->cap = __find_dbgp(dbgp->bus, dbgp->slot, dbgp->func); ++ if ( !dbgp->cap ) ++ return; ++ ++ dbgp_printk("Using EHCI debug port on %02x:%02x.%u\n", ++ dbgp->bus, dbgp->slot, dbgp->func); ++ } ++ else ++ return; ++ ++ debug_port = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, ++ dbgp->cap); ++ dbgp->bar = (debug_port >> 29) & 0x7; ++ dbgp->bar = ((dbgp->bar - 1) * 4) + PCI_BASE_ADDRESS_0; ++ offset = (debug_port >> 16) & 0xfff; ++ dbgp_printk("bar: %02x offset: %03x\n", dbgp->bar, offset); ++ if ( dbgp->bar < PCI_BASE_ADDRESS_0 || dbgp->bar > PCI_BASE_ADDRESS_5 ) ++ { ++ dbgp_printk("unsupported/invalid bar\n"); ++ return; ++ } ++ ++ dbgp->bar_val = bar_val = pci_conf_read32(0, dbgp->bus, dbgp->slot, ++ dbgp->func, dbgp->bar); ++ dbgp_printk("bar_val: %08x\n", bar_val); ++ if ( bar_val & ~PCI_BASE_ADDRESS_MEM_MASK ) ++ { ++ dbgp_printk("only simple 32-bit MMIO BARs supported\n"); ++ return; ++ } ++ bar_val &= PCI_BASE_ADDRESS_MEM_MASK; ++ if ( !bar_val || !(bar_val + (bar_val & -bar_val)) ) ++ { ++ dbgp_printk("firmware initialization of MMIO BAR required\n"); ++ return; ++ } ++ ++ serial_register_uart(SERHND_DBGP, &ehci_dbgp_driver, dbgp); ++} ++ ++int dbgp_op(const struct physdev_dbgp_op *op) ++{ ++ if ( !ehci_dbgp.ehci_debug ) ++ return 0; ++ ++ switch ( op->bus ) ++ { ++ case PHYSDEVOP_DBGP_BUS_UNKNOWN: ++ break; ++ case PHYSDEVOP_DBGP_BUS_PCI: ++ if ( op->u.pci.seg || ehci_dbgp.bus != op->u.pci.bus || ++ PCI_DEVFN(ehci_dbgp.slot, ehci_dbgp.func) != op->u.pci.devfn ) ++ default: ++ return 0; ++ break; ++ } ++ ++ switch ( op->op ) ++ { ++ case PHYSDEVOP_DBGP_RESET_PREPARE: ++ spin_lock_irq(ehci_dbgp.lock); ++ ehci_dbgp.state = dbgp_unsafe; ++ dbgp_wait_until_complete(&ehci_dbgp, NULL); ++ spin_unlock_irq(ehci_dbgp.lock); ++ ++ return ehci_dbgp_check_release(&ehci_dbgp); ++ ++ case PHYSDEVOP_DBGP_RESET_DONE: ++ return ehci_dbgp_external_startup(&ehci_dbgp) ?: 1; ++ } ++ ++ return -ENOSYS; ++} +--- a/xen/drivers/char/serial.c ++++ b/xen/drivers/char/serial.c +@@ -265,6 +265,14 @@ int __init serial_parse_handle(char *con + { + int handle; + ++ if ( !strncmp(conf, "dbgp", 4) && (!conf[4] || conf[4] == ',') ) ++ { ++ if ( !com[SERHND_DBGP].driver ) ++ goto fail; ++ ++ return SERHND_DBGP | SERHND_COOKED; ++ } ++ + if ( strncmp(conf, "com", 3) ) + goto fail; + +--- a/xen/include/asm-x86/fixmap.h ++++ b/xen/include/asm-x86/fixmap.h +@@ -36,7 +36,15 @@ + * from the end of virtual memory backwards. + */ + enum fixed_addresses { +- FIX_RESERVED, /* Index 0 is reserved since fix_to_virt(0) > FIXADDR_TOP. */ ++ /* Index 0 is reserved since fix_to_virt(0) == FIXADDR_TOP. */ ++ FIX_RESERVED, ++ /* ++ * Indexes using the page tables set up before entering __start_xen() ++ * must be among the first (L1_PAGETABLE_ENTRIES - 1) entries. ++ * These are generally those needed by the various console drivers. ++ */ ++ FIX_EHCI_DBGP, ++ /* Everything else should go further down. */ + #ifdef __i386__ + FIX_PAE_HIGHMEM_0, + FIX_PAE_HIGHMEM_END = FIX_PAE_HIGHMEM_0 + NR_CPUS-1, +--- a/xen/include/public/physdev.h ++++ b/xen/include/public/physdev.h +@@ -312,6 +312,24 @@ struct physdev_pci_device { + typedef struct physdev_pci_device physdev_pci_device_t; + DEFINE_XEN_GUEST_HANDLE(physdev_pci_device_t); + ++#define PHYSDEVOP_DBGP_RESET_PREPARE 1 ++#define PHYSDEVOP_DBGP_RESET_DONE 2 ++ ++#define PHYSDEVOP_DBGP_BUS_UNKNOWN 0 ++#define PHYSDEVOP_DBGP_BUS_PCI 1 ++ ++#define PHYSDEVOP_dbgp_op 29 ++struct physdev_dbgp_op { ++ /* IN */ ++ uint8_t op; ++ uint8_t bus; ++ union { ++ struct physdev_pci_device pci; ++ } u; ++}; ++typedef struct physdev_dbgp_op physdev_dbgp_op_t; ++DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t); ++ + /* + * Notify that some PIRQ-bound event channels have been unmasked. + * ** This command is obsolete since interface version 0x00030202 and is ** +--- a/xen/include/xen/serial.h ++++ b/xen/include/xen/serial.h +@@ -69,9 +69,10 @@ struct uart_driver { + }; + + /* 'Serial handles' are composed from the following fields. */ +-#define SERHND_IDX (3<<0) /* COM1 or COM2? */ ++#define SERHND_IDX (3<<0) /* COM1, COM2, or DBGP? */ + # define SERHND_COM1 (0<<0) + # define SERHND_COM2 (1<<0) ++# define SERHND_DBGP (2<<0) + #define SERHND_HI (1<<2) /* Mux/demux each transferred char by MSB. */ + #define SERHND_LO (1<<3) /* Ditto, except that the MSB is cleared. */ + #define SERHND_COOKED (1<<4) /* Newline/carriage-return translation? */ +@@ -142,9 +143,13 @@ struct ns16550_defaults { + unsigned long io_base; /* default io_base address */ + }; + void ns16550_init(int index, struct ns16550_defaults *defaults); ++void ehci_dbgp_init(void); + + void pl011_init(int index, unsigned long register_base_address); + ++struct physdev_dbgp_op; ++int dbgp_op(const struct physdev_dbgp_op *); ++ + /* Baud rate was pre-configured before invoking the UART driver. */ + #define BAUD_AUTO (-1) + diff --git a/25864-sercon-unused.patch b/25864-sercon-unused.patch new file mode 100644 index 0000000..9830025 --- /dev/null +++ b/25864-sercon-unused.patch @@ -0,0 +1,142 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371512 -7200 +# Node ID e1380b5311ccee14eb47d7badb75339933d42249 +# Parent 0d0c55a1975db9c6cac2e9259b5ebea7a7bdbaec +serial: avoid fully initializing unused consoles + +Defer calling the drivers' post-IRQ initialization functions (generally +doing allocation of transmit buffers) until it is known that the +respective console is actually going to be used. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/drivers/char/ehci-dbgp.c ++++ b/xen/drivers/char/ehci-dbgp.c +@@ -1391,7 +1391,8 @@ static int ehci_dbgp_check_release(struc + printk(XENLOG_INFO "Releasing EHCI debug port at %02x:%02x.%u\n", + dbgp->bus, dbgp->slot, dbgp->func); + +- kill_timer(&dbgp->timer); ++ if ( dbgp->timer.function ) ++ kill_timer(&dbgp->timer); + dbgp->ehci_debug = NULL; + + ctrl = readl(&ehci_debug->control); +--- a/xen/drivers/char/serial.c ++++ b/xen/drivers/char/serial.c +@@ -29,6 +29,8 @@ static struct serial_port com[SERHND_IDX + } + }; + ++static bool_t __read_mostly post_irq; ++ + void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) + { + char c; +@@ -263,14 +265,12 @@ char serial_getc(int handle) + + int __init serial_parse_handle(char *conf) + { +- int handle; ++ int handle, flags = 0; + + if ( !strncmp(conf, "dbgp", 4) && (!conf[4] || conf[4] == ',') ) + { +- if ( !com[SERHND_DBGP].driver ) +- goto fail; +- +- return SERHND_DBGP | SERHND_COOKED; ++ handle = SERHND_DBGP; ++ goto common; + } + + if ( strncmp(conf, "com", 3) ) +@@ -288,17 +288,25 @@ int __init serial_parse_handle(char *con + goto fail; + } + +- if ( !com[handle].driver ) +- goto fail; +- + if ( conf[4] == 'H' ) +- handle |= SERHND_HI; ++ flags |= SERHND_HI; + else if ( conf[4] == 'L' ) +- handle |= SERHND_LO; ++ flags |= SERHND_LO; + +- handle |= SERHND_COOKED; ++ common: ++ if ( !com[handle].driver ) ++ goto fail; ++ ++ if ( !post_irq ) ++ com[handle].state = serial_parsed; ++ else if ( com[handle].state != serial_initialized ) ++ { ++ if ( com[handle].driver->init_postirq ) ++ com[handle].driver->init_postirq(&com[handle]); ++ com[handle].state = serial_initialized; ++ } + +- return handle; ++ return handle | flags | SERHND_COOKED; + + fail: + return -1; +@@ -450,8 +458,13 @@ void __init serial_init_postirq(void) + { + int i; + for ( i = 0; i < ARRAY_SIZE(com); i++ ) +- if ( com[i].driver && com[i].driver->init_postirq ) +- com[i].driver->init_postirq(&com[i]); ++ if ( com[i].state == serial_parsed ) ++ { ++ if ( com[i].driver->init_postirq ) ++ com[i].driver->init_postirq(&com[i]); ++ com[i].state = serial_initialized; ++ } ++ post_irq = 1; + } + + void __init serial_endboot(void) +@@ -475,7 +488,7 @@ void serial_suspend(void) + { + int i; + for ( i = 0; i < ARRAY_SIZE(com); i++ ) +- if ( com[i].driver && com[i].driver->suspend ) ++ if ( com[i].state == serial_initialized && com[i].driver->suspend ) + com[i].driver->suspend(&com[i]); + } + +@@ -483,7 +496,7 @@ void serial_resume(void) + { + int i; + for ( i = 0; i < ARRAY_SIZE(com); i++ ) +- if ( com[i].driver && com[i].driver->resume ) ++ if ( com[i].state == serial_initialized && com[i].driver->resume ) + com[i].driver->resume(&com[i]); + } + +--- a/xen/include/xen/serial.h ++++ b/xen/include/xen/serial.h +@@ -25,10 +25,17 @@ extern unsigned int serial_txbufsz; + + struct uart_driver; + ++enum serial_port_state { ++ serial_unused, ++ serial_parsed, ++ serial_initialized ++}; ++ + struct serial_port { + /* Uart-driver parameters. */ + struct uart_driver *driver; + void *uart; ++ enum serial_port_state state; + /* Number of characters the port can hold for transmit. */ + int tx_fifo_size; + /* Transmit data buffer (interrupt-driven uart). */ diff --git a/25866-sercon-ns16550-pci-irq.patch b/25866-sercon-ns16550-pci-irq.patch new file mode 100644 index 0000000..8856988 --- /dev/null +++ b/25866-sercon-ns16550-pci-irq.patch @@ -0,0 +1,56 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371733 -7200 +# Node ID ee12dc357fbecbb0517798f395d14bf1764c6766 +# Parent 5fb5b3b70e34ef278d06aff27878b4b8e6d9145f +ns16550: PCI initialization adjustments + +Besides single-port serial cards, also accept multi-port ones and such +providing mixed functionality (e.g. also having a parallel port). + +Reading PCI_INTERRUPT_PIN before ACPI gets enabled generally produces +an incorrect IRQ (below 16, whereas after enabling ACPI it frequently +would end up at a higher one), so this is useful (almost) only when a +system already boots in ACPI mode. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/xen/drivers/char/ns16550.c ++++ b/xen/drivers/char/ns16550.c +@@ -449,7 +449,6 @@ static int __init check_existence(struct + static int + pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx) + { +- uint16_t class; + uint32_t bar, len; + int b, d, f; + +@@ -460,9 +459,15 @@ pci_uart_config (struct ns16550 *uart, i + { + for ( f = 0; f < 0x8; f++ ) + { +- class = pci_conf_read16(0, b, d, f, PCI_CLASS_DEVICE); +- if ( class != 0x700 ) ++ switch ( pci_conf_read16(0, b, d, f, PCI_CLASS_DEVICE) ) ++ { ++ case 0x0700: /* single port serial */ ++ case 0x0702: /* multi port serial */ ++ case 0x0780: /* other (e.g serial+parallel) */ ++ break; ++ default: + continue; ++ } + + bar = pci_conf_read32(0, b, d, f, + PCI_BASE_ADDRESS_0 + bar_idx*4); +@@ -485,7 +490,8 @@ pci_uart_config (struct ns16550 *uart, i + uart->bar = bar; + uart->bar_idx = bar_idx; + uart->io_base = bar & 0xfffe; +- uart->irq = 0; ++ uart->irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ? ++ pci_conf_read8(0, b, d, f, PCI_INTERRUPT_LINE) : 0; + + return 0; + } diff --git a/25867-sercon-ns16550-parse.patch b/25867-sercon-ns16550-parse.patch new file mode 100644 index 0000000..9bd872c --- /dev/null +++ b/25867-sercon-ns16550-parse.patch @@ -0,0 +1,100 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347371805 -7200 +# Node ID b22f184e1a3cac03abeed92ec4b74235fd0881f4 +# Parent ee12dc357fbecbb0517798f395d14bf1764c6766 +ns16550: command line parsing adjustments + +Allow intermediate parts of the command line options to be absent +(expressed by two immediately succeeding commas). + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/docs/misc/xen-command-line.markdown ++++ b/docs/misc/xen-command-line.markdown +@@ -199,7 +199,7 @@ If set, override Xen's calculation of th + If set, override Xen's default choice for the platform timer. + + ### com1,com2 +-> `= [/][,DPS[,[,[,[,]]]] | pci | amt ] ` ++> `= [/][,[DPS][,[|pci|amt][,[][,[][,[]]]]]]` + + Both option `com1` and `com2` follow the same format. + +--- a/xen/drivers/char/ns16550.c ++++ b/xen/drivers/char/ns16550.c +@@ -536,26 +536,23 @@ static void __init ns16550_parse_port_co + else if ( (baud = simple_strtoul(conf, &conf, 10)) != 0 ) + uart->baud = baud; + +- if ( *conf == '/') ++ if ( *conf == '/' ) + { + conf++; + uart->clock_hz = simple_strtoul(conf, &conf, 0) << 4; + } + +- if ( *conf != ',' ) +- goto config_parsed; +- conf++; +- +- uart->data_bits = simple_strtoul(conf, &conf, 10); ++ if ( *conf == ',' && *++conf != ',' ) ++ { ++ uart->data_bits = simple_strtoul(conf, &conf, 10); + +- uart->parity = parse_parity_char(*conf); +- conf++; ++ uart->parity = parse_parity_char(*conf); + +- uart->stop_bits = simple_strtoul(conf, &conf, 10); ++ uart->stop_bits = simple_strtoul(conf + 1, &conf, 10); ++ } + +- if ( *conf == ',' ) ++ if ( *conf == ',' && *++conf != ',' ) + { +- conf++; + if ( strncmp(conf, "pci", 3) == 0 ) + { + if ( pci_uart_config(uart, 1/* skip AMT */, uart - ns16550_com) ) +@@ -572,24 +569,21 @@ static void __init ns16550_parse_port_co + { + uart->io_base = simple_strtoul(conf, &conf, 0); + } ++ } + +- if ( *conf == ',' ) +- { +- conf++; +- uart->irq = simple_strtoul(conf, &conf, 10); +- if ( *conf == ',' ) +- { +- conf++; +- uart->ps_bdf_enable = 1; +- parse_pci_bdf(&conf, &uart->ps_bdf[0]); +- if ( *conf == ',' ) +- { +- conf++; +- uart->pb_bdf_enable = 1; +- parse_pci_bdf(&conf, &uart->pb_bdf[0]); +- } +- } +- } ++ if ( *conf == ',' && *++conf != ',' ) ++ uart->irq = simple_strtol(conf, &conf, 10); ++ ++ if ( *conf == ',' && *++conf != ',' ) ++ { ++ uart->ps_bdf_enable = 1; ++ parse_pci_bdf(&conf, &uart->ps_bdf[0]); ++ } ++ ++ if ( *conf == ',' && *++conf != ',' ) ++ { ++ uart->pb_bdf_enable = 1; ++ parse_pci_bdf(&conf, &uart->pb_bdf[0]); + } + + config_parsed: diff --git a/25874-x86-EFI-chain-cfg.patch b/25874-x86-EFI-chain-cfg.patch new file mode 100644 index 0000000..7eb1dc8 --- /dev/null +++ b/25874-x86-EFI-chain-cfg.patch @@ -0,0 +1,70 @@ +# HG changeset patch +# User Jan Beulich +# Date 1347437974 -7200 +# Node ID 8c0aa97d529a55de2ab96be1a5a6e9ed6a9c6bf0 +# Parent ac8f4afccd6c6786a3fd5691e8b0c9b38c47e994 +x86-64/EFI: allow chaining of config files + +Namely when making use the CONFIG_XEN_COMPAT_* options in the legacy +Linux kernels, newer kernels may not be compatible with older +hypervisors, so trying to boot such a combination makes little sense. +Booting older kernels on newer hypervisors, however, has to always +work. + +With the way xen.efi looks for its configuration file, allowing +individual configuration files to refer only to compatible kernels, +and referring from an older- to a newer-hypervisor one (the kernels +of which will, as said, necessarily be compatible with the older +hypervisor) allows to greatly reduce redundancy at least in +development environments where one frequently wants multiple +hypervisors and kernles to be installed in parallel. + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/docs/misc/efi.markdown ++++ b/docs/misc/efi.markdown +@@ -75,6 +75,13 @@ Specifies an XSM module to load. + + Specifies a CPU microcode blob to load. + ++###`chain=` ++ ++Specifies an alternate configuration file to use in case the specified section ++(and in particular its `kernel=` setting) can't be found in the default (or ++specified) configuration file. This is only meaningful in the [global] section ++and really not meant to be used together with the `-cfg=` command line option. ++ + Filenames must be specified relative to the location of the EFI binary. + + Extra options to be passed to Xen can also be specified on the command line, +--- a/xen/arch/x86/efi/boot.c ++++ b/xen/arch/x86/efi/boot.c +@@ -797,7 +797,26 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY + else + section.s = get_value(&cfg, "global", "default"); + +- name.s = get_value(&cfg, section.s, "kernel"); ++ for ( ; ; ) ++ { ++ name.s = get_value(&cfg, section.s, "kernel"); ++ if ( name.s ) ++ break; ++ name.s = get_value(&cfg, "global", "chain"); ++ if ( !name.s ) ++ break; ++ efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); ++ cfg.addr = 0; ++ if ( !read_file(dir_handle, s2w(&name), &cfg) ) ++ { ++ PrintStr(L"Chained configuration file '"); ++ PrintStr(name.w); ++ efi_bs->FreePool(name.w); ++ blexit(L"'not found\r\n"); ++ } ++ pre_parse(&cfg); ++ efi_bs->FreePool(name.w); ++ } + if ( !name.s ) + blexit(L"No Dom0 kernel image specified\r\n"); + split_value(name.s); diff --git a/25909-xenpm-consistent.patch b/25909-xenpm-consistent.patch new file mode 100644 index 0000000..b096a5e --- /dev/null +++ b/25909-xenpm-consistent.patch @@ -0,0 +1,630 @@ +References: bnc#780401 + +# HG changeset patch +# User Jan Beulich +# Date 1347869399 -7200 +# Node ID 51408c3528030309e8f064bf6a3c96b37de7dc96 +# Parent 12fa949b90603f057d458e370284471412afb0ba +xenpm: make argument parsing and error handling more consistent + +Specifically, what values are or aren't accepted as CPU identifier, and +how the values get interpreted should be consistent across sub-commands +(intended behavior now: non-negative values are okay, and along with +omitting the argument, specifying "all" will also be accepted). + +For error handling, error messages should get consistently issued to +stderr, and the tool should now (hopefully) produce an exit code of +zero only in the (partial) success case (there may still be a small +number of questionable cases). + +Signed-off-by: Jan Beulich +Acked-by: Keir Fraser + +--- a/tools/misc/xenpm.c ++++ b/tools/misc/xenpm.c +@@ -36,7 +36,7 @@ + #define CPUFREQ_TURBO_ENABLED 1 + + static xc_interface *xc_handle; +-static int max_cpu_nr; ++static unsigned int max_cpu_nr; + + /* help message */ + void show_help(void) +@@ -77,6 +77,33 @@ void help_func(int argc, char *argv[]) + show_help(); + } + ++static void parse_cpuid(const char *arg, int *cpuid) ++{ ++ if ( sscanf(arg, "%d", cpuid) != 1 || *cpuid < 0 ) ++ { ++ if ( strcasecmp(arg, "all") ) ++ { ++ fprintf(stderr, "Invalid CPU identifier: '%s'\n", arg); ++ exit(EINVAL); ++ } ++ *cpuid = -1; ++ } ++} ++ ++static void parse_cpuid_and_int(int argc, char *argv[], ++ int *cpuid, int *val, const char *what) ++{ ++ if ( argc > 1 ) ++ parse_cpuid(argv[0], cpuid); ++ ++ if ( argc == 0 || sscanf(argv[argc > 1], "%d", val) != 1 ) ++ { ++ fprintf(stderr, argc ? "Invalid %s '%s'\n" : "Missing %s\n", ++ what, argv[argc > 1]); ++ exit(EINVAL); ++ } ++} ++ + static void print_cxstat(int cpuid, struct xc_cx_stat *cxstat) + { + int i; +@@ -166,7 +193,8 @@ static int show_cxstat_by_cpuid(xc_inter + if ( ret ) + { + if ( ret == -ENODEV ) +- printf("Either xen cpuidle is disabled or no valid information is registered!\n"); ++ fprintf(stderr, ++ "Either Xen cpuidle is disabled or no valid information is registered!\n"); + return ret; + } + +@@ -181,11 +209,8 @@ void cxstat_func(int argc, char *argv[]) + { + int cpuid = -1; + +- if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 ) +- cpuid = -1; +- +- if ( cpuid >= max_cpu_nr ) +- cpuid = -1; ++ if ( argc > 0 ) ++ parse_cpuid(argv[0], &cpuid); + + show_max_cstate(xc_handle); + +@@ -294,11 +319,8 @@ void pxstat_func(int argc, char *argv[]) + { + int cpuid = -1; + +- if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 ) +- cpuid = -1; +- +- if ( cpuid >= max_cpu_nr ) +- cpuid = -1; ++ if ( argc > 0 ) ++ parse_cpuid(argv[0], &cpuid); + + if ( cpuid < 0 ) + { +@@ -338,10 +360,10 @@ static void signal_int_handler(int signo + goto out; + } + +- if ( gettimeofday(&tv, NULL) == -1 ) ++ if ( gettimeofday(&tv, NULL) ) + { + fprintf(stderr, "failed to get timeofday\n"); +- goto out ; ++ goto out; + } + usec_end = tv.tv_sec * 1000000UL + tv.tv_usec; + +@@ -541,7 +563,7 @@ void start_gather_func(int argc, char *a + printf("Timeout set to %d seconds\n", timeout); + } + +- if ( gettimeofday(&tv, NULL) == -1 ) ++ if ( gettimeofday(&tv, NULL) ) + { + fprintf(stderr, "failed to get timeofday\n"); + return ; +@@ -766,11 +788,8 @@ void cpufreq_para_func(int argc, char *a + { + int cpuid = -1; + +- if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 ) +- cpuid = -1; +- +- if ( cpuid >= max_cpu_nr ) +- cpuid = -1; ++ if ( argc > 0 ) ++ parse_cpuid(argv[0], &cpuid); + + if ( cpuid < 0 ) + { +@@ -788,26 +807,22 @@ void scaling_max_freq_func(int argc, cha + { + int cpuid = -1, freq = -1; + +- if ( (argc >= 2 && (sscanf(argv[1], "%d", &freq) != 1 || +- sscanf(argv[0], "%d", &cpuid) != 1)) || +- (argc == 1 && sscanf(argv[0], "%d", &freq) != 1 ) || +- argc == 0 ) +- { +- fprintf(stderr, "failed to set scaling max freq\n"); +- return ; +- } ++ parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency"); + + if ( cpuid < 0 ) + { + int i; + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MAX_FREQ, freq) ) +- fprintf(stderr, "[CPU%d] failed to set scaling max freq\n", i); ++ fprintf(stderr, ++ "[CPU%d] failed to set scaling max freq (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MAX_FREQ, freq) ) +- fprintf(stderr, "failed to set scaling max freq\n"); ++ fprintf(stderr, "failed to set scaling max freq (%d - %s)\n", ++ errno, strerror(errno)); + } + } + +@@ -815,26 +830,22 @@ void scaling_min_freq_func(int argc, cha + { + int cpuid = -1, freq = -1; + +- if ( (argc >= 2 && (sscanf(argv[1], "%d", &freq) != 1 || +- sscanf(argv[0], "%d", &cpuid) != 1) ) || +- (argc == 1 && sscanf(argv[0], "%d", &freq) != 1 ) || +- argc == 0 ) +- { +- fprintf(stderr, "failed to set scaling min freq\n"); +- return ; +- } ++ parse_cpuid_and_int(argc, argv, &cpuid, &freq, "frequency"); + + if ( cpuid < 0 ) + { + int i; + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_para(xc_handle, i, SCALING_MIN_FREQ, freq) ) +- fprintf(stderr, "[CPU%d] failed to set scaling min freq\n", i); ++ fprintf(stderr, ++ "[CPU%d] failed to set scaling min freq (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_MIN_FREQ, freq) ) +- fprintf(stderr, "failed to set scaling min freq\n"); ++ fprintf(stderr, "failed to set scaling min freq (%d - %s)\n", ++ errno, strerror(errno)); + } + } + +@@ -842,26 +853,22 @@ void scaling_speed_func(int argc, char * + { + int cpuid = -1, speed = -1; + +- if ( (argc >= 2 && (sscanf(argv[1], "%d", &speed) != 1 || +- sscanf(argv[0], "%d", &cpuid) != 1) ) || +- (argc == 1 && sscanf(argv[0], "%d", &speed) != 1 ) || +- argc == 0 ) +- { +- fprintf(stderr, "failed to set scaling speed\n"); +- return ; +- } ++ parse_cpuid_and_int(argc, argv, &cpuid, &speed, "speed"); + + if ( cpuid < 0 ) + { + int i; + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_para(xc_handle, i, SCALING_SETSPEED, speed) ) +- fprintf(stderr, "[CPU%d] failed to set scaling speed\n", i); ++ fprintf(stderr, ++ "[CPU%d] failed to set scaling speed (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_para(xc_handle, cpuid, SCALING_SETSPEED, speed) ) +- fprintf(stderr, "failed to set scaling speed\n"); ++ fprintf(stderr, "failed to set scaling speed (%d - %s)\n", ++ errno, strerror(errno)); + } + } + +@@ -869,14 +876,7 @@ void scaling_sampling_rate_func(int argc + { + int cpuid = -1, rate = -1; + +- if ( (argc >= 2 && (sscanf(argv[1], "%d", &rate) != 1 || +- sscanf(argv[0], "%d", &cpuid) != 1) ) || +- (argc == 1 && sscanf(argv[0], "%d", &rate) != 1 ) || +- argc == 0 ) +- { +- fprintf(stderr, "failed to set scaling sampling rate\n"); +- return ; +- } ++ parse_cpuid_and_int(argc, argv, &cpuid, &rate, "rate"); + + if ( cpuid < 0 ) + { +@@ -884,12 +884,14 @@ void scaling_sampling_rate_func(int argc + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_para(xc_handle, i, SAMPLING_RATE, rate) ) + fprintf(stderr, +- "[CPU%d] failed to set scaling sampling rate\n", i); ++ "[CPU%d] failed to set scaling sampling rate (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_para(xc_handle, cpuid, SAMPLING_RATE, rate) ) +- fprintf(stderr, "failed to set scaling sampling rate\n"); ++ fprintf(stderr, "failed to set scaling sampling rate (%d - %s)\n", ++ errno, strerror(errno)); + } + } + +@@ -897,14 +899,7 @@ void scaling_up_threshold_func(int argc, + { + int cpuid = -1, threshold = -1; + +- if ( (argc >= 2 && (sscanf(argv[1], "%d", &threshold) != 1 || +- sscanf(argv[0], "%d", &cpuid) != 1) ) || +- (argc == 1 && sscanf(argv[0], "%d", &threshold) != 1 ) || +- argc == 0 ) +- { +- fprintf(stderr, "failed to set up scaling threshold\n"); +- return ; +- } ++ parse_cpuid_and_int(argc, argv, &cpuid, &threshold, "threshold"); + + if ( cpuid < 0 ) + { +@@ -912,57 +907,49 @@ void scaling_up_threshold_func(int argc, + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_para(xc_handle, i, UP_THRESHOLD, threshold) ) + fprintf(stderr, +- "[CPU%d] failed to set up scaling threshold\n", i); ++ "[CPU%d] failed to set up scaling threshold (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_para(xc_handle, cpuid, UP_THRESHOLD, threshold) ) +- fprintf(stderr, "failed to set up scaling threshold\n"); ++ fprintf(stderr, "failed to set up scaling threshold (%d - %s)\n", ++ errno, strerror(errno)); + } + } + + void scaling_governor_func(int argc, char *argv[]) + { + int cpuid = -1; +- char *name = NULL; ++ char *name; + + if ( argc >= 2 ) + { +- name = strdup(argv[1]); +- if ( name == NULL ) +- goto out; +- if ( sscanf(argv[0], "%d", &cpuid) != 1 ) +- { +- free(name); +- goto out; +- } ++ parse_cpuid(argv[0], &cpuid); ++ name = argv[1]; + } + else if ( argc > 0 ) ++ name = argv[0]; ++ else + { +- name = strdup(argv[0]); +- if ( name == NULL ) +- goto out; ++ fprintf(stderr, "Missing argument(s)\n"); ++ exit(EINVAL); + } +- else +- goto out; + + if ( cpuid < 0 ) + { + int i; + for ( i = 0; i < max_cpu_nr; i++ ) + if ( xc_set_cpufreq_gov(xc_handle, i, name) ) +- fprintf(stderr, "[CPU%d] failed to set governor name\n", i); ++ fprintf(stderr, "[CPU%d] failed to set governor name (%d - %s)\n", ++ i, errno, strerror(errno)); + } + else + { + if ( xc_set_cpufreq_gov(xc_handle, cpuid, name) ) +- fprintf(stderr, "failed to set governor name\n"); ++ fprintf(stderr, "failed to set governor name (%d - %s)\n", ++ errno, strerror(errno)); + } +- +- free(name); +- return ; +-out: +- fprintf(stderr, "failed to set governor name\n"); + } + + void cpu_topology_func(int argc, char *argv[]) +@@ -971,7 +958,7 @@ void cpu_topology_func(int argc, char *a + DECLARE_HYPERCALL_BUFFER(uint32_t, cpu_to_socket); + DECLARE_HYPERCALL_BUFFER(uint32_t, cpu_to_node); + xc_topologyinfo_t info = { 0 }; +- int i; ++ int i, rc = ENOMEM; + + cpu_to_core = xc_hypercall_buffer_alloc(xc_handle, cpu_to_core, sizeof(*cpu_to_core) * MAX_NR_CPU); + cpu_to_socket = xc_hypercall_buffer_alloc(xc_handle, cpu_to_socket, sizeof(*cpu_to_socket) * MAX_NR_CPU); +@@ -990,7 +977,9 @@ void cpu_topology_func(int argc, char *a + + if ( xc_topologyinfo(xc_handle, &info) ) + { +- printf("Can not get Xen CPU topology: %d\n", errno); ++ rc = errno; ++ fprintf(stderr, "Cannot get Xen CPU topology (%d - %s)\n", ++ errno, strerror(errno)); + goto out; + } + +@@ -1005,116 +994,95 @@ void cpu_topology_func(int argc, char *a + printf("CPU%d\t %d\t %d\t %d\n", + i, cpu_to_core[i], cpu_to_socket[i], cpu_to_node[i]); + } ++ rc = 0; + out: + xc_hypercall_buffer_free(xc_handle, cpu_to_core); + xc_hypercall_buffer_free(xc_handle, cpu_to_socket); + xc_hypercall_buffer_free(xc_handle, cpu_to_node); ++ if ( rc ) ++ exit(rc); + } + + void set_sched_smt_func(int argc, char *argv[]) + { +- int value, rc; ++ int value; + +- if (argc != 1){ +- show_help(); +- exit(-1); ++ if ( argc != 1 ) { ++ fprintf(stderr, "Missing or invalid argument(s)\n"); ++ exit(EINVAL); + } + +- if ( !strncmp(argv[0], "disable", sizeof("disable")) ) +- { ++ if ( !strcasecmp(argv[0], "disable") ) + value = 0; +- } +- else if ( !strncmp(argv[0], "enable", sizeof("enable")) ) +- { ++ else if ( !strcasecmp(argv[0], "enable") ) + value = 1; +- } + else + { +- show_help(); +- exit(-1); ++ fprintf(stderr, "Invalid argument: %s\n", argv[0]); ++ exit(EINVAL); + } + +- rc = xc_set_sched_opt_smt(xc_handle, value); +- printf("%s sched_smt_power_savings %s\n", argv[0], +- rc? "failed":"succeeded" ); +- +- return; ++ if ( !xc_set_sched_opt_smt(xc_handle, value) ) ++ printf("%s sched_smt_power_savings succeeded\n", argv[0]); ++ else ++ fprintf(stderr, "%s sched_smt_power_savings failed (%d - %s)\n", ++ argv[0], errno, strerror(errno)); + } + + void set_vcpu_migration_delay_func(int argc, char *argv[]) + { + int value; +- int rc; +- +- if (argc != 1){ +- show_help(); +- exit(-1); +- } +- +- value = atoi(argv[0]); + +- if (value < 0) +- { +- printf("Please try non-negative vcpu migration delay\n"); +- exit(-1); ++ if ( argc != 1 || (value = atoi(argv[0])) < 0 ) { ++ fprintf(stderr, "Missing or invalid argument(s)\n"); ++ exit(EINVAL); + } + +- rc = xc_set_vcpu_migration_delay(xc_handle, value); +- printf("%s to set vcpu migration delay to %d us\n", +- rc? "Fail":"Succeed", value ); +- +- return; ++ if ( !xc_set_vcpu_migration_delay(xc_handle, value) ) ++ printf("set vcpu migration delay to %d us succeeded\n", value); ++ else ++ fprintf(stderr, "set vcpu migration delay failed (%d - %s)\n", ++ errno, strerror(errno)); + } + + void get_vcpu_migration_delay_func(int argc, char *argv[]) + { + uint32_t value; +- int rc; + +- if (argc != 0){ +- show_help(); +- exit(-1); +- } ++ if ( argc ) ++ fprintf(stderr, "Ignoring argument(s)\n"); + +- rc = xc_get_vcpu_migration_delay(xc_handle, &value); +- if (!rc) +- { +- printf("Schduler vcpu migration delay is %d us\n", value); +- } ++ if ( !xc_get_vcpu_migration_delay(xc_handle, &value) ) ++ printf("Scheduler vcpu migration delay is %d us\n", value); + else +- { +- printf("Failed to get scheduler vcpu migration delay, errno=%d\n", errno); +- } +- +- return; ++ fprintf(stderr, ++ "Failed to get scheduler vcpu migration delay (%d - %s)\n", ++ errno, strerror(errno)); + } + + void set_max_cstate_func(int argc, char *argv[]) + { +- int value, rc; ++ int value; + + if ( argc != 1 || sscanf(argv[0], "%d", &value) != 1 || value < 0 ) + { +- show_help(); +- exit(-1); ++ fprintf(stderr, "Missing or invalid argument(s)\n"); ++ exit(EINVAL); + } + +- rc = xc_set_cpuidle_max_cstate(xc_handle, (uint32_t)value); +- printf("set max_cstate to C%d %s\n", value, +- rc? "failed":"succeeded" ); +- +- return; ++ if ( !xc_set_cpuidle_max_cstate(xc_handle, (uint32_t)value) ) ++ printf("set max_cstate to C%d succeeded\n", value); ++ else ++ fprintf(stderr, "set max_cstate to C%d failed (%d - %s)\n", ++ value, errno, strerror(errno)); + } + + void enable_turbo_mode(int argc, char *argv[]) + { + int cpuid = -1; + +- if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 ) +- cpuid = -1; +- +- if ( cpuid >= max_cpu_nr ) +- cpuid = -1; ++ if ( argc > 0 ) ++ parse_cpuid(argv[0], &cpuid); + + if ( cpuid < 0 ) + { +@@ -1122,21 +1090,22 @@ void enable_turbo_mode(int argc, char *a + * only make effects on dbs governor */ + int i; + for ( i = 0; i < max_cpu_nr; i++ ) +- xc_enable_turbo(xc_handle, i); ++ if ( xc_enable_turbo(xc_handle, i) ) ++ fprintf(stderr, ++ "[CPU%d] failed to enable turbo mode (%d - %s)\n", ++ i, errno, strerror(errno)); + } +- else +- xc_enable_turbo(xc_handle, cpuid); ++ else if ( xc_enable_turbo(xc_handle, cpuid) ) ++ fprintf(stderr, "failed to enable turbo mode (%d - %s)\n", ++ errno, strerror(errno)); + } + + void disable_turbo_mode(int argc, char *argv[]) + { + int cpuid = -1; + +- if ( argc > 0 && sscanf(argv[0], "%d", &cpuid) != 1 ) +- cpuid = -1; +- +- if ( cpuid >= max_cpu_nr ) +- cpuid = -1; ++ if ( argc > 0 ) ++ parse_cpuid(argv[0], &cpuid); + + if ( cpuid < 0 ) + { +@@ -1144,10 +1113,14 @@ void disable_turbo_mode(int argc, char * + * only make effects on dbs governor */ + int i; + for ( i = 0; i < max_cpu_nr; i++ ) +- xc_disable_turbo(xc_handle, i); ++ if ( xc_disable_turbo(xc_handle, i) ) ++ fprintf(stderr, ++ "[CPU%d] failed to disable turbo mode (%d - %s)\n", ++ i, errno, strerror(errno)); + } +- else +- xc_disable_turbo(xc_handle, cpuid); ++ else if ( xc_disable_turbo(xc_handle, cpuid) ) ++ fprintf(stderr, "failed to disable turbo mode (%d - %s)\n", ++ errno, strerror(errno)); + } + + struct { +@@ -1191,15 +1164,17 @@ int main(int argc, char *argv[]) + if ( !xc_handle ) + { + fprintf(stderr, "failed to get the handler\n"); +- return 0; ++ return EIO; + } + + ret = xc_physinfo(xc_handle, &physinfo); + if ( ret ) + { +- fprintf(stderr, "failed to get the processor information\n"); ++ ret = errno; ++ fprintf(stderr, "failed to get processor information (%d - %s)\n", ++ ret, strerror(ret)); + xc_interface_close(xc_handle); +- return 0; ++ return ret; + } + max_cpu_nr = physinfo.nr_cpus; + +@@ -1214,14 +1189,18 @@ int main(int argc, char *argv[]) + for ( i = 0; i < nr_matches; i++ ) + fprintf(stderr, " %s", main_options[matches_main_options[i]].name); + fprintf(stderr, "\n"); ++ ret = EINVAL; + } + else if ( nr_matches == 1 ) + /* dispatch to the corresponding function handler */ + main_options[matches_main_options[0]].function(argc - 2, argv + 2); + else ++ { + show_help(); ++ ret = EINVAL; ++ } + + xc_interface_close(xc_handle); +- return 0; ++ return ret; + } + diff --git a/blktap-pv-cdrom.patch b/blktap-pv-cdrom.patch index 9c2552f..1311a7a 100644 --- a/blktap-pv-cdrom.patch +++ b/blktap-pv-cdrom.patch @@ -677,7 +677,7 @@ Index: xen-4.2.0-testing/tools/blktap/drivers/Makefile -LDLIBS_img := $(AIOLIBS) $(CRYPT_LIB) $(PTHREAD_LIBS) -lz +LDLIBS_xen := $(LDLIBS_libxenctrl) $(LDLIBS_libxenstore) +LDLIBS_blktapctrl := $(MEMSHRLIBS) $(LDLIBS_xen) -L../lib -lblktap -lrt -lm $(PTHREAD_LIBS) -+LDLIBS_img := $(LIBAIO_DIR)/libaio.a $(CRYPT_LIB) $(PTHREAD_LIBS) -lz $(LDLIBS_xen) ++LDLIBS_img := $(AIOLIBS) $(CRYPT_LIB) $(PTHREAD_LIBS) -lz $(LDLIBS_xen) BLK-OBJS-y := block-aio.o BLK-OBJS-y += block-sync.o diff --git a/cve-2012-0029-qemu-xen-unstable.patch b/cve-2012-0029-qemu-xen-unstable.patch deleted file mode 100644 index 5914c20..0000000 --- a/cve-2012-0029-qemu-xen-unstable.patch +++ /dev/null @@ -1,21 +0,0 @@ -Index: xen-4.1.2-testing/tools/qemu-xen-traditional-dir-remote/hw/e1000.c -=================================================================== ---- xen-4.1.2-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/e1000.c -+++ xen-4.1.2-testing/tools/qemu-xen-traditional-dir-remote/hw/e1000.c -@@ -444,6 +444,8 @@ process_tx_desc(E1000State *s, struct e1 - bytes = split_size; - if (tp->size + bytes > msh) - bytes = msh - tp->size; -+ -+ bytes = MIN(sizeof(tp->data) - tp->size, bytes); - cpu_physical_memory_read(addr, tp->data + tp->size, bytes); - if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) - memmove(tp->header, tp->data, hdr); -@@ -459,6 +461,7 @@ process_tx_desc(E1000State *s, struct e1 - // context descriptor TSE is not set, while data descriptor TSE is set - DBGOUT(TXERR, "TCP segmentaion Error\n"); - } else { -+ split_size = MIN(sizeof(tp->data) - tp->size, split_size); - cpu_physical_memory_read(addr, tp->data + tp->size, split_size); - tp->size += split_size; - } diff --git a/ipxe-gcc45-warnings.patch b/ipxe-gcc45-warnings.patch deleted file mode 100644 index eff4232..0000000 --- a/ipxe-gcc45-warnings.patch +++ /dev/null @@ -1,73 +0,0 @@ -Index: xen-4.2.0-testing/tools/firmware/etherboot/patches/ipxe-git-f7c5918b179b -=================================================================== ---- /dev/null -+++ xen-4.2.0-testing/tools/firmware/etherboot/patches/ipxe-git-f7c5918b179b -@@ -0,0 +1,61 @@ -+ -+Subject: [drivers] Fix warnings identified by gcc 4.5 -+From: Bruce Rogers brogers@novell.com Fri Apr 2 18:16:38 2010 -0600 -+Date: Fri Apr 16 07:32:49 2010 -0400: -+Git: f7c5918b179be57fc7f352cb33664eb43de02c30 -+ -+In building gpxe for openSUSE Factory (part of kvm package), there were -+a few problems identified by the compiler. This patch addresses them. -+ -+Signed-off-by: Bruce Rogers -+Signed-off-by: Stefan Hajnoczi -+Signed-off-by: Marty Connor -+ -+diff --git a/src/drivers/net/ath5k/ath5k_qcu.c b/src/drivers/net/ath5k/ath5k_qcu.c -+index a674b85..cb25029 100644 -+--- a/src/drivers/net/ath5k/ath5k_qcu.c -++++ b/src/drivers/net/ath5k/ath5k_qcu.c -+@@ -268,7 +268,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah) -+ } -+ -+ if (tq->tqi_ready_time && -+- (tq->tqi_type != AR5K_TX_QUEUE_ID_CAB)) -++ (tq->tqi_type != AR5K_TX_QUEUE_CAB)) -+ ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, -+ AR5K_QCU_RDYTIMECFG_INTVAL) | -+ AR5K_QCU_RDYTIMECFG_ENABLE, -+diff --git a/src/drivers/net/ns83820.c b/src/drivers/net/ns83820.c -+index 44d875f..c5f2153 100644 -+--- a/src/drivers/net/ns83820.c -++++ b/src/drivers/net/ns83820.c -+@@ -687,7 +687,7 @@ static int ns83820_poll(struct nic *nic, int retrieve) -+ // rx_ring[entry].link = 0; -+ rx_ring[entry].cmdsts = cpu_to_le32(CMDSTS_OWN); -+ -+- ns->cur_rx = ++ns->cur_rx % NR_RX_DESC; -++ ns->cur_rx = (ns->cur_rx + 1) % NR_RX_DESC; -+ -+ if (ns->cur_rx == 0) /* We have wrapped the ring */ -+ kick_rx(); -+diff --git a/src/drivers/net/tulip.c b/src/drivers/net/tulip.c -+index e08e0d8..af30ec6 100644 -+--- a/src/drivers/net/tulip.c -++++ b/src/drivers/net/tulip.c -+@@ -1171,7 +1171,7 @@ static int tulip_poll(struct nic *nic, int retrieve) -+ if (rx_ring[tp->cur_rx].status & 0x00008000) { -+ /* return the descriptor and buffer to receive ring */ -+ rx_ring[tp->cur_rx].status = 0x80000000; -+- tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; -++ tp->cur_rx = (tp->cur_rx + 1) % RX_RING_SIZE; -+ return 0; -+ } -+ -+@@ -1180,7 +1180,7 @@ static int tulip_poll(struct nic *nic, int retrieve) -+ -+ /* return the descriptor and buffer to receive ring */ -+ rx_ring[tp->cur_rx].status = 0x80000000; -+- tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; -++ tp->cur_rx = (tp->cur_rx + 1) % RX_RING_SIZE; -+ -+ return 1; -+ } -Index: xen-4.2.0-testing/tools/firmware/etherboot/patches/series -=================================================================== ---- xen-4.2.0-testing.orig/tools/firmware/etherboot/patches/series -+++ xen-4.2.0-testing/tools/firmware/etherboot/patches/series -@@ -1 +1,2 @@ - boot_prompt_option.patch -+ipxe-git-f7c5918b179b diff --git a/ipxe-ipv4-fragment.patch b/ipxe-ipv4-fragment.patch deleted file mode 100644 index 5816ddd..0000000 --- a/ipxe-ipv4-fragment.patch +++ /dev/null @@ -1,366 +0,0 @@ -Index: xen-4.2.0-testing/tools/firmware/etherboot/patches/ipxe-git-13186b64b6c3 -=================================================================== ---- /dev/null -+++ xen-4.2.0-testing/tools/firmware/etherboot/patches/ipxe-git-13186b64b6c3 -@@ -0,0 +1,354 @@ -+commit 13186b64b6c3d5cbe9ed13bda1532e79b1afe81d -+Author: Michael Brown -+Date: Sat Jul 16 01:15:53 2011 +0100 -+ -+ [ipv4] Fix fragment reassembly -+ -+ Signed-off-by: Michael Brown -+ Signed-off-by: Michal Kubecek -+ -+diff -up a/src/include/gpxe/ip.h.orig-frag b/src/include/gpxe/ip.h -+--- a/src/include/gpxe/ip.h.orig-frag 2010-02-02 17:12:44.000000000 +0100 -++++ b/src/include/gpxe/ip.h 2011-11-18 15:49:17.202660163 +0100 -+@@ -32,9 +32,6 @@ struct net_protocol; -+ #define IP_TOS 0 -+ #define IP_TTL 64 -+ -+-#define IP_FRAG_IOB_SIZE 1500 -+-#define IP_FRAG_TIMEOUT 50 -+- -+ /** An IPv4 packet header */ -+ struct iphdr { -+ uint8_t verhdrlen; -+@@ -74,20 +71,16 @@ struct ipv4_miniroute { -+ struct in_addr gateway; -+ }; -+ -+-/* Fragment reassembly buffer */ -+-struct frag_buffer { -+- /* Identification number */ -+- uint16_t ident; -+- /* Source network address */ -+- struct in_addr src; -+- /* Destination network address */ -+- struct in_addr dest; -+- /* Reassembled I/O buffer */ -+- struct io_buffer *frag_iob; -+- /* Reassembly timer */ -+- struct retry_timer frag_timer; -++/* IPv4 fragment reassembly buffer */ -++struct ipv4_fragment { -+ /* List of fragment reassembly buffers */ -+ struct list_head list; -++ /** Reassembled packet */ -++ struct io_buffer *iobuf; -++ /** Current offset */ -++ size_t offset; -++ /** Reassembly timer */ -++ struct retry_timer timer; -+ }; -+ -+ extern struct list_head ipv4_miniroutes; -+diff -up a/src/include/gpxe/retry.h.orig-frag b/src/include/gpxe/retry.h -+--- a/src/include/gpxe/retry.h.orig-frag 2010-02-02 17:12:44.000000000 +0100 -++++ b/src/include/gpxe/retry.h 2011-11-18 15:59:25.258837891 +0100 -+@@ -51,6 +51,19 @@ struct retry_timer { -+ void ( * expired ) ( struct retry_timer *timer, int over ); -+ }; -+ -++/** -++ * Initialise a timer -++ * -++ * @v timer Retry timer -++ * @v expired Timer expired callback -++ */ -++static inline __attribute__ (( always_inline )) void -++timer_init ( struct retry_timer *timer, -++ void ( * expired ) ( struct retry_timer *timer, int over ) ) -++{ -++ timer->expired = expired; -++} -++ -+ extern void start_timer ( struct retry_timer *timer ); -+ extern void start_timer_fixed ( struct retry_timer *timer, -+ unsigned long timeout ); -+diff -up a/src/net/ipv4.c.orig-frag b/src/net/ipv4.c -+--- a/src/net/ipv4.c.orig-frag 2010-02-02 17:12:44.000000000 +0100 -++++ b/src/net/ipv4.c 2011-11-18 15:49:17.203660142 +0100 -+@@ -14,6 +14,7 @@ -+ #include -+ #include -+ #include -++#include -+ -+ /** @file -+ * -+@@ -32,7 +33,10 @@ struct net_protocol ipv4_protocol; -+ struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes ); -+ -+ /** List of fragment reassembly buffers */ -+-static LIST_HEAD ( frag_buffers ); -++static LIST_HEAD ( ipv4_fragments ); -++ -++/** Fragment reassembly timeout */ -++#define IP_FRAG_TIMEOUT ( TICKS_PER_SEC / 2 ) -+ -+ /** -+ * Add IPv4 minirouting table entry -+@@ -134,104 +138,126 @@ static struct ipv4_miniroute * ipv4_rout -+ } -+ -+ /** -+- * Fragment reassembly counter timeout -++ * Expire fragment reassembly buffer -+ * -+- * @v timer Retry timer -+- * @v over If asserted, the timer is greater than @c MAX_TIMEOUT -++ * @v timer Retry timer -++ * @v fail Failure indicator -+ */ -+-static void ipv4_frag_expired ( struct retry_timer *timer __unused, -+- int over ) { -+- if ( over ) { -+- DBG ( "Fragment reassembly timeout" ); -+- /* Free the fragment buffer */ -+- } -++static void ipv4_fragment_expired ( struct retry_timer *timer, -++ int fail __unused ) { -++ struct ipv4_fragment *frag = -++ container_of ( timer, struct ipv4_fragment, timer ); -++ struct iphdr *iphdr = frag->iobuf->data; -++ -++ DBG ( "IPv4 fragment %04x expired\n", ntohs ( iphdr->ident ) ); -++ free_iob ( frag->iobuf ); -++ list_del ( &frag->list ); -++ free ( frag ); -+ } -+ -+ /** -+- * Free fragment buffer -++ * Find matching fragment reassembly buffer -+ * -+- * @v fragbug Fragment buffer -++ * @v iphdr IPv4 header -++ * @ret frag Fragment reassembly buffer, or NULL -+ */ -+-static void free_fragbuf ( struct frag_buffer *fragbuf ) { -+- free ( fragbuf ); -++static struct ipv4_fragment * ipv4_fragment ( struct iphdr *iphdr ) { -++ struct ipv4_fragment *frag; -++ struct iphdr *frag_iphdr; -++ -++ list_for_each_entry ( frag, &ipv4_fragments, list ) { -++ frag_iphdr = frag->iobuf->data; -++ -++ if ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) && -++ ( iphdr->ident == frag_iphdr->ident ) ) { -++ return frag; -++ } -++ } -++ -++ return NULL; -+ } -+ -+ /** -+ * Fragment reassembler -+ * -+- * @v iobuf I/O buffer, fragment of the datagram -+- * @ret frag_iob Reassembled packet, or NULL -++ * @v iobuf I/O buffer -++ * @ret iobuf Reassembled packet, or NULL -+ */ -+-static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) { -++static struct io_buffer * ipv4_reassemble ( struct io_buffer *iobuf ) { -+ struct iphdr *iphdr = iobuf->data; -+- struct frag_buffer *fragbuf; -+- -+- /** -+- * Check if the fragment belongs to any fragment series -+- */ -+- list_for_each_entry ( fragbuf, &frag_buffers, list ) { -+- if ( fragbuf->ident == iphdr->ident && -+- fragbuf->src.s_addr == iphdr->src.s_addr ) { -+- /** -+- * Check if the packet is the expected fragment -+- * -+- * The offset of the new packet must be equal to the -+- * length of the data accumulated so far (the length of -+- * the reassembled I/O buffer -+- */ -+- if ( iob_len ( fragbuf->frag_iob ) == -+- ( iphdr->frags & IP_MASK_OFFSET ) ) { -+- /** -+- * Append the contents of the fragment to the -+- * reassembled I/O buffer -+- */ -+- iob_pull ( iobuf, sizeof ( *iphdr ) ); -+- memcpy ( iob_put ( fragbuf->frag_iob, -+- iob_len ( iobuf ) ), -+- iobuf->data, iob_len ( iobuf ) ); -+- free_iob ( iobuf ); -+- -+- /** Check if the fragment series is over */ -+- if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) { -+- iobuf = fragbuf->frag_iob; -+- free_fragbuf ( fragbuf ); -+- return iobuf; -+- } -+- -+- } else { -+- /* Discard the fragment series */ -+- free_fragbuf ( fragbuf ); -+- free_iob ( iobuf ); -+- } -+- return NULL; -++ size_t offset = ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 ); -++ unsigned int more_frags = ( iphdr->frags & htons ( IP_MASK_MOREFRAGS )); -++ size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); -++ struct ipv4_fragment *frag; -++ size_t expected_offset; -++ struct io_buffer *new_iobuf; -++ -++ /* Find matching fragment reassembly buffer, if any */ -++ frag = ipv4_fragment ( iphdr ); -++ -++ /* Drop out-of-order fragments */ -++ expected_offset = ( frag ? frag->offset : 0 ); -++ if ( offset != expected_offset ) { -++ DBG ( "IPv4 dropping out-of-sequence fragment %04x (%zd+%zd, " -++ "expected %zd)\n", ntohs ( iphdr->ident ), offset, -++ ( iob_len ( iobuf ) - hdrlen ), expected_offset ); -++ goto drop; -++ } -++ -++ /* Create or extend fragment reassembly buffer as applicable */ -++ if ( frag == NULL ) { -++ -++ /* Create new fragment reassembly buffer */ -++ frag = zalloc ( sizeof ( *frag ) ); -++ if ( ! frag ) -++ goto drop; -++ list_add ( &frag->list, &ipv4_fragments ); -++ frag->iobuf = iobuf; -++ frag->offset = ( iob_len ( iobuf ) - hdrlen ); -++ timer_init ( &frag->timer, ipv4_fragment_expired ); -++ -++ } else { -++ -++ /* Extend reassembly buffer */ -++ iob_pull ( iobuf, hdrlen ); -++ new_iobuf = alloc_iob ( iob_len ( frag->iobuf ) + -++ iob_len ( iobuf ) ); -++ if ( ! new_iobuf ) { -++ DBG ( "IPv4 could not extend reassembly buffer to " -++ "%zd bytes\n", -++ ( iob_len ( frag->iobuf ) + iob_len ( iobuf ) ) ); -++ goto drop; -+ } -+- } -+- -+- /** Check if the fragment is the first in the fragment series */ -+- if ( iphdr->frags & IP_MASK_MOREFRAGS && -+- ( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) { -+- -+- /** Create a new fragment buffer */ -+- fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) ); -+- fragbuf->ident = iphdr->ident; -+- fragbuf->src = iphdr->src; -+- -+- /* Set up the reassembly I/O buffer */ -+- fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE ); -+- iob_pull ( iobuf, sizeof ( *iphdr ) ); -+- memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ), -++ memcpy ( iob_put ( new_iobuf, iob_len ( frag->iobuf ) ), -++ frag->iobuf->data, iob_len ( frag->iobuf ) ); -++ memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ), -+ iobuf->data, iob_len ( iobuf ) ); -++ free_iob ( frag->iobuf ); -++ frag->iobuf = new_iobuf; -++ frag->offset += iob_len ( iobuf ); -+ free_iob ( iobuf ); -++ iphdr = frag->iobuf->data; -++ iphdr->len = ntohs ( iob_len ( frag->iobuf ) ); -+ -+- /* Set the reassembly timer */ -+- fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT; -+- fragbuf->frag_timer.expired = ipv4_frag_expired; -+- start_timer ( &fragbuf->frag_timer ); -++ /* Stop fragment reassembly timer */ -++ stop_timer ( &frag->timer ); -+ -+- /* Add the fragment buffer to the list of fragment buffers */ -+- list_add ( &fragbuf->list, &frag_buffers ); -++ /* If this is the final fragment, return it */ -++ if ( ! more_frags ) { -++ iobuf = frag->iobuf; -++ list_del ( &frag->list ); -++ free ( frag ); -++ return iobuf; -++ } -+ } -+- -++ -++ /* (Re)start fragment reassembly timer */ -++ start_timer_fixed ( &frag->timer, IP_FRAG_TIMEOUT ); -++ -++ return NULL; -++ -++ drop: -++ free_iob ( iobuf ); -+ return NULL; -+ } -+ -+@@ -432,37 +458,38 @@ static int ipv4_rx ( struct io_buffer *i -+ goto err; -+ } -+ -++ /* Truncate packet to correct length */ -++ iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) ); -++ -+ /* Print IPv4 header for debugging */ -+ DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) ); -+ DBG ( "%s len %d proto %d id %04x csum %04x\n", -+ inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol, -+ ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) ); -+ -+- /* Truncate packet to correct length, calculate pseudo-header -+- * checksum and then strip off the IPv4 header. -+- */ -+- iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) ); -+- pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM ); -+- iob_pull ( iobuf, hdrlen ); -+- -+- /* Fragment reassembly */ -+- if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || -+- ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) { -+- /* Pass the fragment to ipv4_reassemble() which either -+- * returns a fully reassembled I/O buffer or NULL. -++ /* Perform fragment reassembly if applicable */ -++ if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) { -++ /* Pass the fragment to ipv4_reassemble() which returns -++ * either a fully reassembled I/O buffer or NULL. -+ */ -+ iobuf = ipv4_reassemble ( iobuf ); -+ if ( ! iobuf ) -+ return 0; -++ iphdr = iobuf->data; -++ hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 ); -+ } -+ -+- /* Construct socket addresses and hand off to transport layer */ -++ /* Construct socket addresses, calculate pseudo-header -++ * checksum, and hand off to transport layer -++ */ -+ memset ( &src, 0, sizeof ( src ) ); -+ src.sin.sin_family = AF_INET; -+ src.sin.sin_addr = iphdr->src; -+ memset ( &dest, 0, sizeof ( dest ) ); -+ dest.sin.sin_family = AF_INET; -+ dest.sin.sin_addr = iphdr->dest; -++ pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM ); -++ iob_pull ( iobuf, hdrlen ); -+ if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st, -+ &dest.st, pshdr_csum ) ) != 0 ) { -+ DBG ( "IPv4 received packet rejected by stack: %s\n", -Index: xen-4.2.0-testing/tools/firmware/etherboot/patches/series -=================================================================== ---- xen-4.2.0-testing.orig/tools/firmware/etherboot/patches/series -+++ xen-4.2.0-testing/tools/firmware/etherboot/patches/series -@@ -1 +1,2 @@ - boot_prompt_option.patch -+ipxe-git-13186b64b6c3 diff --git a/x86-cpufreq-report.patch b/x86-cpufreq-report.patch index f153d59..391e8ee 100644 --- a/x86-cpufreq-report.patch +++ b/x86-cpufreq-report.patch @@ -1,7 +1,5 @@ -Index: xen-4.2.0-testing/xen/arch/x86/platform_hypercall.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/platform_hypercall.c -+++ xen-4.2.0-testing/xen/arch/x86/platform_hypercall.c +--- a/xen/arch/x86/platform_hypercall.c ++++ b/xen/arch/x86/platform_hypercall.c @@ -25,7 +25,7 @@ #include #include @@ -53,10 +51,8 @@ Index: xen-4.2.0-testing/xen/arch/x86/platform_hypercall.c default: ret = -ENOSYS; break; -Index: xen-4.2.0-testing/xen/include/public/platform.h -=================================================================== ---- xen-4.2.0-testing.orig/xen/include/public/platform.h -+++ xen-4.2.0-testing/xen/include/public/platform.h +--- a/xen/include/public/platform.h ++++ b/xen/include/public/platform.h @@ -504,6 +504,16 @@ struct xenpf_core_parking { typedef struct xenpf_core_parking xenpf_core_parking_t; DEFINE_XEN_GUEST_HANDLE(xenpf_core_parking_t); diff --git a/dom-print.patch b/x86-dom-print.patch similarity index 84% rename from dom-print.patch rename to x86-dom-print.patch index 5795764..d25fbb0 100644 --- a/dom-print.patch +++ b/x86-dom-print.patch @@ -1,7 +1,5 @@ -Index: xen-4.2.0-testing/xen/arch/x86/domain.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/domain.c -+++ xen-4.2.0-testing/xen/arch/x86/domain.c +--- a/xen/arch/x86/domain.c ++++ b/xen/arch/x86/domain.c @@ -148,15 +148,30 @@ void dump_pageframe_info(struct domain * printk("Memory pages belonging to domain %u:\n", d->domain_id); diff --git a/x86-extra-trap-info.patch b/x86-extra-trap-info.patch index 86f0636..bc2487d 100644 --- a/x86-extra-trap-info.patch +++ b/x86-extra-trap-info.patch @@ -1,71 +1,5 @@ -Index: xen-4.2.0-testing/xen/arch/x86/x86_32/entry.S -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/x86_32/entry.S -+++ xen-4.2.0-testing/xen/arch/x86/x86_32/entry.S -@@ -389,29 +389,41 @@ UNLIKELY_END(bounce_vm86_3) - movl %eax,UREGS_eip+4(%esp) - ret - _ASM_EXTABLE(.Lft6, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft7, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft8, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft9, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft10, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft11, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft12, domain_crash_synchronous) -+ _ASM_EXTABLE(.Lft7, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft8, domain_crash_page_fault_4) -+ _ASM_EXTABLE(.Lft9, domain_crash_page_fault_8) -+ _ASM_EXTABLE(.Lft10, domain_crash_page_fault_12) -+ _ASM_EXTABLE(.Lft11, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft12, domain_crash_page_fault_4) - _ASM_EXTABLE(.Lft13, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft14, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft15, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft16, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft17, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft18, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft19, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft20, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft21, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft22, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft23, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft24, domain_crash_synchronous) -- _ASM_EXTABLE(.Lft25, domain_crash_synchronous) -+ _ASM_EXTABLE(.Lft14, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft15, domain_crash_page_fault_4) -+ _ASM_EXTABLE(.Lft16, domain_crash_page_fault_8) -+ _ASM_EXTABLE(.Lft17, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft18, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft19, domain_crash_page_fault_4) -+ _ASM_EXTABLE(.Lft20, domain_crash_page_fault_8) -+ _ASM_EXTABLE(.Lft21, domain_crash_page_fault_12) -+ _ASM_EXTABLE(.Lft22, domain_crash_page_fault) -+ _ASM_EXTABLE(.Lft23, domain_crash_page_fault_4) -+ _ASM_EXTABLE(.Lft24, domain_crash_page_fault_8) -+ _ASM_EXTABLE(.Lft25, domain_crash_page_fault_12) - -+.section .rodata,"a" - domain_crash_synchronous_string: - .asciz "domain_crash_sync called from entry.S (%lx)\n" -+.previous - -+domain_crash_page_fault_12: -+ addl $4,%esi -+domain_crash_page_fault_8: -+ addl $4,%esi -+domain_crash_page_fault_4: -+ addl $4,%esi -+domain_crash_page_fault: -+ pushl %esi -+ call show_page_walk -+ addl $4,%esp - domain_crash_synchronous: - pushl $domain_crash_synchronous_string - call printk -Index: xen-4.2.0-testing/xen/arch/x86/x86_64/entry.S -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/x86_64/entry.S -+++ xen-4.2.0-testing/xen/arch/x86/x86_64/entry.S +--- a/xen/arch/x86/x86_64/entry.S ++++ b/xen/arch/x86/x86_64/entry.S @@ -427,22 +427,35 @@ UNLIKELY_END(bounce_failsafe) jz domain_crash_synchronous movq %rax,UREGS_rip+8(%rsp) @@ -95,7 +29,7 @@ Index: xen-4.2.0-testing/xen/arch/x86/x86_64/entry.S + _ASM_EXTABLE(.Lft12, domain_crash_page_fault_8) + _ASM_EXTABLE(.Lft13, domain_crash_page_fault) -+.section .rodata,"a" ++.section .rodata, "a", @progbits domain_crash_synchronous_string: .asciz "domain_crash_sync called from entry.S\n" +.previous diff --git a/x86-ioapic-ack-default.patch b/x86-ioapic-ack-default.patch index 7a0f435..464ac87 100644 --- a/x86-ioapic-ack-default.patch +++ b/x86-ioapic-ack-default.patch @@ -1,24 +1,16 @@ Change default IO-APIC ack mode for single IO-APIC systems to old-style. -Index: xen-4.2.0-testing/xen/arch/x86/io_apic.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/io_apic.c -+++ xen-4.2.0-testing/xen/arch/x86/io_apic.c -@@ -43,7 +43,7 @@ static struct { int pin, apic; } ioapic_ - static DEFINE_SPINLOCK(ioapic_lock); - - bool_t __read_mostly skip_ioapic_setup; --bool_t __read_mostly ioapic_ack_new = 1; -+bool_t __read_mostly ioapic_ack_new = -1; - bool_t __read_mostly ioapic_ack_forced = 0; - - #ifndef sis_apic_bug -@@ -2012,6 +2012,8 @@ void __init setup_IO_APIC(void) - else +--- a/xen/arch/x86/io_apic.c ++++ b/xen/arch/x86/io_apic.c +@@ -2013,7 +2013,10 @@ void __init setup_IO_APIC(void) io_apic_irqs = ~PIC_IRQS; -+ if (ioapic_ack_new < 0) -+ ioapic_ack_new = (nr_ioapics > 1); printk("ENABLING IO-APIC IRQs\n"); - printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old"); +- printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old"); ++ if (!directed_eoi_enabled && !ioapic_ack_forced) { ++ ioapic_ack_new = (nr_ioapics > 1); ++ printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old"); ++ } + /* + * Set up IO-APIC IRQ routing. diff --git a/xen-warnings-unused.diff b/xen-warnings-unused.diff index d274cd6..6b2dd51 100644 --- a/xen-warnings-unused.diff +++ b/xen-warnings-unused.diff @@ -1,7 +1,5 @@ -Index: xen-4.2.0-testing/tools/misc/gtraceview.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/misc/gtraceview.c -+++ xen-4.2.0-testing/tools/misc/gtraceview.c +--- a/tools/misc/gtraceview.c ++++ b/tools/misc/gtraceview.c @@ -621,7 +621,8 @@ void crt_init(void) void nr_addch(int nr, int ch) { @@ -12,10 +10,8 @@ Index: xen-4.2.0-testing/tools/misc/gtraceview.c getyx(stdscr, y, x); for (i = 0; i < nr; i++) { if (x == COLS-1) -Index: xen-4.2.0-testing/tools/xcutils/xc_restore.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/xcutils/xc_restore.c -+++ xen-4.2.0-testing/tools/xcutils/xc_restore.c +--- a/tools/xcutils/xc_restore.c ++++ b/tools/xcutils/xc_restore.c @@ -19,7 +19,8 @@ int main(int argc, char **argv) { @@ -26,10 +22,8 @@ Index: xen-4.2.0-testing/tools/xcutils/xc_restore.c xc_interface *xch; int io_fd, ret; int superpages; -Index: xen-4.2.0-testing/tools/firmware/rombios/32bit/tcgbios/tcgbios.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/firmware/rombios/32bit/tcgbios/tcgbios.c -+++ xen-4.2.0-testing/tools/firmware/rombios/32bit/tcgbios/tcgbios.c +--- a/tools/firmware/rombios/32bit/tcgbios/tcgbios.c ++++ b/tools/firmware/rombios/32bit/tcgbios/tcgbios.c @@ -1064,7 +1064,7 @@ uint32_t HashLogEvent32(struct hlei *hle uint32_t rc = 0; uint16_t size; @@ -39,10 +33,8 @@ Index: xen-4.2.0-testing/tools/firmware/rombios/32bit/tcgbios/tcgbios.c uint32_t hashdataptr; uint32_t hashdatalen; -Index: xen-4.2.0-testing/tools/console/client/main.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/console/client/main.c -+++ xen-4.2.0-testing/tools/console/client/main.c +--- a/tools/console/client/main.c ++++ b/tools/console/client/main.c @@ -277,7 +277,8 @@ int main(int argc, char **argv) }; @@ -53,10 +45,8 @@ Index: xen-4.2.0-testing/tools/console/client/main.c struct xs_handle *xs; char *end; console_type type = CONSOLE_INVAL; -Index: xen-4.2.0-testing/tools/xenstat/xentop/xentop.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/xenstat/xentop/xentop.c -+++ xen-4.2.0-testing/tools/xenstat/xentop/xentop.c +--- a/tools/xenstat/xentop/xentop.c ++++ b/tools/xenstat/xentop/xentop.c @@ -278,7 +278,8 @@ static void fail(const char *str) /* Return the row containing the cursor. */ static int current_row(void) @@ -77,11 +67,9 @@ Index: xen-4.2.0-testing/tools/xenstat/xentop/xentop.c getmaxyx(stdscr, y, x); return y; } -Index: xen-4.2.0-testing/tools/libxl/libxlu_cfg.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/libxl/libxlu_cfg.c -+++ xen-4.2.0-testing/tools/libxl/libxlu_cfg.c -@@ -406,7 +406,7 @@ char *xlu__cfgl_dequote(CfgParseContext +--- a/tools/libxl/libxlu_cfg.c ++++ b/tools/libxl/libxlu_cfg.c +@@ -406,7 +406,7 @@ char *xlu__cfgl_dequote(CfgParseContext #define NUMERIC_CHAR(minlen,maxlen,base,basetext) do{ \ char numbuf[(maxlen)+1], *ep; \ @@ -90,11 +78,9 @@ Index: xen-4.2.0-testing/tools/libxl/libxlu_cfg.c \ strncpy(numbuf,p,(maxlen)); \ numbuf[(maxlen)]= 0; \ -Index: xen-4.2.0-testing/tools/libxl/libxl_pci.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/libxl/libxl_pci.c -+++ xen-4.2.0-testing/tools/libxl/libxl_pci.c -@@ -71,7 +71,7 @@ int libxl__create_pci_backend(libxl__gc +--- a/tools/libxl/libxl_pci.c ++++ b/tools/libxl/libxl_pci.c +@@ -71,7 +71,7 @@ int libxl__create_pci_backend(libxl__gc flexarray_t *front = NULL; flexarray_t *back = NULL; libxl__device device; @@ -103,7 +89,7 @@ Index: xen-4.2.0-testing/tools/libxl/libxl_pci.c front = flexarray_make(16, 1); if (!front) -@@ -80,8 +80,6 @@ int libxl__create_pci_backend(libxl__gc +@@ -80,8 +80,6 @@ int libxl__create_pci_backend(libxl__gc if (!back) goto out; @@ -112,10 +98,8 @@ Index: xen-4.2.0-testing/tools/libxl/libxl_pci.c LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Creating pci backend"); /* add pci device */ -Index: xen-4.2.0-testing/tools/libxl/libxl_dom.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/libxl/libxl_dom.c -+++ xen-4.2.0-testing/tools/libxl/libxl_dom.c +--- a/tools/libxl/libxl_dom.c ++++ b/tools/libxl/libxl_dom.c @@ -565,7 +565,6 @@ int libxl__build_hvm(libxl__gc *gc, uint LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm build set params failed"); goto out; @@ -124,10 +108,8 @@ Index: xen-4.2.0-testing/tools/libxl/libxl_dom.c out: return rc; } -Index: xen-4.2.0-testing/tools/debugger/gdbsx/gx/gx_comm.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/debugger/gdbsx/gx/gx_comm.c -+++ xen-4.2.0-testing/tools/debugger/gdbsx/gx/gx_comm.c +--- a/tools/debugger/gdbsx/gx/gx_comm.c ++++ b/tools/debugger/gdbsx/gx/gx_comm.c @@ -163,7 +163,7 @@ readchar(void) static char buf[BUFSIZ]; static int bufcnt = 0; @@ -137,10 +119,8 @@ Index: xen-4.2.0-testing/tools/debugger/gdbsx/gx/gx_comm.c if (bufcnt-- > 0) return *bufp++ & 0x7f; -Index: xen-4.2.0-testing/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c -+++ xen-4.2.0-testing/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c +--- a/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c ++++ b/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c @@ -836,7 +836,7 @@ static int create_suspend_thread(checkpo static void stop_suspend_thread(checkpoint_state* s) @@ -150,10 +130,8 @@ Index: xen-4.2.0-testing/tools/python/xen/lowlevel/checkpoint/libcheckpoint.c s->done = 1; -Index: xen-4.2.0-testing/tools/python/xen/lowlevel/netlink/libnetlink.c -=================================================================== ---- xen-4.2.0-testing.orig/tools/python/xen/lowlevel/netlink/libnetlink.c -+++ xen-4.2.0-testing/tools/python/xen/lowlevel/netlink/libnetlink.c +--- a/tools/python/xen/lowlevel/netlink/libnetlink.c ++++ b/tools/python/xen/lowlevel/netlink/libnetlink.c @@ -433,7 +433,8 @@ int rtnl_from_file(FILE *rtnl, rtnl_filt nladdr.nl_groups = 0; @@ -164,10 +142,8 @@ Index: xen-4.2.0-testing/tools/python/xen/lowlevel/netlink/libnetlink.c int l; status = fread(&buf, 1, sizeof(*h), rtnl); -Index: xen-4.2.0-testing/xen/common/cpupool.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/common/cpupool.c -+++ xen-4.2.0-testing/xen/common/cpupool.c +--- a/xen/common/cpupool.c ++++ b/xen/common/cpupool.c @@ -371,7 +371,7 @@ int cpupool_add_domain(struct domain *d, { struct cpupool *c; @@ -188,10 +164,8 @@ Index: xen-4.2.0-testing/xen/common/cpupool.c if ( d->cpupool == NULL ) return; -Index: xen-4.2.0-testing/xen/common/kexec.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/common/kexec.c -+++ xen-4.2.0-testing/xen/common/kexec.c +--- a/xen/common/kexec.c ++++ b/xen/common/kexec.c @@ -817,7 +817,8 @@ static int kexec_exec(XEN_GUEST_HANDLE(v { xen_kexec_exec_t exec; @@ -202,10 +176,8 @@ Index: xen-4.2.0-testing/xen/common/kexec.c if ( unlikely(copy_from_guest(&exec, uarg, 1)) ) return -EFAULT; -Index: xen-4.2.0-testing/xen/arch/x86/time.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/time.c -+++ xen-4.2.0-testing/xen/arch/x86/time.c +--- a/xen/arch/x86/time.c ++++ b/xen/arch/x86/time.c @@ -1012,7 +1012,8 @@ static void local_time_calibration(void) * System timestamps, extrapolated from local and master oscillators, * taken during this calibration and the previous calibration. @@ -216,11 +188,9 @@ Index: xen-4.2.0-testing/xen/arch/x86/time.c s_time_t prev_master_stime, curr_master_stime; /* TSC timestamps taken during this calibration and prev calibration. */ -Index: xen-4.2.0-testing/xen/arch/x86/mm/p2m.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/mm/p2m.c -+++ xen-4.2.0-testing/xen/arch/x86/mm/p2m.c -@@ -483,7 +483,7 @@ p2m_remove_page(struct p2m_domain *p2m, +--- a/xen/arch/x86/mm/p2m.c ++++ b/xen/arch/x86/mm/p2m.c +@@ -483,7 +483,7 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned int page_order) { unsigned long i; @@ -229,10 +199,8 @@ Index: xen-4.2.0-testing/xen/arch/x86/mm/p2m.c p2m_type_t t; p2m_access_t a; -Index: xen-4.2.0-testing/xen/arch/x86/cpu/intel_cacheinfo.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/cpu/intel_cacheinfo.c -+++ xen-4.2.0-testing/xen/arch/x86/cpu/intel_cacheinfo.c +--- a/xen/arch/x86/cpu/intel_cacheinfo.c ++++ b/xen/arch/x86/cpu/intel_cacheinfo.c @@ -169,7 +169,8 @@ unsigned int __cpuinit init_intel_cachei unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */ unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ @@ -243,10 +211,8 @@ Index: xen-4.2.0-testing/xen/arch/x86/cpu/intel_cacheinfo.c if (c->cpuid_level > 3) { static int is_initialized; -Index: xen-4.2.0-testing/xen/arch/x86/hvm/viridian.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/hvm/viridian.c -+++ xen-4.2.0-testing/xen/arch/x86/hvm/viridian.c +--- a/xen/arch/x86/hvm/viridian.c ++++ b/xen/arch/x86/hvm/viridian.c @@ -317,7 +317,7 @@ int rdmsr_viridian_regs(uint32_t idx, ui int viridian_hypercall(struct cpu_user_regs *regs) { @@ -256,11 +222,9 @@ Index: xen-4.2.0-testing/xen/arch/x86/hvm/viridian.c uint16_t status = HV_STATUS_SUCCESS; union hypercall_input { -Index: xen-4.2.0-testing/xen/arch/x86/mm.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/mm.c -+++ xen-4.2.0-testing/xen/arch/x86/mm.c -@@ -4969,7 +4969,7 @@ static int ptwr_emulated_update( +--- a/xen/arch/x86/mm.c ++++ b/xen/arch/x86/mm.c +@@ -4973,7 +4973,7 @@ static int ptwr_emulated_update( { unsigned long mfn; unsigned long unaligned_addr = addr; @@ -269,11 +233,9 @@ Index: xen-4.2.0-testing/xen/arch/x86/mm.c l1_pgentry_t pte, ol1e, nl1e, *pl1e; struct vcpu *v = current; struct domain *d = v->domain; -Index: xen-4.2.0-testing/xen/common/tmem.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/common/tmem.c -+++ xen-4.2.0-testing/xen/common/tmem.c -@@ -1348,7 +1348,8 @@ obj_unlock: +--- a/xen/common/tmem.c ++++ b/xen/common/tmem.c +@@ -1352,7 +1352,8 @@ obj_unlock: static int tmem_evict(void) { client_t *client = tmh_client_from_current(); @@ -283,8 +245,8 @@ Index: xen-4.2.0-testing/xen/common/tmem.c obj_t *obj; pool_t *pool; int ret = 0; -@@ -1585,7 +1586,8 @@ static NOINLINE int do_tmem_put(pool_t * - pagesize_t pfn_offset, pagesize_t len, void *cva) +@@ -1589,7 +1590,8 @@ static NOINLINE int do_tmem_put(pool_t * + pagesize_t pfn_offset, pagesize_t len, tmem_cli_va_t clibuf) { obj_t *obj = NULL, *objfound = NULL, *objnew = NULL; - pgp_t *pgp = NULL, *pgpdel = NULL; @@ -293,29 +255,27 @@ Index: xen-4.2.0-testing/xen/common/tmem.c client_t *client = pool->client; int ret = client->frozen ? -EFROZEN : -ENOMEM; -Index: xen-4.2.0-testing/xen/common/tmem_xen.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/common/tmem_xen.c -+++ xen-4.2.0-testing/xen/common/tmem_xen.c -@@ -181,7 +181,7 @@ EXPORT int tmh_copy_from_client(pfp_t *p +--- a/xen/common/tmem_xen.c ++++ b/xen/common/tmem_xen.c +@@ -196,7 +196,7 @@ EXPORT int tmh_copy_from_client(pfp_t *p EXPORT int tmh_compress_from_client(tmem_cli_mfn_t cmfn, - void **out_va, size_t *out_len, void *cli_va) + void **out_va, size_t *out_len, tmem_cli_va_t clibuf) { - int ret = 0; + int __attribute__((__unused__)) ret = 0; unsigned char *dmem = this_cpu(dstmem); unsigned char *wmem = this_cpu(workmem); - pfp_t *cli_pfp = NULL; -@@ -241,7 +241,7 @@ EXPORT int tmh_decompress_to_client(tmem - pfp_t *cli_pfp = NULL; + char *scratch = this_cpu(scratch_page); +@@ -272,7 +272,7 @@ EXPORT int tmh_decompress_to_client(tmem + void *cli_va = NULL; + char *scratch = this_cpu(scratch_page); size_t out_len = PAGE_SIZE; - bool_t tmemc = cli_va != NULL; /* if true, cli_va is control-op buffer */ - int ret; + int __attribute__((__unused__)) ret; - if ( !tmemc ) + if ( guest_handle_is_null(clibuf) ) { -@@ -370,15 +370,17 @@ static void tmh_persistent_pool_page_put +@@ -405,15 +405,17 @@ static void tmh_persistent_pool_page_put EXPORT tmh_client_t *tmh_client_init(cli_id_t cli_id) { tmh_client_t *tmh; @@ -334,11 +294,9 @@ Index: xen-4.2.0-testing/xen/common/tmem_xen.c tmh->persistent_pool = xmem_pool_create(name, tmh_persistent_pool_page_get, tmh_persistent_pool_page_put, PAGE_SIZE, 0, PAGE_SIZE); if ( tmh->persistent_pool == NULL ) -Index: xen-4.2.0-testing/xen/arch/x86/mm/shadow/multi.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/mm/shadow/multi.c -+++ xen-4.2.0-testing/xen/arch/x86/mm/shadow/multi.c -@@ -124,7 +124,7 @@ set_shadow_status(struct vcpu *v, mfn_t +--- a/xen/arch/x86/mm/shadow/multi.c ++++ b/xen/arch/x86/mm/shadow/multi.c +@@ -124,7 +124,7 @@ set_shadow_status(struct vcpu *v, mfn_t /* Put a shadow into the hash table */ { struct domain *d = v->domain; @@ -356,10 +314,8 @@ Index: xen-4.2.0-testing/xen/arch/x86/mm/shadow/multi.c shadow_l1e_t *sl1p, sl1e; struct page_info *sp; -Index: xen-4.2.0-testing/xen/arch/x86/domain_build.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/domain_build.c -+++ xen-4.2.0-testing/xen/arch/x86/domain_build.c +--- a/xen/arch/x86/domain_build.c ++++ b/xen/arch/x86/domain_build.c @@ -377,8 +377,7 @@ int __init construct_dom0( return rc; @@ -370,11 +326,9 @@ Index: xen-4.2.0-testing/xen/arch/x86/domain_build.c machine = elf_uval(&elf, elf.ehdr, e_machine); switch (CONFIG_PAGING_LEVELS) { case 3: /* x86_32p */ -Index: xen-4.2.0-testing/xen/arch/x86/traps.c -=================================================================== ---- xen-4.2.0-testing.orig/xen/arch/x86/traps.c -+++ xen-4.2.0-testing/xen/arch/x86/traps.c -@@ -1910,7 +1910,11 @@ static int emulate_privileged_op(struct +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -1910,7 +1910,11 @@ static int emulate_privileged_op(struct struct vcpu *v = current; unsigned long *reg, eip = regs->eip; u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0, lock = 0, rex = 0; diff --git a/xen.changes b/xen.changes index 3868ddf..4c5b776 100644 --- a/xen.changes +++ b/xen.changes @@ -1,3 +1,30 @@ +------------------------------------------------------------------- +Wed Sep 19 09:43:42 MDT 2012 - carnold@novell.com + +- Upstream patches from Jan + 25833-32on64-bogus-pt_base-adjust.patch + 25835-adjust-rcu-lock-domain.patch + 25836-VT-d-S3-MSI-resume.patch + 25850-tmem-xsa-15-1.patch + 25851-tmem-xsa-15-2.patch + 25852-tmem-xsa-15-3.patch + 25853-tmem-xsa-15-4.patch + 25854-tmem-xsa-15-5.patch + 25855-tmem-xsa-15-6.patch + 25856-tmem-xsa-15-7.patch + 25857-tmem-xsa-15-8.patch + 25858-tmem-xsa-15-9.patch + 25859-tmem-missing-break.patch + 25860-tmem-cleanup.patch + 25861-x86-early-fixmap.patch + 25862-sercon-non-com.patch + 25863-sercon-ehci-dbgp.patch + 25864-sercon-unused.patch + 25866-sercon-ns16550-pci-irq.patch + 25867-sercon-ns16550-parse.patch + 25874-x86-EFI-chain-cfg.patch + 25909-xenpm-consistent.patch + ------------------------------------------------------------------- Tue Sep 18 16:16:04 MDT 2012 - carnold@novell.com diff --git a/xen.spec b/xen.spec index 5ec958c..bf39b53 100644 --- a/xen.spec +++ b/xen.spec @@ -15,6 +15,7 @@ # Please submit bugfixes or comments via http://bugs.opensuse.org/ # + Name: xen ExclusiveArch: %ix86 x86_64 %define xvers 4.2 @@ -162,6 +163,28 @@ Source99: baselibs.conf # http://xenbits.xensource.com/ext/xenalyze Source20000: xenalyze.hg.tar.bz2 # Upstream patches +Patch25833: 25833-32on64-bogus-pt_base-adjust.patch +Patch25835: 25835-adjust-rcu-lock-domain.patch +Patch25836: 25836-VT-d-S3-MSI-resume.patch +Patch25850: 25850-tmem-xsa-15-1.patch +Patch25851: 25851-tmem-xsa-15-2.patch +Patch25852: 25852-tmem-xsa-15-3.patch +Patch25853: 25853-tmem-xsa-15-4.patch +Patch25854: 25854-tmem-xsa-15-5.patch +Patch25855: 25855-tmem-xsa-15-6.patch +Patch25856: 25856-tmem-xsa-15-7.patch +Patch25857: 25857-tmem-xsa-15-8.patch +Patch25858: 25858-tmem-xsa-15-9.patch +Patch25859: 25859-tmem-missing-break.patch +Patch25860: 25860-tmem-cleanup.patch +Patch25861: 25861-x86-early-fixmap.patch +Patch25862: 25862-sercon-non-com.patch +Patch25863: 25863-sercon-ehci-dbgp.patch +Patch25864: 25864-sercon-unused.patch +Patch25866: 25866-sercon-ns16550-pci-irq.patch +Patch25867: 25867-sercon-ns16550-parse.patch +Patch25874: 25874-x86-EFI-chain-cfg.patch +Patch25909: 25909-xenpm-consistent.patch # Upstream qemu patches # Our patches Patch301: xend-config.diff @@ -268,11 +291,11 @@ Patch481: xend-domain-lock-sfex.patch Patch500: 32on64-extra-mem.patch Patch501: x86-ioapic-ack-default.patch Patch502: x86-cpufreq-report.patch -Patch504: dom-print.patch -Patch505: pvdrv-import-shared-info.patch -Patch507: x86-extra-trap-info.patch -Patch508: pvdrv_emulation_control.patch -Patch509: blktap-pv-cdrom.patch +Patch503: x86-dom-print.patch +Patch504: pvdrv-import-shared-info.patch +Patch505: x86-extra-trap-info.patch +Patch506: pvdrv_emulation_control.patch +Patch507: blktap-pv-cdrom.patch Patch510: pv-driver-build.patch Patch511: supported_module.diff Patch512: magic_ioport_compat.patch @@ -623,6 +646,28 @@ Authors: tar xfj %{SOURCE6} -C $RPM_BUILD_DIR/%{xen_build_dir}/tools %patch20000 -p1 # Upstream patches +%patch25833 -p1 +%patch25835 -p1 +%patch25836 -p1 +%patch25850 -p1 +%patch25851 -p1 +%patch25852 -p1 +%patch25853 -p1 +%patch25854 -p1 +%patch25855 -p1 +%patch25856 -p1 +%patch25857 -p1 +%patch25858 -p1 +%patch25859 -p1 +%patch25860 -p1 +%patch25861 -p1 +%patch25862 -p1 +%patch25863 -p1 +%patch25864 -p1 +%patch25866 -p1 +%patch25867 -p1 +%patch25874 -p1 +%patch25909 -p1 # Qemu # Our patches %patch301 -p1 @@ -724,11 +769,11 @@ tar xfj %{SOURCE6} -C $RPM_BUILD_DIR/%{xen_build_dir}/tools %patch500 -p1 %patch501 -p1 %patch502 -p1 +%patch503 -p1 %patch504 -p1 %patch505 -p1 +%patch506 -p1 %patch507 -p1 -%patch508 -p1 -%patch509 -p1 %if %suse_version < 1220 %patch510 -p1 %endif