Statistics
| Branch: | Revision:

root / hw / iommu.c @ 71be0fc3

History | View | Annotate | Download (5.7 kB)

1 420557e8 bellard
/*
2 420557e8 bellard
 * QEMU SPARC iommu emulation
3 420557e8 bellard
 *
4 66321a11 bellard
 * Copyright (c) 2003-2005 Fabrice Bellard
5 420557e8 bellard
 * 
6 420557e8 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 420557e8 bellard
 * of this software and associated documentation files (the "Software"), to deal
8 420557e8 bellard
 * in the Software without restriction, including without limitation the rights
9 420557e8 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 420557e8 bellard
 * copies of the Software, and to permit persons to whom the Software is
11 420557e8 bellard
 * furnished to do so, subject to the following conditions:
12 420557e8 bellard
 *
13 420557e8 bellard
 * The above copyright notice and this permission notice shall be included in
14 420557e8 bellard
 * all copies or substantial portions of the Software.
15 420557e8 bellard
 *
16 420557e8 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 420557e8 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 420557e8 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 420557e8 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 420557e8 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 420557e8 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 420557e8 bellard
 * THE SOFTWARE.
23 420557e8 bellard
 */
24 420557e8 bellard
#include "vl.h"
25 420557e8 bellard
26 420557e8 bellard
/* debug iommu */
27 420557e8 bellard
//#define DEBUG_IOMMU
28 420557e8 bellard
29 66321a11 bellard
#ifdef DEBUG_IOMMU
30 66321a11 bellard
#define DPRINTF(fmt, args...) \
31 66321a11 bellard
do { printf("IOMMU: " fmt , ##args); } while (0)
32 66321a11 bellard
#else
33 66321a11 bellard
#define DPRINTF(fmt, args...)
34 66321a11 bellard
#endif
35 420557e8 bellard
36 66321a11 bellard
#define IOMMU_NREGS (3*4096)
37 420557e8 bellard
#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
38 420557e8 bellard
#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
39 420557e8 bellard
#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
40 420557e8 bellard
#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
41 420557e8 bellard
#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
42 420557e8 bellard
#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
43 420557e8 bellard
#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
44 420557e8 bellard
#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
45 420557e8 bellard
#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
46 420557e8 bellard
#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
47 420557e8 bellard
#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
48 420557e8 bellard
#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
49 420557e8 bellard
50 420557e8 bellard
/* The format of an iopte in the page tables */
51 420557e8 bellard
#define IOPTE_PAGE          0x07ffff00 /* Physical page number (PA[30:12]) */
52 420557e8 bellard
#define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
53 420557e8 bellard
#define IOPTE_WRITE         0x00000004 /* Writeable */
54 420557e8 bellard
#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
55 420557e8 bellard
#define IOPTE_WAZ           0x00000001 /* Write as zeros */
56 420557e8 bellard
57 420557e8 bellard
#define PAGE_SHIFT      12
58 420557e8 bellard
#define PAGE_SIZE       (1 << PAGE_SHIFT)
59 420557e8 bellard
#define PAGE_MASK        (PAGE_SIZE - 1)
60 420557e8 bellard
61 420557e8 bellard
typedef struct IOMMUState {
62 8d5f07fa bellard
    uint32_t addr;
63 66321a11 bellard
    uint32_t regs[IOMMU_NREGS];
64 8d5f07fa bellard
    uint32_t iostart;
65 420557e8 bellard
} IOMMUState;
66 420557e8 bellard
67 420557e8 bellard
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
68 420557e8 bellard
{
69 420557e8 bellard
    IOMMUState *s = opaque;
70 420557e8 bellard
    uint32_t saddr;
71 420557e8 bellard
72 8d5f07fa bellard
    saddr = (addr - s->addr) >> 2;
73 420557e8 bellard
    switch (saddr) {
74 420557e8 bellard
    default:
75 66321a11 bellard
        DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
76 420557e8 bellard
        return s->regs[saddr];
77 420557e8 bellard
        break;
78 420557e8 bellard
    }
79 420557e8 bellard
    return 0;
80 420557e8 bellard
}
81 420557e8 bellard
82 420557e8 bellard
static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
83 420557e8 bellard
{
84 420557e8 bellard
    IOMMUState *s = opaque;
85 420557e8 bellard
    uint32_t saddr;
86 420557e8 bellard
87 8d5f07fa bellard
    saddr = (addr - s->addr) >> 2;
88 66321a11 bellard
    DPRINTF("write reg[%d] = %x\n", saddr, val);
89 420557e8 bellard
    switch (saddr) {
90 8d5f07fa bellard
    case 0:
91 8d5f07fa bellard
        switch (val & IOMMU_CTRL_RNGE) {
92 8d5f07fa bellard
        case IOMMU_RNGE_16MB:
93 8d5f07fa bellard
            s->iostart = 0xff000000;
94 8d5f07fa bellard
            break;
95 8d5f07fa bellard
        case IOMMU_RNGE_32MB:
96 8d5f07fa bellard
            s->iostart = 0xfe000000;
97 8d5f07fa bellard
            break;
98 8d5f07fa bellard
        case IOMMU_RNGE_64MB:
99 8d5f07fa bellard
            s->iostart = 0xfc000000;
100 8d5f07fa bellard
            break;
101 8d5f07fa bellard
        case IOMMU_RNGE_128MB:
102 8d5f07fa bellard
            s->iostart = 0xf8000000;
103 8d5f07fa bellard
            break;
104 8d5f07fa bellard
        case IOMMU_RNGE_256MB:
105 8d5f07fa bellard
            s->iostart = 0xf0000000;
106 8d5f07fa bellard
            break;
107 8d5f07fa bellard
        case IOMMU_RNGE_512MB:
108 8d5f07fa bellard
            s->iostart = 0xe0000000;
109 8d5f07fa bellard
            break;
110 8d5f07fa bellard
        case IOMMU_RNGE_1GB:
111 8d5f07fa bellard
            s->iostart = 0xc0000000;
112 8d5f07fa bellard
            break;
113 8d5f07fa bellard
        default:
114 8d5f07fa bellard
        case IOMMU_RNGE_2GB:
115 8d5f07fa bellard
            s->iostart = 0x80000000;
116 8d5f07fa bellard
            break;
117 8d5f07fa bellard
        }
118 66321a11 bellard
        DPRINTF("iostart = %x\n", s->iostart);
119 8d5f07fa bellard
        /* Fall through */
120 420557e8 bellard
    default:
121 420557e8 bellard
        s->regs[saddr] = val;
122 420557e8 bellard
        break;
123 420557e8 bellard
    }
124 420557e8 bellard
}
125 420557e8 bellard
126 420557e8 bellard
static CPUReadMemoryFunc *iommu_mem_read[3] = {
127 420557e8 bellard
    iommu_mem_readw,
128 420557e8 bellard
    iommu_mem_readw,
129 420557e8 bellard
    iommu_mem_readw,
130 420557e8 bellard
};
131 420557e8 bellard
132 420557e8 bellard
static CPUWriteMemoryFunc *iommu_mem_write[3] = {
133 420557e8 bellard
    iommu_mem_writew,
134 420557e8 bellard
    iommu_mem_writew,
135 420557e8 bellard
    iommu_mem_writew,
136 420557e8 bellard
};
137 420557e8 bellard
138 e80cfcfc bellard
uint32_t iommu_translate_local(void *opaque, uint32_t addr)
139 420557e8 bellard
{
140 e80cfcfc bellard
    IOMMUState *s = opaque;
141 66321a11 bellard
    uint32_t iopte, pa, tmppte;
142 420557e8 bellard
143 66321a11 bellard
    iopte = s->regs[1] << 4;
144 66321a11 bellard
    addr &= ~s->iostart;
145 66321a11 bellard
    iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
146 66321a11 bellard
    cpu_physical_memory_read(iopte, (void *) &pa, 4);
147 420557e8 bellard
    bswap32s(&pa);
148 66321a11 bellard
    tmppte = pa;
149 66321a11 bellard
    pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
150 66321a11 bellard
    DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
151 66321a11 bellard
    return pa;
152 420557e8 bellard
}
153 420557e8 bellard
154 e80cfcfc bellard
static void iommu_save(QEMUFile *f, void *opaque)
155 e80cfcfc bellard
{
156 e80cfcfc bellard
    IOMMUState *s = opaque;
157 e80cfcfc bellard
    int i;
158 e80cfcfc bellard
    
159 e80cfcfc bellard
    qemu_put_be32s(f, &s->addr);
160 66321a11 bellard
    for (i = 0; i < IOMMU_NREGS; i++)
161 e80cfcfc bellard
        qemu_put_be32s(f, &s->regs[i]);
162 e80cfcfc bellard
    qemu_put_be32s(f, &s->iostart);
163 e80cfcfc bellard
}
164 e80cfcfc bellard
165 e80cfcfc bellard
static int iommu_load(QEMUFile *f, void *opaque, int version_id)
166 e80cfcfc bellard
{
167 e80cfcfc bellard
    IOMMUState *s = opaque;
168 e80cfcfc bellard
    int i;
169 e80cfcfc bellard
    
170 e80cfcfc bellard
    if (version_id != 1)
171 e80cfcfc bellard
        return -EINVAL;
172 e80cfcfc bellard
173 e80cfcfc bellard
    qemu_get_be32s(f, &s->addr);
174 66321a11 bellard
    for (i = 0; i < IOMMU_NREGS; i++)
175 e80cfcfc bellard
        qemu_put_be32s(f, &s->regs[i]);
176 e80cfcfc bellard
    qemu_get_be32s(f, &s->iostart);
177 e80cfcfc bellard
178 e80cfcfc bellard
    return 0;
179 e80cfcfc bellard
}
180 e80cfcfc bellard
181 e80cfcfc bellard
static void iommu_reset(void *opaque)
182 e80cfcfc bellard
{
183 e80cfcfc bellard
    IOMMUState *s = opaque;
184 e80cfcfc bellard
185 66321a11 bellard
    memset(s->regs, 0, IOMMU_NREGS * 4);
186 e80cfcfc bellard
    s->iostart = 0;
187 e80cfcfc bellard
}
188 e80cfcfc bellard
189 e80cfcfc bellard
void *iommu_init(uint32_t addr)
190 420557e8 bellard
{
191 420557e8 bellard
    IOMMUState *s;
192 8d5f07fa bellard
    int iommu_io_memory;
193 420557e8 bellard
194 420557e8 bellard
    s = qemu_mallocz(sizeof(IOMMUState));
195 420557e8 bellard
    if (!s)
196 e80cfcfc bellard
        return NULL;
197 420557e8 bellard
198 8d5f07fa bellard
    s->addr = addr;
199 8d5f07fa bellard
200 420557e8 bellard
    iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
201 66321a11 bellard
    cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
202 420557e8 bellard
    
203 e80cfcfc bellard
    register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
204 e80cfcfc bellard
    qemu_register_reset(iommu_reset, s);
205 e80cfcfc bellard
    return s;
206 420557e8 bellard
}