|
|
1.1 ! root 1: /* ! 2: * QEMU SPARC 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: #include "vl.h" ! 25: ! 26: /* debug iommu */ ! 27: //#define DEBUG_IOMMU ! 28: ! 29: #ifdef DEBUG_IOMMU ! 30: #define DPRINTF(fmt, args...) \ ! 31: do { printf("IOMMU: " fmt , ##args); } while (0) ! 32: #else ! 33: #define DPRINTF(fmt, args...) ! 34: #endif ! 35: ! 36: #define IOMMU_NREGS (3*4096) ! 37: #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ ! 38: #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ ! 39: #define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ ! 40: #define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ ! 41: #define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ ! 42: #define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */ ! 43: #define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */ ! 44: #define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */ ! 45: #define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */ ! 46: #define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ ! 47: #define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ ! 48: #define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ ! 49: ! 50: /* The format of an iopte in the page tables */ ! 51: #define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ ! 52: #define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ ! 53: #define IOPTE_WRITE 0x00000004 /* Writeable */ ! 54: #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ ! 55: #define IOPTE_WAZ 0x00000001 /* Write as zeros */ ! 56: ! 57: #define PAGE_SHIFT 12 ! 58: #define PAGE_SIZE (1 << PAGE_SHIFT) ! 59: #define PAGE_MASK (PAGE_SIZE - 1) ! 60: ! 61: typedef struct IOMMUState { ! 62: uint32_t addr; ! 63: uint32_t regs[IOMMU_NREGS]; ! 64: uint32_t iostart; ! 65: } IOMMUState; ! 66: ! 67: static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) ! 68: { ! 69: IOMMUState *s = opaque; ! 70: uint32_t saddr; ! 71: ! 72: saddr = (addr - s->addr) >> 2; ! 73: switch (saddr) { ! 74: default: ! 75: DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]); ! 76: return s->regs[saddr]; ! 77: break; ! 78: } ! 79: return 0; ! 80: } ! 81: ! 82: static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) ! 83: { ! 84: IOMMUState *s = opaque; ! 85: uint32_t saddr; ! 86: ! 87: saddr = (addr - s->addr) >> 2; ! 88: DPRINTF("write reg[%d] = %x\n", saddr, val); ! 89: switch (saddr) { ! 90: case 0: ! 91: switch (val & IOMMU_CTRL_RNGE) { ! 92: case IOMMU_RNGE_16MB: ! 93: s->iostart = 0xff000000; ! 94: break; ! 95: case IOMMU_RNGE_32MB: ! 96: s->iostart = 0xfe000000; ! 97: break; ! 98: case IOMMU_RNGE_64MB: ! 99: s->iostart = 0xfc000000; ! 100: break; ! 101: case IOMMU_RNGE_128MB: ! 102: s->iostart = 0xf8000000; ! 103: break; ! 104: case IOMMU_RNGE_256MB: ! 105: s->iostart = 0xf0000000; ! 106: break; ! 107: case IOMMU_RNGE_512MB: ! 108: s->iostart = 0xe0000000; ! 109: break; ! 110: case IOMMU_RNGE_1GB: ! 111: s->iostart = 0xc0000000; ! 112: break; ! 113: default: ! 114: case IOMMU_RNGE_2GB: ! 115: s->iostart = 0x80000000; ! 116: break; ! 117: } ! 118: DPRINTF("iostart = %x\n", s->iostart); ! 119: /* Fall through */ ! 120: default: ! 121: s->regs[saddr] = val; ! 122: break; ! 123: } ! 124: } ! 125: ! 126: static CPUReadMemoryFunc *iommu_mem_read[3] = { ! 127: iommu_mem_readw, ! 128: iommu_mem_readw, ! 129: iommu_mem_readw, ! 130: }; ! 131: ! 132: static CPUWriteMemoryFunc *iommu_mem_write[3] = { ! 133: iommu_mem_writew, ! 134: iommu_mem_writew, ! 135: iommu_mem_writew, ! 136: }; ! 137: ! 138: uint32_t iommu_translate_local(void *opaque, uint32_t addr) ! 139: { ! 140: IOMMUState *s = opaque; ! 141: uint32_t iopte, pa, tmppte; ! 142: ! 143: iopte = s->regs[1] << 4; ! 144: addr &= ~s->iostart; ! 145: iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; ! 146: cpu_physical_memory_read(iopte, (void *) &pa, 4); ! 147: bswap32s(&pa); ! 148: tmppte = pa; ! 149: pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); ! 150: DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); ! 151: return pa; ! 152: } ! 153: ! 154: static void iommu_save(QEMUFile *f, void *opaque) ! 155: { ! 156: IOMMUState *s = opaque; ! 157: int i; ! 158: ! 159: qemu_put_be32s(f, &s->addr); ! 160: for (i = 0; i < IOMMU_NREGS; i++) ! 161: qemu_put_be32s(f, &s->regs[i]); ! 162: qemu_put_be32s(f, &s->iostart); ! 163: } ! 164: ! 165: static int iommu_load(QEMUFile *f, void *opaque, int version_id) ! 166: { ! 167: IOMMUState *s = opaque; ! 168: int i; ! 169: ! 170: if (version_id != 1) ! 171: return -EINVAL; ! 172: ! 173: qemu_get_be32s(f, &s->addr); ! 174: for (i = 0; i < IOMMU_NREGS; i++) ! 175: qemu_put_be32s(f, &s->regs[i]); ! 176: qemu_get_be32s(f, &s->iostart); ! 177: ! 178: return 0; ! 179: } ! 180: ! 181: static void iommu_reset(void *opaque) ! 182: { ! 183: IOMMUState *s = opaque; ! 184: ! 185: memset(s->regs, 0, IOMMU_NREGS * 4); ! 186: s->iostart = 0; ! 187: } ! 188: ! 189: void *iommu_init(uint32_t addr) ! 190: { ! 191: IOMMUState *s; ! 192: int iommu_io_memory; ! 193: ! 194: s = qemu_mallocz(sizeof(IOMMUState)); ! 195: if (!s) ! 196: return NULL; ! 197: ! 198: s->addr = addr; ! 199: ! 200: iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); ! 201: cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); ! 202: ! 203: register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); ! 204: qemu_register_reset(iommu_reset, s); ! 205: return s; ! 206: } ! 207:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.