Statistics
| Branch: | Revision:

root / ioport.c @ feature-archipelago

History | View | Annotate | Download (8.9 kB)

1 32993977 Isaku Yamahata
/*
2 32993977 Isaku Yamahata
 * QEMU System Emulator
3 32993977 Isaku Yamahata
 *
4 32993977 Isaku Yamahata
 * Copyright (c) 2003-2008 Fabrice Bellard
5 32993977 Isaku Yamahata
 *
6 32993977 Isaku Yamahata
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 32993977 Isaku Yamahata
 * of this software and associated documentation files (the "Software"), to deal
8 32993977 Isaku Yamahata
 * in the Software without restriction, including without limitation the rights
9 32993977 Isaku Yamahata
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 32993977 Isaku Yamahata
 * copies of the Software, and to permit persons to whom the Software is
11 32993977 Isaku Yamahata
 * furnished to do so, subject to the following conditions:
12 32993977 Isaku Yamahata
 *
13 32993977 Isaku Yamahata
 * The above copyright notice and this permission notice shall be included in
14 32993977 Isaku Yamahata
 * all copies or substantial portions of the Software.
15 32993977 Isaku Yamahata
 *
16 32993977 Isaku Yamahata
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 32993977 Isaku Yamahata
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 32993977 Isaku Yamahata
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 32993977 Isaku Yamahata
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 32993977 Isaku Yamahata
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 32993977 Isaku Yamahata
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 32993977 Isaku Yamahata
 * THE SOFTWARE.
23 32993977 Isaku Yamahata
 */
24 32993977 Isaku Yamahata
/*
25 32993977 Isaku Yamahata
 * splitted out ioport related stuffs from vl.c.
26 32993977 Isaku Yamahata
 */
27 32993977 Isaku Yamahata
28 022c62cb Paolo Bonzini
#include "exec/ioport.h"
29 bd3c9aa5 Prerna Saxena
#include "trace.h"
30 022c62cb Paolo Bonzini
#include "exec/memory.h"
31 b40acf99 Jan Kiszka
#include "exec/address-spaces.h"
32 32993977 Isaku Yamahata
33 32993977 Isaku Yamahata
//#define DEBUG_IOPORT
34 32993977 Isaku Yamahata
35 32993977 Isaku Yamahata
#ifdef DEBUG_IOPORT
36 32993977 Isaku Yamahata
#  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
37 32993977 Isaku Yamahata
#else
38 32993977 Isaku Yamahata
#  define LOG_IOPORT(...) do { } while (0)
39 32993977 Isaku Yamahata
#endif
40 32993977 Isaku Yamahata
41 b40acf99 Jan Kiszka
typedef struct MemoryRegionPortioList {
42 b40acf99 Jan Kiszka
    MemoryRegion mr;
43 b40acf99 Jan Kiszka
    void *portio_opaque;
44 b40acf99 Jan Kiszka
    MemoryRegionPortio ports[];
45 b40acf99 Jan Kiszka
} MemoryRegionPortioList;
46 b40acf99 Jan Kiszka
47 3bb28b72 Jan Kiszka
static uint64_t unassigned_io_read(void *opaque, hwaddr addr, unsigned size)
48 3bb28b72 Jan Kiszka
{
49 3bb28b72 Jan Kiszka
    return -1ULL;
50 3bb28b72 Jan Kiszka
}
51 3bb28b72 Jan Kiszka
52 3bb28b72 Jan Kiszka
static void unassigned_io_write(void *opaque, hwaddr addr, uint64_t val,
53 3bb28b72 Jan Kiszka
                                unsigned size)
