From patchwork Mon Mar 20 13:00:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yongbok Kim X-Patchwork-Id: 9634117 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7576B602D6 for ; Mon, 20 Mar 2017 13:08:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5FEA128449 for ; Mon, 20 Mar 2017 13:08:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5498A28451; Mon, 20 Mar 2017 13:08:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 7AF5228449 for ; Mon, 20 Mar 2017 13:08:20 +0000 (UTC) Received: from localhost ([::1]:32912 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cpx2p-000138-Ik for patchwork-qemu-devel@patchwork.kernel.org; Mon, 20 Mar 2017 09:08:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45706) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cpwvX-0003vw-7h for qemu-devel@nongnu.org; Mon, 20 Mar 2017 09:00:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cpwvV-00072G-Dy for qemu-devel@nongnu.org; Mon, 20 Mar 2017 09:00:47 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:52026) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cpwvV-00071u-5F for qemu-devel@nongnu.org; Mon, 20 Mar 2017 09:00:45 -0400 Received: from hhmail02.hh.imgtec.org (unknown [10.100.10.20]) by Forcepoint Email with ESMTPS id 749FF6AF80DC7; Mon, 20 Mar 2017 13:00:39 +0000 (GMT) Received: from localhost.localdomain (192.168.161.53) by hhmail02.hh.imgtec.org (10.100.10.21) with Microsoft SMTP Server (TLS) id 14.3.294.0; Mon, 20 Mar 2017 13:00:42 +0000 From: Yongbok Kim To: QEMU Developers Date: Mon, 20 Mar 2017 13:00:24 +0000 Message-ID: <1490014826-4472-9-git-send-email-yongbok.kim@imgtec.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1490014826-4472-1-git-send-email-yongbok.kim@imgtec.com> References: <1490014826-4472-1-git-send-email-yongbok.kim@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [192.168.161.53] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-Received-From: 195.59.15.196 Subject: [Qemu-devel] [PULL for v2.9 08/10] dma/rc4030: translate memory accesses only when they occur X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Hervé Poussineau This simplifies the code a lot, and this fixes big memory leaks introduced in a3d586f704609a45b6037534cb2f34da5dfd8895 Windows NT is now able to boot without using gigabytes of ram on the host. Signed-off-by: Hervé Poussineau Reviewed-by: Yongbok Kim Signed-off-by: Yongbok Kim --- hw/dma/rc4030.c | 158 +++++++++++++------------------------------------------- 1 file changed, 36 insertions(+), 122 deletions(-) diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 41fc043..5f10b9d 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -34,8 +34,6 @@ /********************************************************/ /* rc4030 emulation */ -#define MAX_TL_ENTRIES 512 - typedef struct dma_pagetable_entry { int32_t frame; int32_t owner; @@ -91,14 +89,8 @@ typedef struct rc4030State qemu_irq timer_irq; qemu_irq jazz_bus_irq; - /* biggest translation table */ - MemoryRegion dma_tt; - /* translation table memory region alias, added to system RAM */ - MemoryRegion dma_tt_alias; /* whole DMA memory region, root of DMA address space */ MemoryRegion dma_mr; - /* translation table entry aliases, added to DMA memory region */ - MemoryRegion dma_mrs[MAX_TL_ENTRIES]; AddressSpace dma_as; MemoryRegion iomem_chipset; @@ -256,96 +248,6 @@ static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size) return val; } -static void rc4030_dma_as_update_one(rc4030State *s, int index, uint32_t frame) -{ - if (index < MAX_TL_ENTRIES) { - memory_region_set_enabled(&s->dma_mrs[index], false); - } - - if (!frame) { - return; - } - - if (index >= MAX_TL_ENTRIES) { - qemu_log_mask(LOG_UNIMP, - "rc4030: trying to use too high " - "translation table entry %d (max allowed=%d)", - index, MAX_TL_ENTRIES); - return; - } - memory_region_set_alias_offset(&s->dma_mrs[index], frame); - memory_region_set_enabled(&s->dma_mrs[index], true); -} - -static void rc4030_dma_tt_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - rc4030State *s = opaque; - - /* write memory */ - memcpy(memory_region_get_ram_ptr(&s->dma_tt) + addr, &data, size); - - /* update dma address space (only if frame field has been written) */ - if (addr % sizeof(dma_pagetable_entry) == 0) { - int index = addr / sizeof(dma_pagetable_entry); - memory_region_transaction_begin(); - rc4030_dma_as_update_one(s, index, (uint32_t)data); - memory_region_transaction_commit(); - } -} - -static const MemoryRegionOps rc4030_dma_tt_ops = { - .write = rc4030_dma_tt_write, - .impl.min_access_size = 4, - .impl.max_access_size = 4, -}; - -static void rc4030_dma_tt_update(rc4030State *s, uint32_t new_tl_base, - uint32_t new_tl_limit) -{ - int entries, i; - dma_pagetable_entry *dma_tl_contents; - - if (s->dma_tl_limit) { - /* write old dma tl table to physical memory */ - memory_region_del_subregion(get_system_memory(), &s->dma_tt_alias); - cpu_physical_memory_write(s->dma_tl_limit & 0x7fffffff, - memory_region_get_ram_ptr(&s->dma_tt), - memory_region_size(&s->dma_tt_alias)); - } - object_unparent(OBJECT(&s->dma_tt_alias)); - - s->dma_tl_base = new_tl_base; - s->dma_tl_limit = new_tl_limit; - new_tl_base &= 0x7fffffff; - - if (s->dma_tl_limit) { - uint64_t dma_tt_size; - if (s->dma_tl_limit <= memory_region_size(&s->dma_tt)) { - dma_tt_size = s->dma_tl_limit; - } else { - dma_tt_size = memory_region_size(&s->dma_tt); - } - memory_region_init_alias(&s->dma_tt_alias, OBJECT(s), - "dma-table-alias", - &s->dma_tt, 0, dma_tt_size); - dma_tl_contents = memory_region_get_ram_ptr(&s->dma_tt); - cpu_physical_memory_read(new_tl_base, dma_tl_contents, dma_tt_size); - - memory_region_transaction_begin(); - entries = dma_tt_size / sizeof(dma_pagetable_entry); - for (i = 0; i < entries; i++) { - rc4030_dma_as_update_one(s, i, dma_tl_contents[i].frame); - } - memory_region_add_subregion(get_system_memory(), new_tl_base, - &s->dma_tt_alias); - memory_region_transaction_commit(); - } else { - memory_region_init(&s->dma_tt_alias, OBJECT(s), - "dma-table-alias", 0); - } -} - static void rc4030_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { @@ -362,11 +264,11 @@ static void rc4030_write(void *opaque, hwaddr addr, uint64_t data, break; /* DMA transl. table base */ case 0x0018: - rc4030_dma_tt_update(s, val, s->dma_tl_limit); + s->dma_tl_base = val; break; /* DMA transl. table limit */ case 0x0020: - rc4030_dma_tt_update(s, s->dma_tl_base, val); + s->dma_tl_limit = val; break; /* DMA transl. table invalidated */ case 0x0028: @@ -586,6 +488,38 @@ static const MemoryRegionOps jazzio_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static IOMMUTLBEntry rc4030_dma_translate(MemoryRegion *iommu, hwaddr addr, + bool is_write) +{ + rc4030State *s = container_of(iommu, rc4030State, dma_mr); + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = addr & ~(DMA_PAGESIZE - 1), + .translated_addr = 0, + .addr_mask = DMA_PAGESIZE - 1, + .perm = IOMMU_NONE, + }; + uint64_t i, entry_address; + dma_pagetable_entry entry; + + i = addr / DMA_PAGESIZE; + if (i < s->dma_tl_limit / sizeof(entry)) { + entry_address = (s->dma_tl_base & 0x7fffffff) + i * sizeof(entry); + if (address_space_read(ret.target_as, entry_address, + MEMTXATTRS_UNSPECIFIED, (unsigned char *)&entry, + sizeof(entry)) == MEMTX_OK) { + ret.translated_addr = entry.frame & ~(DMA_PAGESIZE - 1); + ret.perm = IOMMU_RW; + } + } + + return ret; +} + +static const MemoryRegionIOMMUOps rc4030_dma_ops = { + .translate = rc4030_dma_translate, +}; + static void rc4030_reset(DeviceState *dev) { rc4030State *s = RC4030(dev); @@ -596,7 +530,6 @@ static void rc4030_reset(DeviceState *dev) s->invalid_address_register = 0; memset(s->dma_regs, 0, sizeof(s->dma_regs)); - rc4030_dma_tt_update(s, 0, 0); s->remote_failed_address = s->memory_failed_address = 0; s->cache_maint = 0; @@ -735,7 +668,6 @@ static void rc4030_realize(DeviceState *dev, Error **errp) { rc4030State *s = RC4030(dev); Object *o = OBJECT(dev); - int i; s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, rc4030_periodic_timer, s); @@ -745,37 +677,19 @@ static void rc4030_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->iomem_jazzio, NULL, &jazzio_ops, s, "rc4030.jazzio", 0x00001000); - memory_region_init_rom_device(&s->dma_tt, o, - &rc4030_dma_tt_ops, s, "dma-table", - MAX_TL_ENTRIES * sizeof(dma_pagetable_entry), - NULL); - memory_region_init(&s->dma_tt_alias, o, "dma-table-alias", 0); - memory_region_init(&s->dma_mr, o, "dma", INT32_MAX); - for (i = 0; i < MAX_TL_ENTRIES; ++i) { - memory_region_init_alias(&s->dma_mrs[i], o, "dma-alias", - get_system_memory(), 0, DMA_PAGESIZE); - memory_region_set_enabled(&s->dma_mrs[i], false); - memory_region_add_subregion(&s->dma_mr, i * DMA_PAGESIZE, - &s->dma_mrs[i]); - } + memory_region_init_iommu(&s->dma_mr, o, &rc4030_dma_ops, + "rc4030.dma", UINT32_MAX); address_space_init(&s->dma_as, &s->dma_mr, "rc4030-dma"); } static void rc4030_unrealize(DeviceState *dev, Error **errp) { rc4030State *s = RC4030(dev); - int i; timer_free(s->periodic_timer); address_space_destroy(&s->dma_as); - object_unparent(OBJECT(&s->dma_tt)); - object_unparent(OBJECT(&s->dma_tt_alias)); object_unparent(OBJECT(&s->dma_mr)); - for (i = 0; i < MAX_TL_ENTRIES; ++i) { - memory_region_del_subregion(&s->dma_mr, &s->dma_mrs[i]); - object_unparent(OBJECT(&s->dma_mrs[i])); - } } static void rc4030_class_init(ObjectClass *klass, void *class_data)