Revision 66321a11 hw/iommu.c
b/hw/iommu.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* QEMU SPARC iommu emulation |
3 | 3 |
* |
4 |
* Copyright (c) 2003 Fabrice Bellard |
|
4 |
* Copyright (c) 2003-2005 Fabrice Bellard
|
|
5 | 5 |
* |
6 | 6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | 7 |
* of this software and associated documentation files (the "Software"), to deal |
... | ... | |
26 | 26 |
/* debug iommu */ |
27 | 27 |
//#define DEBUG_IOMMU |
28 | 28 |
|
29 |
/* The IOMMU registers occupy three pages in IO space. */ |
|
30 |
struct iommu_regs { |
|
31 |
/* First page */ |
|
32 |
volatile unsigned long control; /* IOMMU control */ |
|
33 |
volatile unsigned long base; /* Physical base of iopte page table */ |
|
34 |
volatile unsigned long _unused1[3]; |
|
35 |
volatile unsigned long tlbflush; /* write only */ |
|
36 |
volatile unsigned long pageflush; /* write only */ |
|
37 |
volatile unsigned long _unused2[1017]; |
|
38 |
/* Second page */ |
|
39 |
volatile unsigned long afsr; /* Async-fault status register */ |
|
40 |
volatile unsigned long afar; /* Async-fault physical address */ |
|
41 |
volatile unsigned long _unused3[2]; |
|
42 |
volatile unsigned long sbuscfg0; /* SBUS configuration registers, per-slot */ |
|
43 |
volatile unsigned long sbuscfg1; |
|
44 |
volatile unsigned long sbuscfg2; |
|
45 |
volatile unsigned long sbuscfg3; |
|
46 |
volatile unsigned long mfsr; /* Memory-fault status register */ |
|
47 |
volatile unsigned long mfar; /* Memory-fault physical address */ |
|
48 |
volatile unsigned long _unused4[1014]; |
|
49 |
/* Third page */ |
|
50 |
volatile unsigned long mid; /* IOMMU module-id */ |
|
51 |
}; |
|
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 |
|
52 | 35 |
|
36 |
#define IOMMU_NREGS (3*4096) |
|
53 | 37 |
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ |
54 | 38 |
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */ |
55 | 39 |
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ |
... | ... | |
63 | 47 |
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ |
64 | 48 |
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ |
65 | 49 |
|
66 |
#define IOMMU_AFSR_ERR 0x80000000 /* LE, TO, or BE asserted */ |
|
67 |
#define IOMMU_AFSR_LE 0x40000000 /* SBUS reports error after transaction */ |
|
68 |
#define IOMMU_AFSR_TO 0x20000000 /* Write access took more than 12.8 us. */ |
|
69 |
#define IOMMU_AFSR_BE 0x10000000 /* Write access received error acknowledge */ |
|
70 |
#define IOMMU_AFSR_SIZE 0x0e000000 /* Size of transaction causing error */ |
|
71 |
#define IOMMU_AFSR_S 0x01000000 /* Sparc was in supervisor mode */ |
|
72 |
#define IOMMU_AFSR_RESV 0x00f00000 /* Reserver, forced to 0x8 by hardware */ |
|
73 |
#define IOMMU_AFSR_ME 0x00080000 /* Multiple errors occurred */ |
|
74 |
#define IOMMU_AFSR_RD 0x00040000 /* A read operation was in progress */ |
|
75 |
#define IOMMU_AFSR_FAV 0x00020000 /* IOMMU afar has valid contents */ |
|
76 |
|
|
77 |
#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ |
|
78 |
#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ |
|
79 |
#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ |
|
80 |
#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses |
|
81 |
produced by this device as pure |
|
82 |
physical. */ |
|
83 |
|
|
84 |
#define IOMMU_MFSR_ERR 0x80000000 /* One or more of PERR1 or PERR0 */ |
|
85 |
#define IOMMU_MFSR_S 0x01000000 /* Sparc was in supervisor mode */ |
|
86 |
#define IOMMU_MFSR_CPU 0x00800000 /* CPU transaction caused parity error */ |
|
87 |
#define IOMMU_MFSR_ME 0x00080000 /* Multiple parity errors occurred */ |
|
88 |
#define IOMMU_MFSR_PERR 0x00006000 /* high bit indicates parity error occurred |
|
89 |
on the even word of the access, low bit |
|
90 |
indicated odd word caused the parity error */ |
|
91 |
#define IOMMU_MFSR_BM 0x00001000 /* Error occurred while in boot mode */ |
|
92 |
#define IOMMU_MFSR_C 0x00000800 /* Address causing error was marked cacheable */ |
|
93 |
#define IOMMU_MFSR_RTYP 0x000000f0 /* Memory request transaction type */ |
|
94 |
|
|
95 |
#define IOMMU_MID_SBAE 0x001f0000 /* SBus arbitration enable */ |
|
96 |
#define IOMMU_MID_SE 0x00100000 /* Enables SCSI/ETHERNET arbitration */ |
|
97 |
#define IOMMU_MID_SB3 0x00080000 /* Enable SBUS device 3 arbitration */ |
|
98 |
#define IOMMU_MID_SB2 0x00040000 /* Enable SBUS device 2 arbitration */ |
|
99 |
#define IOMMU_MID_SB1 0x00020000 /* Enable SBUS device 1 arbitration */ |
|
100 |
#define IOMMU_MID_SB0 0x00010000 /* Enable SBUS device 0 arbitration */ |
|
101 |
#define IOMMU_MID_MID 0x0000000f /* Module-id, hardcoded to 0x8 */ |
|
102 |
|
|
103 | 50 |
/* The format of an iopte in the page tables */ |
104 | 51 |
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ |
105 | 52 |
#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ |
... | ... | |
113 | 60 |
|
114 | 61 |
typedef struct IOMMUState { |
115 | 62 |
uint32_t addr; |
116 |
uint32_t regs[sizeof(struct iommu_regs)];
|
|
63 |
uint32_t regs[IOMMU_NREGS];
|
|
117 | 64 |
uint32_t iostart; |
118 | 65 |
} IOMMUState; |
119 | 66 |
|
... | ... | |
125 | 72 |
saddr = (addr - s->addr) >> 2; |
126 | 73 |
switch (saddr) { |
127 | 74 |
default: |
75 |
DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]); |
|
128 | 76 |
return s->regs[saddr]; |
129 | 77 |
break; |
130 | 78 |
} |
... | ... | |
137 | 85 |
uint32_t saddr; |
138 | 86 |
|
139 | 87 |
saddr = (addr - s->addr) >> 2; |
88 |
DPRINTF("write reg[%d] = %x\n", saddr, val); |
|
140 | 89 |
switch (saddr) { |
141 | 90 |
case 0: |
142 | 91 |
switch (val & IOMMU_CTRL_RNGE) { |
... | ... | |
166 | 115 |
s->iostart = 0x80000000; |
167 | 116 |
break; |
168 | 117 |
} |
118 |
DPRINTF("iostart = %x\n", s->iostart); |
|
169 | 119 |
/* Fall through */ |
170 | 120 |
default: |
171 | 121 |
s->regs[saddr] = val; |
... | ... | |
188 | 138 |
uint32_t iommu_translate_local(void *opaque, uint32_t addr) |
189 | 139 |
{ |
190 | 140 |
IOMMUState *s = opaque; |
191 |
uint32_t *iopte = (void *)(s->regs[1] << 4), pa;
|
|
141 |
uint32_t iopte, pa, tmppte;
|
|
192 | 142 |
|
193 |
iopte += ((addr - s->iostart) >> PAGE_SHIFT); |
|
194 |
cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4); |
|
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); |
|
195 | 147 |
bswap32s(&pa); |
196 |
pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */ |
|
197 |
return pa + (addr & PAGE_MASK); |
|
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; |
|
198 | 152 |
} |
199 | 153 |
|
200 | 154 |
static void iommu_save(QEMUFile *f, void *opaque) |
... | ... | |
203 | 157 |
int i; |
204 | 158 |
|
205 | 159 |
qemu_put_be32s(f, &s->addr); |
206 |
for (i = 0; i < sizeof(struct iommu_regs); i += 4)
|
|
160 |
for (i = 0; i < IOMMU_NREGS; i++)
|
|
207 | 161 |
qemu_put_be32s(f, &s->regs[i]); |
208 | 162 |
qemu_put_be32s(f, &s->iostart); |
209 | 163 |
} |
... | ... | |
217 | 171 |
return -EINVAL; |
218 | 172 |
|
219 | 173 |
qemu_get_be32s(f, &s->addr); |
220 |
for (i = 0; i < sizeof(struct iommu_regs); i += 4)
|
|
174 |
for (i = 0; i < IOMMU_NREGS; i++)
|
|
221 | 175 |
qemu_put_be32s(f, &s->regs[i]); |
222 | 176 |
qemu_get_be32s(f, &s->iostart); |
223 | 177 |
|
... | ... | |
228 | 182 |
{ |
229 | 183 |
IOMMUState *s = opaque; |
230 | 184 |
|
231 |
memset(s->regs, 0, sizeof(struct iommu_regs));
|
|
185 |
memset(s->regs, 0, IOMMU_NREGS * 4);
|
|
232 | 186 |
s->iostart = 0; |
233 | 187 |
} |
234 | 188 |
|
... | ... | |
244 | 198 |
s->addr = addr; |
245 | 199 |
|
246 | 200 |
iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); |
247 |
cpu_register_physical_memory(addr, sizeof(struct iommu_regs), |
|
248 |
iommu_io_memory); |
|
201 |
cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); |
|
249 | 202 |
|
250 | 203 |
register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); |
251 | 204 |
qemu_register_reset(iommu_reset, s); |
Also available in: Unified diff