54 3bb28b72 Jan Kiszka
{
55 3bb28b72 Jan Kiszka
}
56 3bb28b72 Jan Kiszka
57 3bb28b72 Jan Kiszka
const MemoryRegionOps unassigned_io_ops = {
58 3bb28b72 Jan Kiszka
    .read = unassigned_io_read,
59 3bb28b72 Jan Kiszka
    .write = unassigned_io_write,
60 3bb28b72 Jan Kiszka
    .endianness = DEVICE_NATIVE_ENDIAN,
61 3bb28b72 Jan Kiszka
};
62 3bb28b72 Jan Kiszka
63 c227f099 Anthony Liguori
void cpu_outb(pio_addr_t addr, uint8_t val)
64 32993977 Isaku Yamahata
{
65 07323531 Isaku Yamahata
    LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
66 bd3c9aa5 Prerna Saxena
    trace_cpu_out(addr, val);
67 b40acf99 Jan Kiszka
    address_space_write(&address_space_io, addr, &val, 1);
68 32993977 Isaku Yamahata
}
69 32993977 Isaku Yamahata
70 c227f099 Anthony Liguori
void cpu_outw(pio_addr_t addr, uint16_t val)
71 32993977 Isaku Yamahata
{
72 b40acf99 Jan Kiszka
    uint8_t buf[2];
73 b40acf99 Jan Kiszka
74 07323531 Isaku Yamahata
    LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
75 bd3c9aa5 Prerna Saxena
    trace_cpu_out(addr, val);
76 b40acf99 Jan Kiszka
    stw_p(buf, val);
77 b40acf99 Jan Kiszka
    address_space_write(&address_space_io, addr, buf, 2);
78 32993977 Isaku Yamahata
}
79 32993977 Isaku Yamahata
80 c227f099 Anthony Liguori
void cpu_outl(pio_addr_t addr, uint32_t val)
81 32993977 Isaku Yamahata
{
82 b40acf99 Jan Kiszka
    uint8_t buf[4];
83 b40acf99 Jan Kiszka
84 07323531 Isaku Yamahata
    LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
85 bd3c9aa5 Prerna Saxena
    trace_cpu_out(addr, val);
86 b40acf99 Jan Kiszka
    stl_p(buf, val);
87 b40acf99 Jan Kiszka
    address_space_write(&address_space_io, addr, buf, 4);
88 32993977 Isaku Yamahata
}
89 32993977 Isaku Yamahata
90 c227f099 Anthony Liguori
uint8_t cpu_inb(pio_addr_t addr)
91 32993977 Isaku Yamahata
{
92 07323531 Isaku Yamahata
    uint8_t val;
93 b40acf99 Jan Kiszka
94 b40acf99 Jan Kiszka
    address_space_read(&address_space_io, addr, &val, 1);
95 bd3c9aa5 Prerna Saxena
    trace_cpu_in(addr, val);
96 07323531 Isaku Yamahata
    LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
97 32993977 Isaku Yamahata
    return val;
98 32993977 Isaku Yamahata
}
99 32993977 Isaku Yamahata
100 c227f099 Anthony Liguori
uint16_t cpu_inw(pio_addr_t addr)
101 32993977 Isaku Yamahata
{
102 b40acf99 Jan Kiszka
    uint8_t buf[2];
103 07323531 Isaku Yamahata
    uint16_t val;
104 b40acf99 Jan Kiszka
105 b40acf99 Jan Kiszka
    address_space_read(&address_space_io, addr, buf, 2);
106 b40acf99 Jan Kiszka
    val = lduw_p(buf);
107 bd3c9aa5 Prerna Saxena
    trace_cpu_in(addr, val);
108 07323531 Isaku Yamahata
    LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
109 32993977 Isaku Yamahata
    return val;
110 32993977 Isaku Yamahata
}
111 32993977 Isaku Yamahata
112 c227f099 Anthony Liguori
uint32_t cpu_inl(pio_addr_t addr)
113 32993977 Isaku Yamahata
{
114 b40acf99 Jan Kiszka
    uint8_t buf[4];
115 07323531 Isaku Yamahata
    uint32_t val;
116 b40acf99 Jan Kiszka
117 b40acf99 Jan Kiszka
    address_space_read(&address_space_io, addr, buf, 4);
118 b40acf99 Jan Kiszka
    val = ldl_p(buf);
119 bd3c9aa5 Prerna Saxena
    trace_cpu_in(addr, val);
120 07323531 Isaku Yamahata
    LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
121 32993977 Isaku Yamahata
    return val;
122 32993977 Isaku Yamahata
}
123 6bf9fd43 Avi Kivity
124 6bf9fd43 Avi Kivity
void portio_list_init(PortioList *piolist,
125 db10ca90 Paolo Bonzini
                      Object *owner,
126 6bf9fd43 Avi Kivity
                      const MemoryRegionPortio *callbacks,
127 6bf9fd43 Avi Kivity
                      void *opaque, const char *name)
128 6bf9fd43 Avi Kivity
{
129 6bf9fd43 Avi Kivity
    unsigned n = 0;
130 6bf9fd43 Avi Kivity
131 6bf9fd43 Avi Kivity
    while (callbacks[n].size) {
132 6bf9fd43 Avi Kivity
        ++n;
133 6bf9fd43 Avi Kivity
    }
134 6bf9fd43 Avi Kivity
135 6bf9fd43 Avi Kivity
    piolist->ports = callbacks;
136 6bf9fd43 Avi Kivity
    piolist->nr = 0;
137 6bf9fd43 Avi Kivity
    piolist->regions = g_new0(MemoryRegion *, n);
138 6bf9fd43 Avi Kivity
    piolist->address_space = NULL;
139 6bf9fd43 Avi Kivity
    piolist->opaque = opaque;
140 db10ca90 Paolo Bonzini
    piolist->owner = owner;
141 6bf9fd43 Avi Kivity
    piolist->name = name;
142 c76bc480 Jan Kiszka
    piolist->flush_coalesced_mmio = false;
143 c76bc480 Jan Kiszka
}
144 c76bc480 Jan Kiszka
145 c76bc480 Jan Kiszka
void portio_list_set_flush_coalesced(PortioList *piolist)
146 c76bc480 Jan Kiszka
{
147 c76bc480 Jan Kiszka
    piolist->flush_coalesced_mmio = true;
148 6bf9fd43 Avi Kivity
}
149 6bf9fd43 Avi Kivity
150 6bf9fd43 Avi Kivity
void portio_list_destroy(PortioList *piolist)
151 6bf9fd43 Avi Kivity
{
152 6bf9fd43 Avi Kivity
    g_free(piolist->regions);
153 6bf9fd43 Avi Kivity
}
154 6bf9fd43 Avi Kivity
155 b40acf99 Jan Kiszka
static const MemoryRegionPortio *find_portio(MemoryRegionPortioList *mrpio,
156 b40acf99 Jan Kiszka
                                             uint64_t offset, unsigned size,
157 b40acf99 Jan Kiszka
                                             bool write)
158 b40acf99 Jan Kiszka
{
159 b40acf99 Jan Kiszka
    const MemoryRegionPortio *mrp;
160 b40acf99 Jan Kiszka
161 b40acf99 Jan Kiszka
    for (mrp = mrpio->ports; mrp->size; ++mrp) {
162 b40acf99 Jan Kiszka
        if (offset >= mrp->offset && offset < mrp->offset + mrp->len &&
163 b40acf99 Jan Kiszka
            size == mrp->size &&
164 b40acf99 Jan Kiszka
            (write ? (bool)mrp->write : (bool)mrp->read)) {
165 b40acf99 Jan Kiszka
            return mrp;
166 b40acf99 Jan Kiszka
        }
167 b40acf99 Jan Kiszka
    }
168 b40acf99 Jan Kiszka
    return NULL;
169 b40acf99 Jan Kiszka
}
170 b40acf99 Jan Kiszka
171 b40acf99 Jan Kiszka
static uint64_t portio_read(void *opaque, hwaddr addr, unsigned size)
172 b40acf99 Jan Kiszka
{
173 b40acf99 Jan Kiszka
    MemoryRegionPortioList *mrpio = opaque;
174 b40acf99 Jan Kiszka
    const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, false);
175 b40acf99 Jan Kiszka
    uint64_t data;
176 b40acf99 Jan Kiszka
177 b40acf99 Jan Kiszka
    data = ((uint64_t)1 << (size * 8)) - 1;
178 b40acf99 Jan Kiszka
    if (mrp) {
179 b40acf99 Jan Kiszka
        data = mrp->read(mrpio->portio_opaque, mrp->base + addr);
180 b40acf99 Jan Kiszka
    } else if (size == 2) {
181 b40acf99 Jan Kiszka
        mrp = find_portio(mrpio, addr, 1, false);
182 b40acf99 Jan Kiszka
        assert(mrp);
183 b40acf99 Jan Kiszka
        data = mrp->read(mrpio->portio_opaque, mrp->base + addr) |
184 b40acf99 Jan Kiszka
                (mrp->read(mrpio->portio_opaque, mrp->base + addr + 1) << 8);
185 b40acf99 Jan Kiszka
    }
186 b40acf99 Jan Kiszka
    return data;
