From patchwork Wed Mar 16 12:22:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yu Zhang X-Patchwork-Id: 8599631 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E8D489F294 for ; Wed, 16 Mar 2016 12:36:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4905E201EF for ; Wed, 16 Mar 2016 12:36:11 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7D069202AE for ; Wed, 16 Mar 2016 12:36:09 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1agAdj-0006Mv-F1; Wed, 16 Mar 2016 12:33:27 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1agAdh-0006Mc-UO for xen-devel@lists.xen.org; Wed, 16 Mar 2016 12:33:26 +0000 Received: from [85.158.139.211] by server-5.bemta-5.messagelabs.com id 0F/A5-03597-59259E65; Wed, 16 Mar 2016 12:33:25 +0000 X-Env-Sender: yu.c.zhang@linux.intel.com X-Msg-Ref: server-13.tower-206.messagelabs.com!1458131603!29155961!1 X-Originating-IP: [192.55.52.88] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTkyLjU1LjUyLjg4ID0+IDM3NDcyNQ==\n X-StarScan-Received: X-StarScan-Version: 8.11; banners=-,-,- X-VirusChecked: Checked Received: (qmail 56167 invoked from network); 16 Mar 2016 12:33:23 -0000 Received: from mga01.intel.com (HELO mga01.intel.com) (192.55.52.88) by server-13.tower-206.messagelabs.com with SMTP; 16 Mar 2016 12:33:23 -0000 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP; 16 Mar 2016 05:33:22 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,344,1455004800"; d="scan'208";a="925298897" Received: from zhangyu-xengt.bj.intel.com ([10.238.157.44]) by fmsmga001.fm.intel.com with ESMTP; 16 Mar 2016 05:33:20 -0700 From: Yu Zhang To: xen-devel@lists.xen.org Date: Wed, 16 Mar 2016 20:22:40 +0800 Message-Id: <1458130960-30109-1-git-send-email-yu.c.zhang@linux.intel.com> X-Mailer: git-send-email 1.9.1 Cc: kevin.tian@intel.com, keir@xen.org, jbeulich@suse.com, george.dunlap@eu.citrix.com, andrew.cooper3@citrix.com, tim@xen.org, Paul.Durrant@citrix.com, zhiyuan.lv@intel.com, jun.nakajima@intel.com Subject: [Xen-devel] [PATCH 3/3] Add HVMOP to map guest ram with p2m_ioreq_server to an ioreq server X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP A new HVMOP - HVMOP_map_mem_type_to_ioreq_server, is added to let one ioreq server claim its responsibility for the handling of guest pages with p2m type p2m_ioreq_server. Users of this HVMOP can specify whether the p2m_ioreq_server is supposed to handle write accesses or read ones in a flag. By now, we only support one ioreq server for this p2m type, so once an ioreq server has claimed its ownership, following calls of the HVMOP_map_mem_type_to_ioreq_server will fail. Note: this HVMOP does not change the p2m type of any guest ram page, until the HVMOP_set_mem_type is triggered. So normally the steps would be the backend driver first claims its ownership of guest ram pages with p2m_ioreq_server type. At then sets the memory type to p2m_ioreq_server for specified guest ram pages. Signed-off-by: Paul Durrant Signed-off-by: Yu Zhang --- xen/arch/x86/hvm/emulate.c | 118 +++++++++++++++++++++++++++++++++++++-- xen/arch/x86/hvm/hvm.c | 92 +++++++++++++++++++++++++++++- xen/arch/x86/mm/hap/nested_hap.c | 2 +- xen/arch/x86/mm/p2m-ept.c | 9 ++- xen/arch/x86/mm/p2m-pt.c | 25 ++++++--- xen/arch/x86/mm/p2m.c | 79 ++++++++++++++++++++++++++ xen/arch/x86/mm/shadow/multi.c | 26 ++++++++- xen/include/asm-x86/p2m.h | 19 ++++++- xen/include/public/hvm/hvm_op.h | 24 ++++++++ 9 files changed, 374 insertions(+), 20 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index ddc8007..ace23ba 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -94,11 +94,69 @@ static const struct hvm_io_handler null_handler = { .ops = &null_ops }; +static int mem_read(const struct hvm_io_handler *io_handler, + uint64_t addr, + uint32_t size, + uint64_t *data) +{ + struct domain *currd = current->domain; + unsigned long gmfn = paddr_to_pfn(addr); + unsigned long offset = addr & ~PAGE_MASK; + struct page_info *page = get_page_from_gfn(currd, gmfn, NULL, P2M_UNSHARE); + uint8_t *p; + + if ( !page ) + return X86EMUL_UNHANDLEABLE; + + p = __map_domain_page(page); + p += offset; + memcpy(data, p, size); + + unmap_domain_page(p); + put_page(page); + + return X86EMUL_OKAY; +} + +static int mem_write(const struct hvm_io_handler *handler, + uint64_t addr, + uint32_t size, + uint64_t data) +{ + struct domain *currd = current->domain; + unsigned long gmfn = paddr_to_pfn(addr); + unsigned long offset = addr & ~PAGE_MASK; + struct page_info *page = get_page_from_gfn(currd, gmfn, NULL, P2M_UNSHARE); + uint8_t *p; + + if ( !page ) + return X86EMUL_UNHANDLEABLE; + + p = __map_domain_page(page); + p += offset; + memcpy(p, &data, size); + + unmap_domain_page(p); + put_page(page); + + return X86EMUL_OKAY; +} + +static const struct hvm_io_ops mem_ops = { + .read = mem_read, + .write = mem_write +}; + +static const struct hvm_io_handler mem_handler = { + .ops = &mem_ops +}; + static int hvmemul_do_io( bool_t is_mmio, paddr_t addr, unsigned long reps, unsigned int size, uint8_t dir, bool_t df, bool_t data_is_addr, uintptr_t data) { struct vcpu *curr = current; + struct domain *currd = curr->domain; struct hvm_vcpu_io *vio = &curr->arch.hvm_vcpu.hvm_io; ioreq_t p = { .type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO, @@ -140,7 +198,7 @@ static int hvmemul_do_io( (p.dir != dir) || (p.df != df) || (p.data_is_ptr != data_is_addr) ) - domain_crash(curr->domain); + domain_crash(currd); if ( data_is_addr ) return X86EMUL_UNHANDLEABLE; @@ -168,13 +226,65 @@ static int hvmemul_do_io( break; case X86EMUL_UNHANDLEABLE: { - struct hvm_ioreq_server *s = - hvm_select_ioreq_server(curr->domain, &p); + struct hvm_ioreq_server *s; + p2m_type_t p2mt; + + if ( is_mmio ) + { + unsigned long gmfn = paddr_to_pfn(addr); + + (void) get_gfn_query_unlocked(currd, gmfn, &p2mt); + + switch ( p2mt ) + { + case p2m_ioreq_server: + { + unsigned long flags; + + p2m_get_ioreq_server(currd, p2mt, &flags, &s); + + if ( !s ) + break; + + if ( (dir == IOREQ_READ && + !(flags & P2M_IOREQ_HANDLE_READ_ACCESS)) || + (dir == IOREQ_WRITE && + !(flags & P2M_IOREQ_HANDLE_WRITE_ACCESS)) ) + s = NULL; + + break; + } + case p2m_ram_rw: + s = NULL; + break; + + default: + s = hvm_select_ioreq_server(currd, &p); + break; + } + } + else + { + p2mt = p2m_invalid; + + s = hvm_select_ioreq_server(currd, &p); + } /* If there is no suitable backing DM, just ignore accesses */ if ( !s ) { - rc = hvm_process_io_intercept(&null_handler, &p); + switch ( p2mt ) + { + case p2m_ioreq_server: + case p2m_ram_rw: + rc = hvm_process_io_intercept(&mem_handler, &p); + break; + + default: + rc = hvm_process_io_intercept(&null_handler, &p); + break; + } + vio->io_req.state = STATE_IOREQ_NONE; } else diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 07eee4a..29ddbc4 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1252,6 +1252,8 @@ static int hvm_destroy_ioreq_server(struct domain *d, ioservid_t id) domain_pause(d); + p2m_destroy_ioreq_server(d, s); + hvm_ioreq_server_disable(s, 0); list_del(&s->list_entry); @@ -1411,6 +1413,55 @@ static int hvm_unmap_io_range_from_ioreq_server(struct domain *d, ioservid_t id, return rc; } +static int hvm_map_mem_type_to_ioreq_server(struct domain *d, + ioservid_t id, + hvmmem_type_t type, + uint32_t flags) +{ + struct hvm_ioreq_server *s; + p2m_type_t p2mt; + int rc; + + switch ( type ) + { + case HVMMEM_ioreq_server: + p2mt = p2m_ioreq_server; + break; + + default: + return -EINVAL; + } + + if ( flags & ~(HVMOP_IOREQ_MEM_ACCESS_READ | + HVMOP_IOREQ_MEM_ACCESS_WRITE) ) + return -EINVAL; + + spin_lock(&d->arch.hvm_domain.ioreq_server.lock); + + rc = -ENOENT; + list_for_each_entry ( s, + &d->arch.hvm_domain.ioreq_server.list, + list_entry ) + { + if ( s == d->arch.hvm_domain.default_ioreq_server ) + continue; + + if ( s->id == id ) + { + rc = p2m_set_ioreq_server(d, p2mt, flags, s); + if ( rc ) + break; + + gdprintk(XENLOG_DEBUG, "%u claimed type p2m_ioreq_server\n", + s->id); + } + } + + spin_unlock(&d->arch.hvm_domain.ioreq_server.lock); + + return rc; +} + static int hvm_set_ioreq_server_state(struct domain *d, ioservid_t id, bool_t enabled) { @@ -3174,9 +3225,9 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, * If this GFN is emulated MMIO or marked as read-only, pass the fault * to the mmio handler. */ - if ( (p2mt == p2m_mmio_dm) || - (npfec.write_access && - (p2m_is_discard_write(p2mt) || (p2mt == p2m_ioreq_server))) ) + if ( (p2mt == p2m_mmio_dm) || + (p2mt == p2m_ioreq_server) || + (npfec.write_access && p2m_is_discard_write(p2mt)) ) { __put_gfn(p2m, gfn); if ( ap2m_active ) @@ -5989,6 +6040,36 @@ static int hvmop_unmap_io_range_from_ioreq_server( return rc; } +static int hvmop_map_mem_type_to_ioreq_server( + XEN_GUEST_HANDLE_PARAM(xen_hvm_map_mem_type_to_ioreq_server_t) uop) +{ + xen_hvm_map_mem_type_to_ioreq_server_t op; + struct domain *d; + int rc; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + + rc = rcu_lock_remote_domain_by_id(op.domid, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto out; + + rc = xsm_hvm_ioreq_server(XSM_DM_PRIV, d, + HVMOP_map_mem_type_to_ioreq_server); + if ( rc != 0 ) + goto out; + + rc = hvm_map_mem_type_to_ioreq_server(d, op.id, op.type, op.flags); + + out: + rcu_unlock_domain(d); + return rc; +} + static int hvmop_set_ioreq_server_state( XEN_GUEST_HANDLE_PARAM(xen_hvm_set_ioreq_server_state_t) uop) { @@ -6754,6 +6835,11 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) guest_handle_cast(arg, xen_hvm_io_range_t)); break; + case HVMOP_map_mem_type_to_ioreq_server: + rc = hvmop_map_mem_type_to_ioreq_server( + guest_handle_cast(arg, xen_hvm_map_mem_type_to_ioreq_server_t)); + break; + case HVMOP_set_ioreq_server_state: rc = hvmop_set_ioreq_server_state( guest_handle_cast(arg, xen_hvm_set_ioreq_server_state_t)); diff --git a/xen/arch/x86/mm/hap/nested_hap.c b/xen/arch/x86/mm/hap/nested_hap.c index 9cee5a0..bbb6d85 100644 --- a/xen/arch/x86/mm/hap/nested_hap.c +++ b/xen/arch/x86/mm/hap/nested_hap.c @@ -174,7 +174,7 @@ nestedhap_walk_L0_p2m(struct p2m_domain *p2m, paddr_t L1_gpa, paddr_t *L0_gpa, if ( *p2mt == p2m_mmio_direct ) goto direct_mmio_out; rc = NESTEDHVM_PAGEFAULT_MMIO; - if ( *p2mt == p2m_mmio_dm ) + if ( *p2mt == p2m_mmio_dm || *p2mt == p2m_ioreq_server ) goto out; rc = NESTEDHVM_PAGEFAULT_L0_ERROR; diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index 380ec25..21e04ce 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -132,6 +132,14 @@ static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry, entry->r = entry->w = entry->x = 1; entry->a = entry->d = !!cpu_has_vmx_ept_ad; break; + case p2m_ioreq_server: + entry->r = !(p2m->ioreq.flags & P2M_IOREQ_HANDLE_READ_ACCESS); + entry->w = (entry->r & + !(p2m->ioreq.flags & P2M_IOREQ_HANDLE_WRITE_ACCESS)); + entry->x = entry->r; + entry->a = !!cpu_has_vmx_ept_ad; + entry->d = 0; + break; case p2m_mmio_direct: entry->r = entry->x = 1; entry->w = !rangeset_contains_singleton(mmio_ro_ranges, @@ -171,7 +179,6 @@ static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry, entry->a = entry->d = !!cpu_has_vmx_ept_ad; break; case p2m_grant_map_ro: - case p2m_ioreq_server: entry->r = 1; entry->w = entry->x = 0; entry->a = !!cpu_has_vmx_ept_ad; diff --git a/xen/arch/x86/mm/p2m-pt.c b/xen/arch/x86/mm/p2m-pt.c index eabd2e3..7a0ddb8 100644 --- a/xen/arch/x86/mm/p2m-pt.c +++ b/xen/arch/x86/mm/p2m-pt.c @@ -72,8 +72,8 @@ static const unsigned long pgt[] = { PGT_l3_page_table }; -static unsigned long p2m_type_to_flags(p2m_type_t t, mfn_t mfn, - unsigned int level) +static unsigned long p2m_type_to_flags(struct p2m_domain *p2m, p2m_type_t t, + mfn_t mfn, unsigned int level) { unsigned long flags; /* @@ -94,8 +94,18 @@ static unsigned long p2m_type_to_flags(p2m_type_t t, mfn_t mfn, default: return flags | _PAGE_NX_BIT; case p2m_grant_map_ro: - case p2m_ioreq_server: return flags | P2M_BASE_FLAGS | _PAGE_NX_BIT; + case p2m_ioreq_server: + { + flags |= P2M_BASE_FLAGS | _PAGE_RW; + + if ( p2m->ioreq.flags & P2M_IOREQ_HANDLE_READ_ACCESS ) + return flags & ~(_PAGE_PRESENT | _PAGE_RW); + else if ( p2m->ioreq.flags & P2M_IOREQ_HANDLE_WRITE_ACCESS ) + return flags & ~_PAGE_RW; + else + return flags; + } case p2m_ram_ro: case p2m_ram_logdirty: case p2m_ram_shared: @@ -442,7 +452,8 @@ static int do_recalc(struct p2m_domain *p2m, unsigned long gfn) p2m_type_t p2mt = p2m_is_logdirty_range(p2m, gfn & mask, gfn | ~mask) ? p2m_ram_logdirty : p2m_ram_rw; unsigned long mfn = l1e_get_pfn(e); - unsigned long flags = p2m_type_to_flags(p2mt, _mfn(mfn), level); + unsigned long flags = p2m_type_to_flags(p2m, p2mt, + _mfn(mfn), level); if ( level ) { @@ -579,7 +590,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, ASSERT(!mfn_valid(mfn) || p2mt != p2m_mmio_direct); l3e_content = mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ? l3e_from_pfn(mfn_x(mfn), - p2m_type_to_flags(p2mt, mfn, 2) | _PAGE_PSE) + p2m_type_to_flags(p2m, p2mt, mfn, 2) | _PAGE_PSE) : l3e_empty(); entry_content.l1 = l3e_content.l3; @@ -615,7 +626,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ) entry_content = p2m_l1e_from_pfn(mfn_x(mfn), - p2m_type_to_flags(p2mt, mfn, 0)); + p2m_type_to_flags(p2m, p2mt, mfn, 0)); else entry_content = l1e_empty(); @@ -651,7 +662,7 @@ p2m_pt_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, ASSERT(!mfn_valid(mfn) || p2mt != p2m_mmio_direct); if ( mfn_valid(mfn) || p2m_allows_invalid_mfn(p2mt) ) l2e_content = l2e_from_pfn(mfn_x(mfn), - p2m_type_to_flags(p2mt, mfn, 1) | + p2m_type_to_flags(p2m, p2mt, mfn, 1) | _PAGE_PSE); else l2e_content = l2e_empty(); diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index b3fce1b..2f9a6d9 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -83,6 +83,8 @@ static int p2m_initialise(struct domain *d, struct p2m_domain *p2m) else p2m_pt_init(p2m); + spin_lock_init(&p2m->ioreq.lock); + return ret; } @@ -289,6 +291,83 @@ void p2m_memory_type_changed(struct domain *d) } } +int p2m_set_ioreq_server(struct domain *d, p2m_type_t t, + unsigned long flags, + struct hvm_ioreq_server *s) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + int rc; + + spin_lock(&p2m->ioreq.lock); + + rc = -EINVAL; + if ( t != p2m_ioreq_server ) + goto out; + + rc = -EBUSY; + if ( ( p2m->ioreq.server != NULL ) && (flags != 0) ) + goto out; + + if ( flags == 0 ) + { + p2m->ioreq.server = NULL; + p2m->ioreq.flags = 0; + } + else + { + p2m->ioreq.server = s; + p2m->ioreq.flags = flags; + } + + p2m_memory_type_changed(d); + + rc = 0; + +out: + spin_unlock(&p2m->ioreq.lock); + + return rc; +} + +void p2m_get_ioreq_server(struct domain *d, p2m_type_t t, + unsigned long *flags, + struct hvm_ioreq_server **s) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + + if ( t != p2m_ioreq_server ) + { + *s = NULL; + *flags = 0; + return; + } + + spin_lock(&p2m->ioreq.lock); + + *s = p2m->ioreq.server; + *flags = p2m->ioreq.flags; + + spin_unlock(&p2m->ioreq.lock); +} + +void p2m_destroy_ioreq_server(struct domain *d, + struct hvm_ioreq_server *s) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + + spin_lock(&p2m->ioreq.lock); + + if ( p2m->ioreq.server == s ) + { + p2m->ioreq.server = NULL; + p2m->ioreq.flags = 0; + } + + p2m_memory_type_changed(d); + + spin_unlock(&p2m->ioreq.lock); +} + void p2m_enable_hardware_log_dirty(struct domain *d) { struct p2m_domain *p2m = p2m_get_hostp2m(d); diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index c81302a..c836517 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -530,6 +530,7 @@ _sh_propagate(struct vcpu *v, guest_l1e_t guest_entry = { guest_intpte }; shadow_l1e_t *sp = shadow_entry_ptr; struct domain *d = v->domain; + struct p2m_domain *p2m = d->arch.p2m; struct sh_dirty_vram *dirty_vram = d->arch.hvm_domain.dirty_vram; gfn_t target_gfn = guest_l1e_get_gfn(guest_entry); u32 pass_thru_flags; @@ -695,6 +696,15 @@ _sh_propagate(struct vcpu *v, sflags &= ~_PAGE_RW; } + if ( p2mt == p2m_ioreq_server ) + { + if ( p2m->ioreq.flags & P2M_IOREQ_HANDLE_WRITE_ACCESS ) + sflags &= ~_PAGE_RW; + + if ( p2m->ioreq.flags & P2M_IOREQ_HANDLE_READ_ACCESS ) + sflags &= ~_PAGE_PRESENT; + } + /* Read-only memory */ if ( p2m_is_readonly(p2mt) ) sflags &= ~_PAGE_RW; @@ -2855,6 +2865,7 @@ static int sh_page_fault(struct vcpu *v, struct cpu_user_regs *regs) { struct domain *d = v->domain; + struct p2m_domain *p2m = d->arch.p2m; walk_t gw; gfn_t gfn = _gfn(0); mfn_t gmfn, sl1mfn = _mfn(0); @@ -3224,13 +3235,24 @@ static int sh_page_fault(struct vcpu *v, } /* Need to hand off device-model MMIO to the device model */ - if ( p2mt == p2m_mmio_dm - || (p2mt == p2m_ioreq_server && ft == ft_demand_write) ) + if ( p2mt == p2m_mmio_dm ) { gpa = guest_walk_to_gpa(&gw); goto mmio; } + if ( p2mt == p2m_ioreq_server ) + { + if ( (ft == ft_demand_write && + (p2m->ioreq.flags & P2M_IOREQ_HANDLE_WRITE_ACCESS)) || + (ft == ft_demand_read && + (p2m->ioreq.flags & P2M_IOREQ_HANDLE_READ_ACCESS)) ) + { + gpa = guest_walk_to_gpa(&gw); + goto mmio; + } + } + /* Ignore attempts to write to read-only memory. */ if ( p2m_is_readonly(p2mt) && (ft == ft_demand_write) ) { diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 084a1f2..3076fa8 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -111,8 +111,7 @@ typedef unsigned int p2m_query_t; #define P2M_RO_TYPES (p2m_to_mask(p2m_ram_logdirty) \ | p2m_to_mask(p2m_ram_ro) \ | p2m_to_mask(p2m_grant_map_ro) \ - | p2m_to_mask(p2m_ram_shared) \ - | p2m_to_mask(p2m_ioreq_server)) + | p2m_to_mask(p2m_ram_shared)) /* Write-discard types, which should discard the write operations */ #define P2M_DISCARD_WRITE_TYPES (p2m_to_mask(p2m_ram_ro) \ @@ -321,6 +320,16 @@ struct p2m_domain { struct ept_data ept; /* NPT-equivalent structure could be added here. */ }; + + struct { + spinlock_t lock; + struct hvm_ioreq_server *server; + unsigned long flags; + +#define P2M_IOREQ_HANDLE_WRITE_ACCESS HVMOP_IOREQ_MEM_ACCESS_WRITE +#define P2M_IOREQ_HANDLE_READ_ACCESS HVMOP_IOREQ_MEM_ACCESS_READ + + } ioreq; }; /* get host p2m table */ @@ -822,6 +831,12 @@ static inline unsigned int p2m_get_iommu_flags(p2m_type_t p2mt) return flags; } +int p2m_set_ioreq_server(struct domain *d, p2m_type_t t, unsigned long flags, + struct hvm_ioreq_server *s); +void p2m_get_ioreq_server(struct domain *d, p2m_type_t t, unsigned long *flags, + struct hvm_ioreq_server **s); +void p2m_destroy_ioreq_server(struct domain *d, struct hvm_ioreq_server *s); + #endif /* _XEN_P2M_H */ /* diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h index a1eae52..e7fc75d 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -489,6 +489,30 @@ struct xen_hvm_altp2m_op { typedef struct xen_hvm_altp2m_op xen_hvm_altp2m_op_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_altp2m_op_t); +#if defined(__XEN__) || defined(__XEN_TOOLS__) + +#define HVMOP_map_mem_type_to_ioreq_server 26 +struct xen_hvm_map_mem_type_to_ioreq_server { + domid_t domid; /* IN - domain to be serviced */ + ioservid_t id; /* IN - server id */ + hvmmem_type_t type; /* IN - memory type */ + uint32_t flags; /* IN - types of access to be + intercepted */ +#define _HVMOP_IOREQ_MEM_ACCESS_READ 0 +#define HVMOP_IOREQ_MEM_ACCESS_READ \ + (1u << _HVMOP_IOREQ_MEM_ACCESS_READ) + +#define _HVMOP_IOREQ_MEM_ACCESS_WRITE 1 +#define HVMOP_IOREQ_MEM_ACCESS_WRITE \ + (1u << _HVMOP_IOREQ_MEM_ACCESS_WRITE) +}; +typedef struct xen_hvm_map_mem_type_to_ioreq_server + xen_hvm_map_mem_type_to_ioreq_server_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_map_mem_type_to_ioreq_server_t); + +#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ + + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ /*