| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU SPARC iommu emulation | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |  * Copyright (c) 2003-2005 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-11-17 17:14:51 +00:00
										 |  |  | #include "hw.h"
 | 
					
						
							|  |  |  | #include "sun4m.h"
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* debug iommu */ | 
					
						
							|  |  |  | //#define DEBUG_IOMMU
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  | #ifdef DEBUG_IOMMU
 | 
					
						
							|  |  |  | #define DPRINTF(fmt, args...) \
 | 
					
						
							|  |  |  | do { printf("IOMMU: " fmt , ##args); } while (0) | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define DPRINTF(fmt, args...)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  | #define IOMMU_NREGS (3*4096/4)
 | 
					
						
							|  |  |  | #define IOMMU_CTRL          (0x0000 >> 2)
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | #define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
 | 
					
						
							|  |  |  | #define IOMMU_CTRL_VERS     0x0f000000 /* Version */
 | 
					
						
							|  |  |  | #define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
 | 
					
						
							|  |  |  | #define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
 | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  | #define IOMMU_CTRL_MASK     0x0000001d
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IOMMU_BASE          (0x0004 >> 2)
 | 
					
						
							|  |  |  | #define IOMMU_BASE_MASK     0x07fffc00
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IOMMU_TLBFLUSH      (0x0014 >> 2)
 | 
					
						
							|  |  |  | #define IOMMU_TLBFLUSH_MASK 0xffffffff
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IOMMU_PGFLUSH       (0x0018 >> 2)
 | 
					
						
							|  |  |  | #define IOMMU_PGFLUSH_MASK  0xffffffff
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | #define IOMMU_AFSR          (0x1000 >> 2)
 | 
					
						
							|  |  |  | #define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  | #define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after
 | 
					
						
							|  |  |  |                                           transaction */ | 
					
						
							|  |  |  | #define IOMMU_AFSR_TO       0x20000000 /* Write access took more than
 | 
					
						
							|  |  |  |                                           12.8 us. */ | 
					
						
							|  |  |  | #define IOMMU_AFSR_BE       0x10000000 /* Write access received error
 | 
					
						
							|  |  |  |                                           acknowledge */ | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | #define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
 | 
					
						
							|  |  |  | #define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  | #define IOMMU_AFSR_RESV     0x00800000 /* Reserved, forced to 0x8 by
 | 
					
						
							|  |  |  |                                           hardware */ | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | #define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
 | 
					
						
							|  |  |  | #define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
 | 
					
						
							|  |  |  | #define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:24 +00:00
										 |  |  | #define IOMMU_AFSR_MASK     0xff0fffff
 | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define IOMMU_AFAR          (0x1004 >> 2)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  | #define IOMMU_SBCFG0        (0x1010 >> 2) /* SBUS configration per-slot */
 | 
					
						
							|  |  |  | #define IOMMU_SBCFG1        (0x1014 >> 2) /* SBUS configration per-slot */
 | 
					
						
							|  |  |  | #define IOMMU_SBCFG2        (0x1018 >> 2) /* SBUS configration per-slot */
 | 
					
						
							|  |  |  | #define IOMMU_SBCFG3        (0x101c >> 2) /* SBUS configration per-slot */
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  | #define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when
 | 
					
						
							|  |  |  |                                           bypass enabled */ | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  | #define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
 | 
					
						
							|  |  |  | #define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
 | 
					
						
							|  |  |  | #define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
 | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |                                           produced by this device as pure | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |                                           physical. */ | 
					
						
							|  |  |  | #define IOMMU_SBCFG_MASK    0x00010003
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IOMMU_ARBEN         (0x2000 >> 2) /* SBUS arbitration enable */
 | 
					
						
							|  |  |  | #define IOMMU_ARBEN_MASK    0x001f0000
 | 
					
						
							|  |  |  | #define IOMMU_MID           0x00000008
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* The format of an iopte in the page tables */ | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:25 +00:00
										 |  |  | #define IOPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  | #define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or
 | 
					
						
							|  |  |  |                                           Viking/MXCC) */ | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | #define IOPTE_WRITE         0x00000004 /* Writeable */
 | 
					
						
							|  |  |  | #define IOPTE_VALID         0x00000002 /* IOPTE is valid */
 | 
					
						
							|  |  |  | #define IOPTE_WAZ           0x00000001 /* Write as zeros */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PAGE_SHIFT      12
 | 
					
						
							|  |  |  | #define PAGE_SIZE       (1 << PAGE_SHIFT)
 | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  | #define PAGE_MASK       (PAGE_SIZE - 1)
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct IOMMUState { | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     target_phys_addr_t addr; | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     uint32_t regs[IOMMU_NREGS]; | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     target_phys_addr_t iostart; | 
					
						
							| 
									
										
										
										
											2007-11-17 09:04:09 +00:00
										 |  |  |     uint32_t version; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     qemu_irq irq; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | } IOMMUState; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-01 17:06:38 +00:00
										 |  |  | static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr) | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s = opaque; | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     target_phys_addr_t saddr; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     uint32_t ret; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-10-04 21:23:09 +00:00
										 |  |  |     saddr = (addr - s->addr) >> 2; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |     switch (saddr) { | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |         ret = s->regs[saddr]; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case IOMMU_AFAR: | 
					
						
							|  |  |  |     case IOMMU_AFSR: | 
					
						
							|  |  |  |         ret = s->regs[saddr]; | 
					
						
							|  |  |  |         qemu_irq_lower(s->irq); | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     DPRINTF("read reg[%d] = %x\n", (int)saddr, ret); | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-01 17:06:38 +00:00
										 |  |  | static void iommu_mem_writel(void *opaque, target_phys_addr_t addr, | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  |                              uint32_t val) | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s = opaque; | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     target_phys_addr_t saddr; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-10-04 21:23:09 +00:00
										 |  |  |     saddr = (addr - s->addr) >> 2; | 
					
						
							| 
									
										
										
										
											2007-08-11 07:49:55 +00:00
										 |  |  |     DPRINTF("write reg[%d] = %x\n", (int)saddr, val); | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |     switch (saddr) { | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_CTRL: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         switch (val & IOMMU_CTRL_RNGE) { | 
					
						
							|  |  |  |         case IOMMU_RNGE_16MB: | 
					
						
							|  |  |  |             s->iostart = 0xffffffffff000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_32MB: | 
					
						
							|  |  |  |             s->iostart = 0xfffffffffe000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_64MB: | 
					
						
							|  |  |  |             s->iostart = 0xfffffffffc000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_128MB: | 
					
						
							|  |  |  |             s->iostart = 0xfffffffff8000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_256MB: | 
					
						
							|  |  |  |             s->iostart = 0xfffffffff0000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_512MB: | 
					
						
							|  |  |  |             s->iostart = 0xffffffffe0000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case IOMMU_RNGE_1GB: | 
					
						
							|  |  |  |             s->iostart = 0xffffffffc0000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |         case IOMMU_RNGE_2GB: | 
					
						
							|  |  |  |             s->iostart = 0xffffffff80000000ULL; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); | 
					
						
							| 
									
										
										
										
											2007-11-17 09:04:09 +00:00
										 |  |  |         s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version); | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_BASE: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         s->regs[saddr] = val & IOMMU_BASE_MASK; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_TLBFLUSH: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         DPRINTF("tlb flush %x\n", val); | 
					
						
							|  |  |  |         s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_PGFLUSH: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         DPRINTF("page flush %x\n", val); | 
					
						
							|  |  |  |         s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     case IOMMU_AFAR: | 
					
						
							|  |  |  |         s->regs[saddr] = val; | 
					
						
							|  |  |  |         qemu_irq_lower(s->irq); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:24 +00:00
										 |  |  |     case IOMMU_AFSR: | 
					
						
							|  |  |  |         s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |         qemu_irq_lower(s->irq); | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:24 +00:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_SBCFG0: | 
					
						
							|  |  |  |     case IOMMU_SBCFG1: | 
					
						
							|  |  |  |     case IOMMU_SBCFG2: | 
					
						
							|  |  |  |     case IOMMU_SBCFG3: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         s->regs[saddr] = val & IOMMU_SBCFG_MASK; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2005-10-30 17:24:19 +00:00
										 |  |  |     case IOMMU_ARBEN: | 
					
						
							|  |  |  |         // XXX implement SBus probing: fault when reading unmapped
 | 
					
						
							|  |  |  |         // addresses, fault cause and address stored to MMU/IOMMU
 | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |     default: | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         s->regs[saddr] = val; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static CPUReadMemoryFunc *iommu_mem_read[3] = { | 
					
						
							| 
									
										
										
										
											2008-01-01 17:06:38 +00:00
										 |  |  |     NULL, | 
					
						
							|  |  |  |     NULL, | 
					
						
							|  |  |  |     iommu_mem_readl, | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static CPUWriteMemoryFunc *iommu_mem_write[3] = { | 
					
						
							| 
									
										
										
										
											2008-01-01 17:06:38 +00:00
										 |  |  |     NULL, | 
					
						
							|  |  |  |     NULL, | 
					
						
							|  |  |  |     iommu_mem_writel, | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  | static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-09-20 16:01:51 +00:00
										 |  |  |     uint32_t ret; | 
					
						
							|  |  |  |     target_phys_addr_t iopte; | 
					
						
							| 
									
										
										
										
											2007-08-11 07:49:55 +00:00
										 |  |  | #ifdef DEBUG_IOMMU
 | 
					
						
							|  |  |  |     target_phys_addr_t pa = addr; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-11 07:49:55 +00:00
										 |  |  |     iopte = s->regs[IOMMU_BASE] << 4; | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     addr &= ~s->iostart; | 
					
						
							|  |  |  |     iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; | 
					
						
							| 
									
										
										
										
											2007-09-20 16:01:51 +00:00
										 |  |  |     cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4); | 
					
						
							| 
									
										
										
										
											2007-09-22 12:09:09 +00:00
										 |  |  |     tswap32s(&ret); | 
					
						
							| 
									
										
										
										
											2007-09-20 16:01:51 +00:00
										 |  |  |     DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx | 
					
						
							|  |  |  |             ", *pte = %x\n", pa, iopte, ret); | 
					
						
							| 
									
										
										
										
											2007-08-11 07:49:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  | static target_phys_addr_t iommu_translate_pa(IOMMUState *s, | 
					
						
							|  |  |  |                                              target_phys_addr_t addr, | 
					
						
							|  |  |  |                                              uint32_t pte) | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     uint32_t tmppte; | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     target_phys_addr_t pa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tmppte = pte; | 
					
						
							|  |  |  |     pa = ((pte & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); | 
					
						
							|  |  |  |     DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx | 
					
						
							|  |  |  |             " (iopte = %x)\n", addr, pa, tmppte); | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     return pa; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  | static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, | 
					
						
							|  |  |  |                            int is_write) | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     DPRINTF("bad addr " TARGET_FMT_plx "\n", addr); | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  |     s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV | | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  |         IOMMU_AFSR_FAV; | 
					
						
							|  |  |  |     if (!is_write) | 
					
						
							|  |  |  |         s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD; | 
					
						
							|  |  |  |     s->regs[IOMMU_AFAR] = addr; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     qemu_irq_raise(s->irq); | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-09-03 16:09:07 +00:00
										 |  |  | void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, | 
					
						
							|  |  |  |                            uint8_t *buf, int len, int is_write) | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     int l; | 
					
						
							|  |  |  |     uint32_t flags; | 
					
						
							|  |  |  |     target_phys_addr_t page, phys_addr; | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     while (len > 0) { | 
					
						
							|  |  |  |         page = addr & TARGET_PAGE_MASK; | 
					
						
							|  |  |  |         l = (page + TARGET_PAGE_SIZE) - addr; | 
					
						
							|  |  |  |         if (l > len) | 
					
						
							|  |  |  |             l = len; | 
					
						
							|  |  |  |         flags = iommu_page_get_flags(opaque, page); | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  |         if (!(flags & IOPTE_VALID)) { | 
					
						
							|  |  |  |             iommu_bad_addr(opaque, page, is_write); | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  |         phys_addr = iommu_translate_pa(opaque, addr, flags); | 
					
						
							|  |  |  |         if (is_write) { | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  |             if (!(flags & IOPTE_WRITE)) { | 
					
						
							|  |  |  |                 iommu_bad_addr(opaque, page, is_write); | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2007-08-11 07:52:09 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2006-08-29 04:52:16 +00:00
										 |  |  |             cpu_physical_memory_write(phys_addr, buf, len); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             cpu_physical_memory_read(phys_addr, buf, len); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         len -= l; | 
					
						
							|  |  |  |         buf += l; | 
					
						
							|  |  |  |         addr += l; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  | static void iommu_save(QEMUFile *f, void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s = opaque; | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2007-09-17 08:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     for (i = 0; i < IOMMU_NREGS; i++) | 
					
						
							| 
									
										
										
										
											2007-10-06 11:28:21 +00:00
										 |  |  |         qemu_put_be32s(f, &s->regs[i]); | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     qemu_put_be64s(f, &s->iostart); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int iommu_load(QEMUFile *f, void *opaque, int version_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s = opaque; | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2007-09-17 08:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     if (version_id != 2) | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |         return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     for (i = 0; i < IOMMU_NREGS; i++) | 
					
						
							| 
									
										
										
										
											2007-07-03 09:55:03 +00:00
										 |  |  |         qemu_get_be32s(f, &s->regs[i]); | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     qemu_get_be64s(f, &s->iostart); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void iommu_reset(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     memset(s->regs, 0, IOMMU_NREGS * 4); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |     s->iostart = 0; | 
					
						
							| 
									
										
										
										
											2007-11-17 09:04:09 +00:00
										 |  |  |     s->regs[IOMMU_CTRL] = s->version; | 
					
						
							|  |  |  |     s->regs[IOMMU_ARBEN] = IOMMU_MID; | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  |     s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     qemu_irq_lower(s->irq); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  | void *iommu_init(target_phys_addr_t addr, uint32_t version, qemu_irq irq) | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     IOMMUState *s; | 
					
						
							| 
									
										
										
										
											2004-10-04 21:23:09 +00:00
										 |  |  |     int iommu_io_memory; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     s = qemu_mallocz(sizeof(IOMMUState)); | 
					
						
							|  |  |  |     if (!s) | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-10-04 21:23:09 +00:00
										 |  |  |     s->addr = addr; | 
					
						
							| 
									
										
										
										
											2007-11-17 09:04:09 +00:00
										 |  |  |     s->version = version; | 
					
						
							| 
									
										
										
										
											2008-01-01 17:04:45 +00:00
										 |  |  |     s->irq = irq; | 
					
						
							| 
									
										
										
										
											2004-10-04 21:23:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-01 14:51:23 +00:00
										 |  |  |     iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, | 
					
						
							|  |  |  |                                              iommu_mem_write, s); | 
					
						
							| 
									
										
										
										
											2005-04-06 20:47:48 +00:00
										 |  |  |     cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); | 
					
						
							| 
									
										
										
										
											2007-09-17 08:09:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-19 12:58:30 +00:00
										 |  |  |     register_savevm("iommu", addr, 2, iommu_save, iommu_load, s); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |     qemu_register_reset(iommu_reset, s); | 
					
						
							| 
									
										
										
										
											2007-11-17 09:04:09 +00:00
										 |  |  |     iommu_reset(s); | 
					
						
							| 
									
										
										
										
											2004-12-19 23:18:01 +00:00
										 |  |  |     return s; | 
					
						
							| 
									
										
										
										
											2004-09-30 22:13:50 +00:00
										 |  |  | } |