[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH V2 01/23] x86/ioreq: Prepare IOREQ feature for making it common
> -----Original Message----- > From: Oleksandr Tyshchenko <olekstysh@xxxxxxxxx> > Sent: 15 October 2020 17:44 > To: xen-devel@xxxxxxxxxxxxxxxxxxxx > Cc: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>; Paul Durrant > <paul@xxxxxxx>; Jan Beulich > <jbeulich@xxxxxxxx>; Andrew Cooper <andrew.cooper3@xxxxxxxxxx>; Roger Pau > Monné > <roger.pau@xxxxxxxxxx>; Julien Grall <julien@xxxxxxx>; Stefano Stabellini > <sstabellini@xxxxxxxxxx>; > Wei Liu <wl@xxxxxxx>; Julien Grall <julien.grall@xxxxxxx> > Subject: [PATCH V2 01/23] x86/ioreq: Prepare IOREQ feature for making it > common > > From: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx> > > As a lot of x86 code can be re-used on Arm later on, this > patch makes some preparation to x86/hvm/ioreq.c before moving > to the common code. This way we will get a verbatim copy for > a code movement in subsequent patch (arch/x86/hvm/ioreq.c > will be *just* renamed to common/ioreq). > > This patch does the following: > 1. Introduce *inline* arch_hvm_ioreq_init(), arch_hvm_ioreq_destroy(), > arch_hvm_io_completion(), arch_hvm_destroy_ioreq_server() and > hvm_ioreq_server_get_type_addr() to abstract arch specific materials. > 2 Make hvm_map_mem_type_to_ioreq_server() *inline*. It is not going > to be called from the common code. > 3. Make get_ioreq_server() global. It is going to be called from > a few places. > 4. Add IOREQ_STATUS_* #define-s and update candidates for moving. > 5. Re-order #include-s alphabetically. > > This support is going to be used on Arm to be able run device > emulator outside of Xen hypervisor. > > Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx> > CC: Julien Grall <julien.grall@xxxxxxx> > > --- > Please note, this is a split/cleanup/hardening of Julien's PoC: > "Add support for Guest IO forwarding to a device emulator" > > Changes RFC -> V1: > - new patch, was split from: > "[RFC PATCH V1 01/12] hvm/ioreq: Make x86's IOREQ feature common" > - fold the check of p->type into hvm_get_ioreq_server_range_type() > and make it return success/failure > - remove relocate_portio_handler() call from arch_hvm_ioreq_destroy() > in arch/x86/hvm/ioreq.c > - introduce arch_hvm_destroy_ioreq_server()/arch_handle_hvm_io_completion() > > Changes V1 -> V2: > - update patch description > - make arch functions inline and put them into arch header > to achieve a truly rename by the subsequent patch > - return void in arch_hvm_destroy_ioreq_server() > - return bool in arch_hvm_ioreq_destroy() > - bring relocate_portio_handler() back to arch_hvm_ioreq_destroy() > - rename IOREQ_IO* to IOREQ_STATUS* > - remove *handle* from arch_handle_hvm_io_completion() > - re-order #include-s alphabetically > - rename hvm_get_ioreq_server_range_type() to > hvm_ioreq_server_get_type_addr() > and add "const" to several arguments > --- > xen/arch/x86/hvm/ioreq.c | 153 +++++-------------------------------- > xen/include/asm-x86/hvm/ioreq.h | 165 > +++++++++++++++++++++++++++++++++++++++- > 2 files changed, 184 insertions(+), 134 deletions(-) > > diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c > index 1cc27df..d3433d7 100644 > --- a/xen/arch/x86/hvm/ioreq.c > +++ b/xen/arch/x86/hvm/ioreq.c > @@ -1,5 +1,5 @@ > /* > - * hvm/io.c: hardware virtual machine I/O emulation > + * ioreq.c: hardware virtual machine I/O emulation > * > * Copyright (c) 2016 Citrix Systems Inc. > * > @@ -17,21 +17,18 @@ > */ > > #include <xen/ctype.h> > +#include <xen/domain.h> > +#include <xen/event.h> > #include <xen/init.h> > +#include <xen/irq.h> > #include <xen/lib.h> > -#include <xen/trace.h> > +#include <xen/paging.h> > #include <xen/sched.h> > -#include <xen/irq.h> > #include <xen/softirq.h> > -#include <xen/domain.h> > -#include <xen/event.h> > -#include <xen/paging.h> > +#include <xen/trace.h> > #include <xen/vpci.h> > > -#include <asm/hvm/emulate.h> > -#include <asm/hvm/hvm.h> > #include <asm/hvm/ioreq.h> > -#include <asm/hvm/vmx/vmx.h> > > #include <public/hvm/ioreq.h> > #include <public/hvm/params.h> > @@ -48,8 +45,8 @@ static void set_ioreq_server(struct domain *d, unsigned int > id, > #define GET_IOREQ_SERVER(d, id) \ > (d)->arch.hvm.ioreq_server.server[id] > > -static struct hvm_ioreq_server *get_ioreq_server(const struct domain *d, > - unsigned int id) > +struct hvm_ioreq_server *get_ioreq_server(const struct domain *d, > + unsigned int id) > { > if ( id >= MAX_NR_IOREQ_SERVERS ) > return NULL; > @@ -209,19 +206,8 @@ bool handle_hvm_io_completion(struct vcpu *v) > return handle_pio(vio->io_req.addr, vio->io_req.size, > vio->io_req.dir); > > - case HVMIO_realmode_completion: > - { > - struct hvm_emulate_ctxt ctxt; > - > - hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs()); > - vmx_realmode_emulate_one(&ctxt); > - hvm_emulate_writeback(&ctxt); > - > - break; > - } > default: > - ASSERT_UNREACHABLE(); > - break; > + return arch_hvm_io_completion(io_completion); > } > > return true; > @@ -855,7 +841,7 @@ int hvm_destroy_ioreq_server(struct domain *d, ioservid_t > id) > > domain_pause(d); > > - p2m_set_ioreq_server(d, 0, s); > + arch_hvm_destroy_ioreq_server(s); > > hvm_ioreq_server_disable(s); > > @@ -1080,54 +1066,6 @@ int hvm_unmap_io_range_from_ioreq_server(struct domain > *d, ioservid_t id, > return rc; > } > > -/* > - * Map or unmap an ioreq server to specific memory type. For now, only > - * HVMMEM_ioreq_server is supported, and in the future new types can be > - * introduced, e.g. HVMMEM_ioreq_serverX mapped to ioreq server X. And > - * currently, only write operations are to be forwarded to an ioreq server. > - * Support for the emulation of read operations can be added when an ioreq > - * server has such requirement in the future. > - */ > -int hvm_map_mem_type_to_ioreq_server(struct domain *d, ioservid_t id, > - uint32_t type, uint32_t flags) > -{ > - struct hvm_ioreq_server *s; > - int rc; > - > - if ( type != HVMMEM_ioreq_server ) > - return -EINVAL; > - > - if ( flags & ~XEN_DMOP_IOREQ_MEM_ACCESS_WRITE ) > - return -EINVAL; > - > - spin_lock_recursive(&d->arch.hvm.ioreq_server.lock); > - > - s = get_ioreq_server(d, id); > - > - rc = -ENOENT; > - if ( !s ) > - goto out; > - > - rc = -EPERM; > - if ( s->emulator != current->domain ) > - goto out; > - > - rc = p2m_set_ioreq_server(d, flags, s); > - > - out: > - spin_unlock_recursive(&d->arch.hvm.ioreq_server.lock); > - > - if ( rc == 0 && flags == 0 ) > - { > - struct p2m_domain *p2m = p2m_get_hostp2m(d); > - > - if ( read_atomic(&p2m->ioreq.entry_count) ) > - p2m_change_entry_type_global(d, p2m_ioreq_server, p2m_ram_rw); > - } > - > - return rc; > -} > - > int hvm_set_ioreq_server_state(struct domain *d, ioservid_t id, > bool enabled) > { > @@ -1215,7 +1153,7 @@ void hvm_destroy_all_ioreq_servers(struct domain *d) > struct hvm_ioreq_server *s; > unsigned int id; > > - if ( !relocate_portio_handler(d, 0xcf8, 0xcf8, 4) ) > + if ( !arch_hvm_ioreq_destroy(d) ) > return; > > spin_lock_recursive(&d->arch.hvm.ioreq_server.lock); > @@ -1243,50 +1181,13 @@ struct hvm_ioreq_server > *hvm_select_ioreq_server(struct domain *d, > ioreq_t *p) > { > struct hvm_ioreq_server *s; > - uint32_t cf8; > uint8_t type; > uint64_t addr; > unsigned int id; > > - if ( p->type != IOREQ_TYPE_COPY && p->type != IOREQ_TYPE_PIO ) > + if ( hvm_ioreq_server_get_type_addr(d, p, &type, &addr) ) > return NULL; > > - cf8 = d->arch.hvm.pci_cf8; > - > - if ( p->type == IOREQ_TYPE_PIO && > - (p->addr & ~3) == 0xcfc && > - CF8_ENABLED(cf8) ) > - { > - uint32_t x86_fam; > - pci_sbdf_t sbdf; > - unsigned int reg; > - > - reg = hvm_pci_decode_addr(cf8, p->addr, &sbdf); > - > - /* PCI config data cycle */ > - type = XEN_DMOP_IO_RANGE_PCI; > - addr = ((uint64_t)sbdf.sbdf << 32) | reg; > - /* AMD extended configuration space access? */ > - if ( CF8_ADDR_HI(cf8) && > - d->arch.cpuid->x86_vendor == X86_VENDOR_AMD && > - (x86_fam = get_cpu_family( > - d->arch.cpuid->basic.raw_fms, NULL, NULL)) >= 0x10 && > - x86_fam < 0x17 ) > - { > - uint64_t msr_val; > - > - if ( !rdmsr_safe(MSR_AMD64_NB_CFG, msr_val) && > - (msr_val & (1ULL << AMD64_NB_CFG_CF8_EXT_ENABLE_BIT)) ) > - addr |= CF8_ADDR_HI(cf8); > - } > - } > - else > - { > - type = (p->type == IOREQ_TYPE_PIO) ? > - XEN_DMOP_IO_RANGE_PORT : XEN_DMOP_IO_RANGE_MEMORY; > - addr = p->addr; > - } > - > FOR_EACH_IOREQ_SERVER(d, id, s) > { > struct rangeset *r; > @@ -1351,7 +1252,7 @@ static int hvm_send_buffered_ioreq(struct > hvm_ioreq_server *s, ioreq_t *p) > pg = iorp->va; > > if ( !pg ) > - return X86EMUL_UNHANDLEABLE; > + return IOREQ_STATUS_UNHANDLED; > > /* > * Return 0 for the cases we can't deal with: > @@ -1381,7 +1282,7 @@ static int hvm_send_buffered_ioreq(struct > hvm_ioreq_server *s, ioreq_t *p) > break; > default: > gdprintk(XENLOG_WARNING, "unexpected ioreq size: %u\n", p->size); > - return X86EMUL_UNHANDLEABLE; > + return IOREQ_STATUS_UNHANDLED; > } > > spin_lock(&s->bufioreq_lock); > @@ -1391,7 +1292,7 @@ static int hvm_send_buffered_ioreq(struct > hvm_ioreq_server *s, ioreq_t *p) > { > /* The queue is full: send the iopacket through the normal path. */ > spin_unlock(&s->bufioreq_lock); > - return X86EMUL_UNHANDLEABLE; > + return IOREQ_STATUS_UNHANDLED; > } > > pg->buf_ioreq[pg->ptrs.write_pointer % IOREQ_BUFFER_SLOT_NUM] = bp; > @@ -1422,7 +1323,7 @@ static int hvm_send_buffered_ioreq(struct > hvm_ioreq_server *s, ioreq_t *p) > notify_via_xen_event_channel(d, s->bufioreq_evtchn); > spin_unlock(&s->bufioreq_lock); > > - return X86EMUL_OKAY; > + return IOREQ_STATUS_HANDLED; > } > > int hvm_send_ioreq(struct hvm_ioreq_server *s, ioreq_t *proto_p, > @@ -1438,7 +1339,7 @@ int hvm_send_ioreq(struct hvm_ioreq_server *s, ioreq_t > *proto_p, > return hvm_send_buffered_ioreq(s, proto_p); > > if ( unlikely(!vcpu_start_shutdown_deferral(curr)) ) > - return X86EMUL_RETRY; > + return IOREQ_STATUS_RETRY; > > list_for_each_entry ( sv, > &s->ioreq_vcpu_list, > @@ -1478,11 +1379,11 @@ int hvm_send_ioreq(struct hvm_ioreq_server *s, > ioreq_t *proto_p, > notify_via_xen_event_channel(d, port); > > sv->pending = true; > - return X86EMUL_RETRY; > + return IOREQ_STATUS_RETRY; > } > } > > - return X86EMUL_UNHANDLEABLE; > + return IOREQ_STATUS_UNHANDLED; > } > > unsigned int hvm_broadcast_ioreq(ioreq_t *p, bool buffered) > @@ -1496,30 +1397,18 @@ unsigned int hvm_broadcast_ioreq(ioreq_t *p, bool > buffered) > if ( !s->enabled ) > continue; > > - if ( hvm_send_ioreq(s, p, buffered) == X86EMUL_UNHANDLEABLE ) > + if ( hvm_send_ioreq(s, p, buffered) == IOREQ_STATUS_UNHANDLED ) > failed++; > } > > return failed; > } > > -static int hvm_access_cf8( > - int dir, unsigned int port, unsigned int bytes, uint32_t *val) > -{ > - struct domain *d = current->domain; > - > - if ( dir == IOREQ_WRITE && bytes == 4 ) > - d->arch.hvm.pci_cf8 = *val; > - > - /* We always need to fall through to the catch all emulator */ > - return X86EMUL_UNHANDLEABLE; > -} > - > void hvm_ioreq_init(struct domain *d) > { > spin_lock_init(&d->arch.hvm.ioreq_server.lock); > > - register_portio_handler(d, 0xcf8, 4, hvm_access_cf8); > + arch_hvm_ioreq_init(d); > } > > /* > diff --git a/xen/include/asm-x86/hvm/ioreq.h b/xen/include/asm-x86/hvm/ioreq.h > index e2588e9..376e2ef 100644 > --- a/xen/include/asm-x86/hvm/ioreq.h > +++ b/xen/include/asm-x86/hvm/ioreq.h > @@ -19,6 +19,165 @@ > #ifndef __ASM_X86_HVM_IOREQ_H__ > #define __ASM_X86_HVM_IOREQ_H__ > > +#include <asm/hvm/emulate.h> > +#include <asm/hvm/vmx/vmx.h> > + > +#include <public/hvm/params.h> > + > +struct hvm_ioreq_server *get_ioreq_server(const struct domain *d, > + unsigned int id); > + > +static inline bool arch_hvm_io_completion(enum hvm_io_completion > io_completion) > +{ > + switch ( io_completion ) > + { > + case HVMIO_realmode_completion: > + { > + struct hvm_emulate_ctxt ctxt; > + > + hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs()); > + vmx_realmode_emulate_one(&ctxt); > + hvm_emulate_writeback(&ctxt); > + > + break; > + } > + > + default: > + ASSERT_UNREACHABLE(); > + break; > + } > + > + return true; > +} > + > +/* Called when target domain is paused */ > +static inline void arch_hvm_destroy_ioreq_server(struct hvm_ioreq_server *s) > +{ > + p2m_set_ioreq_server(s->target, 0, s); > +} > + > +/* > + * Map or unmap an ioreq server to specific memory type. For now, only > + * HVMMEM_ioreq_server is supported, and in the future new types can be > + * introduced, e.g. HVMMEM_ioreq_serverX mapped to ioreq server X. And > + * currently, only write operations are to be forwarded to an ioreq server. > + * Support for the emulation of read operations can be added when an ioreq > + * server has such requirement in the future. > + */ > +static inline int hvm_map_mem_type_to_ioreq_server(struct domain *d, > + ioservid_t id, > + uint32_t type, > + uint32_t flags) > +{ > + struct hvm_ioreq_server *s; > + int rc; > + > + if ( type != HVMMEM_ioreq_server ) > + return -EINVAL; > + > + if ( flags & ~XEN_DMOP_IOREQ_MEM_ACCESS_WRITE ) > + return -EINVAL; > + > + spin_lock_recursive(&d->arch.hvm.ioreq_server.lock); > + > + s = get_ioreq_server(d, id); > + > + rc = -ENOENT; > + if ( !s ) > + goto out; > + > + rc = -EPERM; > + if ( s->emulator != current->domain ) > + goto out; > + > + rc = p2m_set_ioreq_server(d, flags, s); > + > + out: > + spin_unlock_recursive(&d->arch.hvm.ioreq_server.lock); > + > + if ( rc == 0 && flags == 0 ) > + { > + struct p2m_domain *p2m = p2m_get_hostp2m(d); > + > + if ( read_atomic(&p2m->ioreq.entry_count) ) > + p2m_change_entry_type_global(d, p2m_ioreq_server, p2m_ram_rw); > + } > + > + return rc; > +} > + The above doesn't really feel right to me. It's really an entry point into the ioreq server code and as such I think it ought to be left in the common code. I suggest replacing the p2m_set_ioreq_server() function with an arch specific function (also taking the type) which you can then implement here. The rest of the patch looks ok. Paul > +static inline int hvm_ioreq_server_get_type_addr(const struct domain *d, > + const ioreq_t *p, > + uint8_t *type, > + uint64_t *addr) > +{ > + uint32_t cf8 = d->arch.hvm.pci_cf8; > + > + if ( p->type != IOREQ_TYPE_COPY && p->type != IOREQ_TYPE_PIO ) > + return -EINVAL; > + > + if ( p->type == IOREQ_TYPE_PIO && > + (p->addr & ~3) == 0xcfc && > + CF8_ENABLED(cf8) ) > + { > + uint32_t x86_fam; > + pci_sbdf_t sbdf; > + unsigned int reg; > + > + reg = hvm_pci_decode_addr(cf8, p->addr, &sbdf); > + > + /* PCI config data cycle */ > + *type = XEN_DMOP_IO_RANGE_PCI; > + *addr = ((uint64_t)sbdf.sbdf << 32) | reg; > + /* AMD extended configuration space access? */ > + if ( CF8_ADDR_HI(cf8) && > + d->arch.cpuid->x86_vendor == X86_VENDOR_AMD && > + (x86_fam = get_cpu_family( > + d->arch.cpuid->basic.raw_fms, NULL, NULL)) >= 0x10 && > + x86_fam < 0x17 ) > + { > + uint64_t msr_val; > + > + if ( !rdmsr_safe(MSR_AMD64_NB_CFG, msr_val) && > + (msr_val & (1ULL << AMD64_NB_CFG_CF8_EXT_ENABLE_BIT)) ) > + *addr |= CF8_ADDR_HI(cf8); > + } > + } > + else > + { > + *type = (p->type == IOREQ_TYPE_PIO) ? > + XEN_DMOP_IO_RANGE_PORT : XEN_DMOP_IO_RANGE_MEMORY; > + *addr = p->addr; > + } > + > + return 0; > +} > + > +static inline int hvm_access_cf8( > + int dir, unsigned int port, unsigned int bytes, uint32_t *val) > +{ > + struct domain *d = current->domain; > + > + if ( dir == IOREQ_WRITE && bytes == 4 ) > + d->arch.hvm.pci_cf8 = *val; > + > + /* We always need to fall through to the catch all emulator */ > + return X86EMUL_UNHANDLEABLE; > +} > + > +static inline void arch_hvm_ioreq_init(struct domain *d) > +{ > + register_portio_handler(d, 0xcf8, 4, hvm_access_cf8); > +} > + > +static inline bool arch_hvm_ioreq_destroy(struct domain *d) > +{ > + if ( !relocate_portio_handler(d, 0xcf8, 0xcf8, 4) ) > + return false; > + > + return true; > +} > + > bool hvm_io_pending(struct vcpu *v); > bool handle_hvm_io_completion(struct vcpu *v); > bool is_ioreq_server_page(struct domain *d, const struct page_info *page); > @@ -38,8 +197,6 @@ int hvm_map_io_range_to_ioreq_server(struct domain *d, > ioservid_t id, > int hvm_unmap_io_range_from_ioreq_server(struct domain *d, ioservid_t id, > uint32_t type, uint64_t start, > uint64_t end); > -int hvm_map_mem_type_to_ioreq_server(struct domain *d, ioservid_t id, > - uint32_t type, uint32_t flags); > int hvm_set_ioreq_server_state(struct domain *d, ioservid_t id, > bool enabled); > > @@ -55,6 +212,10 @@ unsigned int hvm_broadcast_ioreq(ioreq_t *p, bool > buffered); > > void hvm_ioreq_init(struct domain *d); > > +#define IOREQ_STATUS_HANDLED X86EMUL_OKAY > +#define IOREQ_STATUS_UNHANDLED X86EMUL_UNHANDLEABLE > +#define IOREQ_STATUS_RETRY X86EMUL_RETRY > + > #endif /* __ASM_X86_HVM_IOREQ_H__ */ > > /* > -- > 2.7.4
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |