|
|
1.1 ! root 1: /* ! 2: * QEMU Sun4m iommu emulation ! 3: * ! 4: * Copyright (c) 2003-2005 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: ! 25: #include "sun4m.h" ! 26: #include "sysbus.h" ! 27: ! 28: /* debug iommu */ ! 29: //#define DEBUG_IOMMU ! 30: ! 31: #ifdef DEBUG_IOMMU ! 32: #define DPRINTF(fmt, ...) \ ! 33: do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) ! 34: #else ! 35: #define DPRINTF(fmt, ...) ! 36: #endif ! 37: ! 38: /* ! 39: * I/O MMU used by Sun4m systems ! 40: * ! 41: * Chipset docs: ! 42: * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01, ! 43: * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf ! 44: */ ! 45: ! 46: #define IOMMU_NREGS (4*4096/4) ! 47: #define IOMMU_CTRL (0x0000 >> 2) ! 48: #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ ! 49: #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ ! 50: #define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ ! 51: #define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ ! 52: #define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ ! 53: #define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */ ! 54: #define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */ ! 55: #define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */ ! 56: #define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */ ! 57: #define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ ! 58: #define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ ! 59: #define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ ! 60: #define IOMMU_CTRL_MASK 0x0000001d ! 61: ! 62: #define IOMMU_BASE (0x0004 >> 2) ! 63: #define IOMMU_BASE_MASK 0x07fffc00 ! 64: ! 65: #define IOMMU_TLBFLUSH (0x0014 >> 2) ! 66: #define IOMMU_TLBFLUSH_MASK 0xffffffff ! 67: ! 68: #define IOMMU_PGFLUSH (0x0018 >> 2) ! 69: #define IOMMU_PGFLUSH_MASK 0xffffffff ! 70: ! 71: #define IOMMU_AFSR (0x1000 >> 2) ! 72: #define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ ! 73: #define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after ! 74: transaction */ ! 75: #define IOMMU_AFSR_TO 0x20000000 /* Write access took more than ! 76: 12.8 us. */ ! 77: #define IOMMU_AFSR_BE 0x10000000 /* Write access received error ! 78: acknowledge */ ! 79: #define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ ! 80: #define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ ! 81: #define IOMMU_AFSR_RESV 0x00800000 /* Reserved, forced to 0x8 by ! 82: hardware */ ! 83: #define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ ! 84: #define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ ! 85: #define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ ! 86: #define IOMMU_AFSR_MASK 0xff0fffff ! 87: ! 88: #define IOMMU_AFAR (0x1004 >> 2) ! 89: ! 90: #define IOMMU_AER (0x1008 >> 2) /* Arbiter Enable Register */ ! 91: #define IOMMU_AER_EN_P0_ARB 0x00000001 /* MBus master 0x8 (Always 1) */ ! 92: #define IOMMU_AER_EN_P1_ARB 0x00000002 /* MBus master 0x9 */ ! 93: #define IOMMU_AER_EN_P2_ARB 0x00000004 /* MBus master 0xa */ ! 94: #define IOMMU_AER_EN_P3_ARB 0x00000008 /* MBus master 0xb */ ! 95: #define IOMMU_AER_EN_0 0x00010000 /* SBus slot 0 */ ! 96: #define IOMMU_AER_EN_1 0x00020000 /* SBus slot 1 */ ! 97: #define IOMMU_AER_EN_2 0x00040000 /* SBus slot 2 */ ! 98: #define IOMMU_AER_EN_3 0x00080000 /* SBus slot 3 */ ! 99: #define IOMMU_AER_EN_F 0x00100000 /* SBus on-board */ ! 100: #define IOMMU_AER_SBW 0x80000000 /* S-to-M asynchronous writes */ ! 101: #define IOMMU_AER_MASK 0x801f000f ! 102: ! 103: #define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */ ! 104: #define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */ ! 105: #define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */ ! 106: #define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */ ! 107: #define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when ! 108: bypass enabled */ ! 109: #define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ ! 110: #define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ ! 111: #define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses ! 112: produced by this device as pure ! 113: physical. */ ! 114: #define IOMMU_SBCFG_MASK 0x00010003 ! 115: ! 116: #define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */ ! 117: #define IOMMU_ARBEN_MASK 0x001f0000 ! 118: #define IOMMU_MID 0x00000008 ! 119: ! 120: #define IOMMU_MASK_ID (0x3018 >> 2) /* Mask ID */ ! 121: #define IOMMU_MASK_ID_MASK 0x00ffffff ! 122: ! 123: #define IOMMU_MSII_MASK 0x26000000 /* microSPARC II mask number */ ! 124: #define IOMMU_TS_MASK 0x23000000 /* turboSPARC mask number */ ! 125: ! 126: /* The format of an iopte in the page tables */ ! 127: #define IOPTE_PAGE 0xffffff00 /* Physical page number (PA[35:12]) */ ! 128: #define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or ! 129: Viking/MXCC) */ ! 130: #define IOPTE_WRITE 0x00000004 /* Writeable */ ! 131: #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ ! 132: #define IOPTE_WAZ 0x00000001 /* Write as zeros */ ! 133: ! 134: #define IOMMU_PAGE_SHIFT 12 ! 135: #define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT) ! 136: #define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1) ! 137: ! 138: typedef struct IOMMUState { ! 139: SysBusDevice busdev; ! 140: uint32_t regs[IOMMU_NREGS]; ! 141: target_phys_addr_t iostart; ! 142: uint32_t version; ! 143: qemu_irq irq; ! 144: } IOMMUState; ! 145: ! 146: static uint32_t iommu_mem_readl(void *opaque, target_phys_addr_t addr) ! 147: { ! 148: IOMMUState *s = opaque; ! 149: target_phys_addr_t saddr; ! 150: uint32_t ret; ! 151: ! 152: saddr = addr >> 2; ! 153: switch (saddr) { ! 154: default: ! 155: ret = s->regs[saddr]; ! 156: break; ! 157: case IOMMU_AFAR: ! 158: case IOMMU_AFSR: ! 159: ret = s->regs[saddr]; ! 160: qemu_irq_lower(s->irq); ! 161: break; ! 162: } ! 163: DPRINTF("read reg[%d] = %x\n", (int)saddr, ret); ! 164: return ret; ! 165: } ! 166: ! 167: static void iommu_mem_writel(void *opaque, target_phys_addr_t addr, ! 168: uint32_t val) ! 169: { ! 170: IOMMUState *s = opaque; ! 171: target_phys_addr_t saddr; ! 172: ! 173: saddr = addr >> 2; ! 174: DPRINTF("write reg[%d] = %x\n", (int)saddr, val); ! 175: switch (saddr) { ! 176: case IOMMU_CTRL: ! 177: switch (val & IOMMU_CTRL_RNGE) { ! 178: case IOMMU_RNGE_16MB: ! 179: s->iostart = 0xffffffffff000000ULL; ! 180: break; ! 181: case IOMMU_RNGE_32MB: ! 182: s->iostart = 0xfffffffffe000000ULL; ! 183: break; ! 184: case IOMMU_RNGE_64MB: ! 185: s->iostart = 0xfffffffffc000000ULL; ! 186: break; ! 187: case IOMMU_RNGE_128MB: ! 188: s->iostart = 0xfffffffff8000000ULL; ! 189: break; ! 190: case IOMMU_RNGE_256MB: ! 191: s->iostart = 0xfffffffff0000000ULL; ! 192: break; ! 193: case IOMMU_RNGE_512MB: ! 194: s->iostart = 0xffffffffe0000000ULL; ! 195: break; ! 196: case IOMMU_RNGE_1GB: ! 197: s->iostart = 0xffffffffc0000000ULL; ! 198: break; ! 199: default: ! 200: case IOMMU_RNGE_2GB: ! 201: s->iostart = 0xffffffff80000000ULL; ! 202: break; ! 203: } ! 204: DPRINTF("iostart = " TARGET_FMT_plx "\n", s->iostart); ! 205: s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version); ! 206: break; ! 207: case IOMMU_BASE: ! 208: s->regs[saddr] = val & IOMMU_BASE_MASK; ! 209: break; ! 210: case IOMMU_TLBFLUSH: ! 211: DPRINTF("tlb flush %x\n", val); ! 212: s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; ! 213: break; ! 214: case IOMMU_PGFLUSH: ! 215: DPRINTF("page flush %x\n", val); ! 216: s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; ! 217: break; ! 218: case IOMMU_AFAR: ! 219: s->regs[saddr] = val; ! 220: qemu_irq_lower(s->irq); ! 221: break; ! 222: case IOMMU_AER: ! 223: s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB; ! 224: break; ! 225: case IOMMU_AFSR: ! 226: s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV; ! 227: qemu_irq_lower(s->irq); ! 228: break; ! 229: case IOMMU_SBCFG0: ! 230: case IOMMU_SBCFG1: ! 231: case IOMMU_SBCFG2: ! 232: case IOMMU_SBCFG3: ! 233: s->regs[saddr] = val & IOMMU_SBCFG_MASK; ! 234: break; ! 235: case IOMMU_ARBEN: ! 236: // XXX implement SBus probing: fault when reading unmapped ! 237: // addresses, fault cause and address stored to MMU/IOMMU ! 238: s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; ! 239: break; ! 240: case IOMMU_MASK_ID: ! 241: s->regs[saddr] |= val & IOMMU_MASK_ID_MASK; ! 242: break; ! 243: default: ! 244: s->regs[saddr] = val; ! 245: break; ! 246: } ! 247: } ! 248: ! 249: static CPUReadMemoryFunc * const iommu_mem_read[3] = { ! 250: NULL, ! 251: NULL, ! 252: iommu_mem_readl, ! 253: }; ! 254: ! 255: static CPUWriteMemoryFunc * const iommu_mem_write[3] = { ! 256: NULL, ! 257: NULL, ! 258: iommu_mem_writel, ! 259: }; ! 260: ! 261: static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr) ! 262: { ! 263: uint32_t ret; ! 264: target_phys_addr_t iopte; ! 265: #ifdef DEBUG_IOMMU ! 266: target_phys_addr_t pa = addr; ! 267: #endif ! 268: ! 269: iopte = s->regs[IOMMU_BASE] << 4; ! 270: addr &= ~s->iostart; ! 271: iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3; ! 272: cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4); ! 273: tswap32s(&ret); ! 274: DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx ! 275: ", *pte = %x\n", pa, iopte, ret); ! 276: ! 277: return ret; ! 278: } ! 279: ! 280: static target_phys_addr_t iommu_translate_pa(target_phys_addr_t addr, ! 281: uint32_t pte) ! 282: { ! 283: target_phys_addr_t pa; ! 284: ! 285: pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK); ! 286: DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx ! 287: " (iopte = %x)\n", addr, pa, pte); ! 288: ! 289: return pa; ! 290: } ! 291: ! 292: static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, ! 293: int is_write) ! 294: { ! 295: DPRINTF("bad addr " TARGET_FMT_plx "\n", addr); ! 296: s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV | ! 297: IOMMU_AFSR_FAV; ! 298: if (!is_write) ! 299: s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD; ! 300: s->regs[IOMMU_AFAR] = addr; ! 301: qemu_irq_raise(s->irq); ! 302: } ! 303: ! 304: void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, ! 305: uint8_t *buf, int len, int is_write) ! 306: { ! 307: int l; ! 308: uint32_t flags; ! 309: target_phys_addr_t page, phys_addr; ! 310: ! 311: while (len > 0) { ! 312: page = addr & IOMMU_PAGE_MASK; ! 313: l = (page + IOMMU_PAGE_SIZE) - addr; ! 314: if (l > len) ! 315: l = len; ! 316: flags = iommu_page_get_flags(opaque, page); ! 317: if (!(flags & IOPTE_VALID)) { ! 318: iommu_bad_addr(opaque, page, is_write); ! 319: return; ! 320: } ! 321: phys_addr = iommu_translate_pa(addr, flags); ! 322: if (is_write) { ! 323: if (!(flags & IOPTE_WRITE)) { ! 324: iommu_bad_addr(opaque, page, is_write); ! 325: return; ! 326: } ! 327: cpu_physical_memory_write(phys_addr, buf, l); ! 328: } else { ! 329: cpu_physical_memory_read(phys_addr, buf, l); ! 330: } ! 331: len -= l; ! 332: buf += l; ! 333: addr += l; ! 334: } ! 335: } ! 336: ! 337: static const VMStateDescription vmstate_iommu = { ! 338: .name ="iommu", ! 339: .version_id = 2, ! 340: .minimum_version_id = 2, ! 341: .minimum_version_id_old = 2, ! 342: .fields = (VMStateField []) { ! 343: VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS), ! 344: VMSTATE_UINT64(iostart, IOMMUState), ! 345: VMSTATE_END_OF_LIST() ! 346: } ! 347: }; ! 348: ! 349: static void iommu_reset(DeviceState *d) ! 350: { ! 351: IOMMUState *s = container_of(d, IOMMUState, busdev.qdev); ! 352: ! 353: memset(s->regs, 0, IOMMU_NREGS * 4); ! 354: s->iostart = 0; ! 355: s->regs[IOMMU_CTRL] = s->version; ! 356: s->regs[IOMMU_ARBEN] = IOMMU_MID; ! 357: s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV; ! 358: s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB; ! 359: s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK; ! 360: } ! 361: ! 362: static int iommu_init1(SysBusDevice *dev) ! 363: { ! 364: IOMMUState *s = FROM_SYSBUS(IOMMUState, dev); ! 365: int io; ! 366: ! 367: sysbus_init_irq(dev, &s->irq); ! 368: ! 369: io = cpu_register_io_memory(iommu_mem_read, iommu_mem_write, s); ! 370: sysbus_init_mmio(dev, IOMMU_NREGS * sizeof(uint32_t), io); ! 371: ! 372: return 0; ! 373: } ! 374: ! 375: static SysBusDeviceInfo iommu_info = { ! 376: .init = iommu_init1, ! 377: .qdev.name = "iommu", ! 378: .qdev.size = sizeof(IOMMUState), ! 379: .qdev.vmsd = &vmstate_iommu, ! 380: .qdev.reset = iommu_reset, ! 381: .qdev.props = (Property[]) { ! 382: DEFINE_PROP_HEX32("version", IOMMUState, version, 0), ! 383: DEFINE_PROP_END_OF_LIST(), ! 384: } ! 385: }; ! 386: ! 387: static void iommu_register_devices(void) ! 388: { ! 389: sysbus_register_withprop(&iommu_info); ! 390: } ! 391: ! 392: device_init(iommu_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.