From: Avi Kivity <avi@redhat.com>
To: qemu-devel@nongnu.org, Blue Swirl <blauwirbel@gmail.com>,
Anthony Liguori <anthony@codemonkey.ws>,
"Michael S. Tsirkin" <mst@redhat.com>,
Alex Williamson <alex.williamson@redhat.com>,
liu ping fan <qemulist@gmail.com>,
Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [RFC v1 3/7] memory: iommu support
Date: Thu, 11 Oct 2012 16:29:43 +0200 [thread overview]
Message-ID: <5076D7D7.40906@redhat.com> (raw)
In-Reply-To: <1349962023-560-4-git-send-email-avi@redhat.com>
On 10/11/2012 03:26 PM, Avi Kivity wrote:
> Add a new memory region type that translates addresses it is given,
> then forwards them to a target address space. This is similar to
> an alias, except that the mapping is more flexible than a linear
> translation and trucation, and also less efficient since the
> translation happens at runtime.
>
> The implementation uses an AddressSpace mapping the target region to
> avoid hierarchical dispatch all the way to the resolved region; only
> iommu regions are looked up dynamically.
>
>
> typedef struct {
> void *buffer;
> + AddressSpace *as;
> target_phys_addr_t addr;
> target_phys_addr_t len;
> } BounceBuffer;
> @@ -3563,23 +3564,42 @@ void *address_space_map(AddressSpace *as,
> ram_addr_t raddr = RAM_ADDR_MAX;
> ram_addr_t rlen;
> void *ret;
> + IOMMUTLBEntry iotlb;
> + target_phys_addr_t xlat;
> + AddressSpace *as_xlat;
>
> while (len > 0) {
> + xlat = addr;
> + as_xlat = as;
> page = addr & TARGET_PAGE_MASK;
> l = (page + TARGET_PAGE_SIZE) - addr;
> if (l > len)
> l = len;
> section = phys_page_find(d, page >> TARGET_PAGE_BITS);
>
> + while (section->mr->iommu_ops) {
> + iotlb = section->mr->iommu_ops->translate(section->mr, addr, is_write);
should be using xlat here, or this fails the second time around.
> + if (iotlb.valid) {
> + xlat = ((iotlb.translated_addr & ~iotlb.addr_mask)
> + | (addr & iotlb.addr_mask));
> + as_xlat = section->mr->iommu_target_as;
> + l = (MIN(xlat + l - 1, xlat | iotlb.addr_mask) - xlat) + 1;
> + section = phys_page_find(as_xlat->dispatch, xlat >> TARGET_PAGE_BITS);
> + } else {
> + section = &phys_sections[phys_section_unassigned];
> + }
> + }
> +
> if (!(memory_region_is_ram(section->mr) && !section->readonly)) {
> if (todo || bounce.buffer) {
> break;
> }
> bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, TARGET_PAGE_SIZE);
> - bounce.addr = addr;
> + bounce.addr = xlat;
> + bounce.as = as_xlat;
> bounce.len = l;
> if (!is_write) {
> - address_space_read(as, addr, bounce.buffer, l);
> + address_space_read(as_xlat, xlat, bounce.buffer, l);
> }
>
> *plen = l;
> @@ -3587,7 +3607,7 @@ void *address_space_map(AddressSpace *as,
> }
> if (!todo) {
> raddr = memory_region_get_ram_addr(section->mr)
> - + memory_region_section_addr(section, addr);
> + + memory_region_section_addr(section, xlat);
> }
>
> len -= l;
> @@ -3632,7 +3652,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, target_phys_addr_t len,
> return;
> }
> if (is_write) {
> - address_space_write(as, bounce.addr, bounce.buffer, access_len);
> + address_space_write(bounce.as, bounce.addr, bounce.buffer, access_len);
> }
> qemu_vfree(bounce.buffer);
> bounce.buffer = NULL;
> diff --git a/memory.c b/memory.c
> index 5df6177..1d92bb8 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -775,6 +775,12 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr)
> qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
> }
>
> +static void memory_region_destructor_iommu(MemoryRegion *mr)
> +{
> + address_space_destroy(mr->iommu_target_as);
> + g_free(mr->iommu_target_as);
> +}
> +
> static bool memory_region_wrong_endianness(MemoryRegion *mr)
> {
> #ifdef TARGET_WORDS_BIGENDIAN
> @@ -789,6 +795,7 @@ void memory_region_init(MemoryRegion *mr,
> uint64_t size)
> {
> mr->ops = NULL;
> + mr->iommu_ops = NULL;
> mr->parent = NULL;
> mr->size = int128_make64(size);
> if (size == UINT64_MAX) {
> @@ -980,6 +987,101 @@ void memory_region_init_rom_device(MemoryRegion *mr,
> mr->ram_addr = qemu_ram_alloc(size, mr);
> }
>
> +static void memory_region_iommu_rw(MemoryRegion *iommu, target_phys_addr_t addr,
> + uint8_t *buf, unsigned len, bool is_write)
> +{
> + IOMMUTLBEntry tlb;
> + unsigned clen;
> + target_phys_addr_t xlat;
> +
> + while (len) {
> + tlb = iommu->iommu_ops->translate(iommu, addr, is_write);
> + clen = (MIN(addr | tlb.addr_mask, addr + len - 1) - addr) + 1;
> + if (tlb.valid) {
> + xlat = (tlb.translated_addr & ~tlb.addr_mask) | (addr & tlb.addr_mask);
> + address_space_rw(iommu->iommu_target_as, xlat, buf, clen, is_write);
> + } else {
> + if (!is_write) {
> + memset(buf, 0xff, clen);
> + }
> + }
> + buf += clen;
> + addr += clen;
> + len -= clen;
> + }
> +}
> +
> +static uint64_t memory_region_iommu_read(void *opaque, target_phys_addr_t addr,
> + unsigned size)
> +{
> + MemoryRegion *iommu = opaque;
> + union {
> + uint8_t buf[8];
> + uint8_t u8;
> + uint16_t u16;
> + uint32_t u32;
> + uint64_t u64;
> + } ret;
> +
> + memory_region_iommu_rw(iommu, addr, ret.buf, size, false);
> + switch (size) {
> + case 1: return ret.u8;
> + case 2: return ret.u16;
> + case 4: return ret.u32;
> + case 8: return ret.u64;
> + default: abort();
> + }
> +}
> +
> +static void memory_region_iommu_write(void *opaque, target_phys_addr_t addr,
> + uint64_t data, unsigned size)
> +{
> + MemoryRegion *iommu = opaque;
> + union {
> + uint8_t buf[8];
> + uint8_t u8;
> + uint16_t u16;
> + uint32_t u32;
> + uint64_t u64;
> + } in;
> +
> + switch (size) {
> + case 1: in.u8 = data; break;
> + case 2: in.u16 = data; break;
> + case 4: in.u32 = data; break;
> + case 8: in.u64 = data; break;
> + default: abort();
> + }
> + memory_region_iommu_rw(iommu, addr, in.buf, size, true);
> +}
> +
> +static MemoryRegionOps memory_region_iommu_ops = {
> + .read = memory_region_iommu_read,
> + .write = memory_region_iommu_write,
> +#ifdef HOST_BIGENDIAN
> + .endianness = DEVICE_BIG_ENDIAN,
> +#else
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +#endif
> +};
> +
> +void memory_region_init_iommu(MemoryRegion *mr,
> + MemoryRegionIOMMUOps *ops,
> + MemoryRegion *target,
> + const char *name,
> + uint64_t size)
> +{
> + memory_region_init(mr, name, size);
> + mr->ops = &memory_region_iommu_ops;
> + mr->iommu_ops = ops,
> + mr->opaque = mr;
> + mr->terminates = true; /* then re-forwards */
> + mr->destructor = memory_region_destructor_iommu;
> + mr->iommu_target = target;
> + mr->iommu_target_as = g_new(AddressSpace, 1);
> + address_space_init(mr->iommu_target_as, target);
> +}
> +
> static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
> unsigned size)
> {
> @@ -1053,6 +1155,11 @@ bool memory_region_is_rom(MemoryRegion *mr)
> return mr->ram && mr->readonly;
> }
>
> +bool memory_region_is_iommu(MemoryRegion *mr)
> +{
> + return mr->iommu_ops;
> +}
> +
> void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
> {
> uint8_t mask = 1 << client;
> diff --git a/memory.h b/memory.h
> index 79393f1..299d584 100644
> --- a/memory.h
> +++ b/memory.h
> @@ -113,12 +113,29 @@ struct MemoryRegionOps {
> const MemoryRegionMmio old_mmio;
> };
>
> +typedef struct IOMMUTLBEntry IOMMUTLBEntry;
> +typedef struct MemoryRegionIOMMUOps MemoryRegionIOMMUOps;
> +
> +struct IOMMUTLBEntry {
> + target_phys_addr_t device_addr;
> + target_phys_addr_t translated_addr;
> + target_phys_addr_t addr_mask; /* 0xfff = 4k translation */
> + bool valid;
> +};
> +
> +struct MemoryRegionIOMMUOps {
> + /* Returns a TLB entry that contains a given address. */
> + IOMMUTLBEntry (*translate)(MemoryRegion *iommu, target_phys_addr_t addr,
> + bool is_write);
> +};
> +
> typedef struct CoalescedMemoryRange CoalescedMemoryRange;
> typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
>
> struct MemoryRegion {
> /* All fields are private - violators will be prosecuted */
> const MemoryRegionOps *ops;
> + const MemoryRegionIOMMUOps *iommu_ops;
> void *opaque;
> MemoryRegion *parent;
> Int128 size;
> @@ -145,6 +162,8 @@ struct MemoryRegion {
> uint8_t dirty_log_mask;
> unsigned ioeventfd_nb;
> MemoryRegionIoeventfd *ioeventfds;
> + MemoryRegion *iommu_target;
> + struct AddressSpace *iommu_target_as;
> };
>
> struct MemoryRegionPortio {
> @@ -334,6 +353,24 @@ void memory_region_init_rom_device(MemoryRegion *mr,
> void memory_region_init_reservation(MemoryRegion *mr,
> const char *name,
> uint64_t size);
> +
> +/**
> + * memory_region_init_iommu: Initialize a memory region that translates addresses
> + *
> + * An IOMMU region translates addresses and forwards accesses to a target memory region.
> + *
> + * @mr: the #MemoryRegion to be initialized
> + * @ops: a function that translates addresses into the @target region
> + * @target: a #MemoryRegion that will be used to satisfy accesses to translated addresses
> + * @name: used for debugging; not visible to the user or ABI
> + * @size: size of the region.
> + */
> +void memory_region_init_iommu(MemoryRegion *mr,
> + MemoryRegionIOMMUOps *ops,
> + MemoryRegion *target,
> + const char *name,
> + uint64_t size);
> +
> /**
> * memory_region_destroy: Destroy a memory region and reclaim all resources.
> *
> @@ -373,6 +410,15 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
> }
>
> /**
> + * memory_region_is_ram: check whether a memory region is an iommu
> + *
> + * Returns %true is a memory region is an iommu.
> + *
> + * @mr: the memory region being queried
> + */
> +bool memory_region_is_iommu(MemoryRegion *mr);
> +
> +/**
> * memory_region_name: get a memory region's name
> *
> * Returns the string that was used to initialize the memory region.
>
--
error compiling committee.c: too many arguments to function
next prev parent reply other threads:[~2012-10-11 14:54 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-11 13:26 [Qemu-devel] [RFC v1 0/7] IOMMU support Avi Kivity
2012-10-11 13:26 ` [Qemu-devel] [RFC v1 1/7] memory: fix address space initialization/destruction Avi Kivity
2012-10-11 13:31 ` Paolo Bonzini
2012-10-11 13:33 ` Avi Kivity
2012-10-13 9:14 ` Blue Swirl
2012-10-11 13:26 ` [Qemu-devel] [RFC v1 2/7] memory: limit sections in the radix tree to the actual address space size Avi Kivity
2012-10-11 13:26 ` [Qemu-devel] [RFC v1 3/7] memory: iommu support Avi Kivity
2012-10-11 13:42 ` Paolo Bonzini
2012-10-11 13:45 ` Avi Kivity
2012-10-11 13:54 ` Paolo Bonzini
2012-10-11 13:57 ` Avi Kivity
2012-10-12 2:51 ` Benjamin Herrenschmidt
2012-10-15 16:54 ` Avi Kivity
2012-10-12 2:45 ` Benjamin Herrenschmidt
2012-10-13 9:30 ` Blue Swirl
2012-10-13 11:37 ` Benjamin Herrenschmidt
2012-10-11 14:29 ` Avi Kivity [this message]
2012-10-11 13:27 ` [Qemu-devel] [RFC v1 4/7] pci: switch iommu to using the memory API Avi Kivity
2012-10-11 13:53 ` Paolo Bonzini
2012-10-11 13:56 ` Avi Kivity
2012-10-13 9:13 ` Blue Swirl
2012-10-15 10:31 ` Avi Kivity
2012-10-11 13:27 ` [Qemu-devel] [RFC v1 5/7] i440fx: add an iommu Avi Kivity
2012-10-11 13:27 ` [Qemu-devel] [RFC v1 6/7] vfio: abort if an emulated iommu is used Avi Kivity
2012-10-11 13:27 ` [Qemu-devel] [RFC v1 7/7] vhost: " Avi Kivity
2012-10-11 13:31 ` Michael S. Tsirkin
2012-10-11 13:34 ` Avi Kivity
2012-10-11 13:44 ` Michael S. Tsirkin
2012-10-11 13:44 ` Avi Kivity
2012-10-11 14:35 ` Michael S. Tsirkin
2012-10-11 14:35 ` Avi Kivity
2012-10-11 15:34 ` Michael S. Tsirkin
2012-10-11 15:48 ` Avi Kivity
2012-10-11 19:38 ` Alex Williamson
2012-10-15 10:24 ` Avi Kivity
2012-10-15 8:44 ` liu ping fan
2012-10-15 10:32 ` Avi Kivity
2012-10-12 2:36 ` [Qemu-devel] [RFC v1 0/7] IOMMU support Benjamin Herrenschmidt
2012-10-15 10:45 ` Avi Kivity
2012-10-15 19:52 ` Benjamin Herrenschmidt
2012-10-16 9:30 ` Avi Kivity
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5076D7D7.40906@redhat.com \
--to=avi@redhat.com \
--cc=alex.williamson@redhat.com \
--cc=anthony@codemonkey.ws \
--cc=blauwirbel@gmail.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemulist@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).