187 b40acf99 Jan Kiszka
}
188 b40acf99 Jan Kiszka
189 b40acf99 Jan Kiszka
static void portio_write(void *opaque, hwaddr addr, uint64_t data,
190 b40acf99 Jan Kiszka
                         unsigned size)
191 b40acf99 Jan Kiszka
{
192 b40acf99 Jan Kiszka
    MemoryRegionPortioList *mrpio = opaque;
193 b40acf99 Jan Kiszka
    const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, true);
194 b40acf99 Jan Kiszka
195 b40acf99 Jan Kiszka
    if (mrp) {
196 b40acf99 Jan Kiszka
        mrp->write(mrpio->portio_opaque, mrp->base + addr, data);
197 b40acf99 Jan Kiszka
    } else if (size == 2) {
198 b40acf99 Jan Kiszka
        mrp = find_portio(mrpio, addr, 1, true);
199 b40acf99 Jan Kiszka
        assert(mrp);
200 b40acf99 Jan Kiszka
        mrp->write(mrpio->portio_opaque, mrp->base + addr, data & 0xff);
201 b40acf99 Jan Kiszka
        mrp->write(mrpio->portio_opaque, mrp->base + addr + 1, data >> 8);
202 b40acf99 Jan Kiszka
    }
203 b40acf99 Jan Kiszka
}
204 b40acf99 Jan Kiszka
205 b40acf99 Jan Kiszka
static const MemoryRegionOps portio_ops = {
206 b40acf99 Jan Kiszka
    .read = portio_read,
207 b40acf99 Jan Kiszka
    .write = portio_write,
208 f36a6382 Paolo Bonzini
    .endianness = DEVICE_LITTLE_ENDIAN,
209 b40acf99 Jan Kiszka
    .valid.unaligned = true,
210 b40acf99 Jan Kiszka
    .impl.unaligned = true,
211 b40acf99 Jan Kiszka
};
212 b40acf99 Jan Kiszka
213 6bf9fd43 Avi Kivity
static void portio_list_add_1(PortioList *piolist,
214 6bf9fd43 Avi Kivity
                              const MemoryRegionPortio *pio_init,
215 6bf9fd43 Avi Kivity
                              unsigned count, unsigned start,
216 6bf9fd43 Avi Kivity
                              unsigned off_low, unsigned off_high)
217 6bf9fd43 Avi Kivity
{
218 b40acf99 Jan Kiszka
    MemoryRegionPortioList *mrpio;
219 6bf9fd43 Avi Kivity
    unsigned i;
220 6bf9fd43 Avi Kivity
221 6bf9fd43 Avi Kivity
    /* Copy the sub-list and null-terminate it.  */
222 b40acf99 Jan Kiszka
    mrpio = g_malloc0(sizeof(MemoryRegionPortioList) +
223 b40acf99 Jan Kiszka
                      sizeof(MemoryRegionPortio) * (count + 1));
224 b40acf99 Jan Kiszka
    mrpio->portio_opaque = piolist->opaque;
225 b40acf99 Jan Kiszka
    memcpy(mrpio->ports, pio_init, sizeof(MemoryRegionPortio) * count);
226 b40acf99 Jan Kiszka
    memset(mrpio->ports + count, 0, sizeof(MemoryRegionPortio));
227 6bf9fd43 Avi Kivity
228 6bf9fd43 Avi Kivity
    /* Adjust the offsets to all be zero-based for the region.  */
229 6bf9fd43 Avi Kivity
    for (i = 0; i < count; ++i) {
230 b40acf99 Jan Kiszka
        mrpio->ports[i].offset -= off_low;
231 b40acf99 Jan Kiszka
        mrpio->ports[i].base = start + off_low;
232 6bf9fd43 Avi Kivity
    }
233 6bf9fd43 Avi Kivity
234 de58ac72 Avi Kivity
    /*
235 de58ac72 Avi Kivity
     * Use an alias so that the callback is called with an absolute address,
236 de58ac72 Avi Kivity
     * rather than an offset relative to to start + off_low.
237 de58ac72 Avi Kivity
     */
238 db10ca90 Paolo Bonzini
    memory_region_init_io(&mrpio->mr, piolist->owner, &portio_ops, mrpio,
239 db10ca90 Paolo Bonzini
                          piolist->name, off_high - off_low);
240 c76bc480 Jan Kiszka
    if (piolist->flush_coalesced_mmio) {
241 c76bc480 Jan Kiszka
        memory_region_set_flush_coalesced(&mrpio->mr);
242 c76bc480 Jan Kiszka
    }
243 6bf9fd43 Avi Kivity
    memory_region_add_subregion(piolist->address_space,
244 b40acf99 Jan Kiszka
                                start + off_low, &mrpio->mr);
245 b40acf99 Jan Kiszka
    piolist->regions[piolist->nr] = &mrpio->mr;
246 de58ac72 Avi Kivity
    ++piolist->nr;
247 6bf9fd43 Avi Kivity
}
248 6bf9fd43 Avi Kivity
249 6bf9fd43 Avi Kivity
void portio_list_add(PortioList *piolist,
250 6bf9fd43 Avi Kivity
                     MemoryRegion *address_space,
251 6bf9fd43 Avi Kivity
                     uint32_t start)
252 6bf9fd43 Avi Kivity
{
253 6bf9fd43 Avi Kivity
    const MemoryRegionPortio *pio, *pio_start = piolist->ports;
254 6bf9fd43 Avi Kivity
    unsigned int off_low, off_high, off_last, count;
255 6bf9fd43 Avi Kivity
256 6bf9fd43 Avi Kivity
    piolist->address_space = address_space;
257 6bf9fd43 Avi Kivity
258 6bf9fd43 Avi Kivity
    /* Handle the first entry specially.  */
259 6bf9fd43 Avi Kivity
    off_last = off_low = pio_start->offset;
260 6bf9fd43 Avi Kivity
    off_high = off_low + pio_start->len;
261 6bf9fd43 Avi Kivity
    count = 1;
262 6bf9fd43 Avi Kivity
263 6bf9fd43 Avi Kivity
    for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
264 6bf9fd43 Avi Kivity
        /* All entries must be sorted by offset.  */
265 6bf9fd43 Avi Kivity
        assert(pio->offset >= off_last);
266 6bf9fd43 Avi Kivity
        off_last = pio->offset;
267 6bf9fd43 Avi Kivity
268 6bf9fd43 Avi Kivity
        /* If we see a hole, break the region.  */
269 6bf9fd43 Avi Kivity
        if (off_last > off_high) {
270 6bf9fd43 Avi Kivity
            portio_list_add_1(piolist, pio_start, count, start, off_low,
271 6bf9fd43 Avi Kivity
                              off_high);
272 6bf9fd43 Avi Kivity
            /* ... and start collecting anew.  */
273 6bf9fd43 Avi Kivity
            pio_start = pio;
274 6bf9fd43 Avi Kivity
            off_low = off_last;
275 6bf9fd43 Avi Kivity
            off_high = off_low + pio->len;
276 6bf9fd43 Avi Kivity
            count = 0;
277 6bf9fd43 Avi Kivity
        } else if (off_last + pio->len > off_high) {
278 6bf9fd43 Avi Kivity
            off_high = off_last + pio->len;
279 6bf9fd43 Avi Kivity
        }
280 6bf9fd43 Avi Kivity
    }
281 6bf9fd43 Avi Kivity
282 6bf9fd43 Avi Kivity
    /* There will always be an open sub-list.  */
283 6bf9fd43 Avi Kivity
    portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
284 6bf9fd43 Avi Kivity
}
285 6bf9fd43 Avi Kivity
286 6bf9fd43 Avi Kivity
void portio_list_del(PortioList *piolist)
287 6bf9fd43 Avi Kivity
{
288 b40acf99 Jan Kiszka
    MemoryRegionPortioList *mrpio;
289 6bf9fd43 Avi Kivity
    unsigned i;
290 6bf9fd43 Avi Kivity
291 6bf9fd43 Avi Kivity
    for (i = 0; i < piolist->nr; ++i) {
292 b40acf99 Jan Kiszka
        mrpio = container_of(piolist->regions[i], MemoryRegionPortioList, mr);
293 b40acf99 Jan Kiszka
        memory_region_del_subregion(piolist->address_space, &mrpio->mr);
294 b40acf99 Jan Kiszka
        memory_region_destroy(&mrpio->mr);
295 b40acf99 Jan Kiszka
        g_free(mrpio);
296 6bf9fd43 Avi Kivity
        piolist->regions[i] = NULL;
297 6bf9fd43 Avi Kivity
    }
298 6bf9fd43 Avi Kivity
}