4 * Copyright (c) 2003-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
25 * splitted out ioport related stuffs from vl.c.
28 #include "exec/ioport.h"
30 #include "exec/memory.h"
31 #include "exec/address-spaces.h"
33 /***********************************************************/
36 //#define DEBUG_UNUSED_IOPORT
37 //#define DEBUG_IOPORT
39 #ifdef DEBUG_UNUSED_IOPORT
40 # define LOG_UNUSED_IOPORT(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
42 # define LOG_UNUSED_IOPORT(fmt, ...) do{ } while (0)
46 # define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
48 # define LOG_IOPORT(...) do { } while (0)
51 typedef struct MemoryRegionPortioList
{
54 MemoryRegionPortio ports
[];
55 } MemoryRegionPortioList
;
57 /* XXX: use a two level table to limit memory usage */
59 static void *ioport_opaque
[MAX_IOPORTS
];
60 static IOPortReadFunc
*ioport_read_table
[3][MAX_IOPORTS
];
61 static IOPortWriteFunc
*ioport_write_table
[3][MAX_IOPORTS
];
62 static IOPortDestructor
*ioport_destructor_table
[MAX_IOPORTS
];
64 static IOPortReadFunc default_ioport_readb
, default_ioport_readw
, default_ioport_readl
;
65 static IOPortWriteFunc default_ioport_writeb
, default_ioport_writew
, default_ioport_writel
;
67 static uint32_t ioport_read(int index
, uint32_t address
)
69 static IOPortReadFunc
* const default_func
[3] = {
74 IOPortReadFunc
*func
= ioport_read_table
[index
][address
];
76 func
= default_func
[index
];
77 return func(ioport_opaque
[address
], address
);
80 static void ioport_write(int index
, uint32_t address
, uint32_t data
)
82 static IOPortWriteFunc
* const default_func
[3] = {
83 default_ioport_writeb
,
84 default_ioport_writew
,
87 IOPortWriteFunc
*func
= ioport_write_table
[index
][address
];
89 func
= default_func
[index
];
90 func(ioport_opaque
[address
], address
, data
);
93 static uint32_t default_ioport_readb(void *opaque
, uint32_t address
)
95 LOG_UNUSED_IOPORT("unused inb: port=0x%04"PRIx32
"\n", address
);
99 static void default_ioport_writeb(void *opaque
, uint32_t address
, uint32_t data
)
101 LOG_UNUSED_IOPORT("unused outb: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
105 /* default is to make two byte accesses */
106 static uint32_t default_ioport_readw(void *opaque
, uint32_t address
)
109 data
= ioport_read(0, address
);
110 address
= (address
+ 1) & IOPORTS_MASK
;
111 data
|= ioport_read(0, address
) << 8;
115 static void default_ioport_writew(void *opaque
, uint32_t address
, uint32_t data
)
117 ioport_write(0, address
, data
& 0xff);
118 address
= (address
+ 1) & IOPORTS_MASK
;
119 ioport_write(0, address
, (data
>> 8) & 0xff);
122 static uint32_t default_ioport_readl(void *opaque
, uint32_t address
)
124 LOG_UNUSED_IOPORT("unused inl: port=0x%04"PRIx32
"\n", address
);
128 static void default_ioport_writel(void *opaque
, uint32_t address
, uint32_t data
)
130 LOG_UNUSED_IOPORT("unused outl: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
134 static int ioport_bsize(int size
, int *bsize
)
138 } else if (size
== 2) {
140 } else if (size
== 4) {
148 /* size is the word size in byte */
149 static int register_ioport_read(pio_addr_t start
, int length
, int size
,
150 IOPortReadFunc
*func
, void *opaque
)
154 if (ioport_bsize(size
, &bsize
)) {
155 hw_error("register_ioport_read: invalid size");
158 for(i
= start
; i
< start
+ length
; ++i
) {
159 ioport_read_table
[bsize
][i
] = func
;
160 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
161 hw_error("register_ioport_read: invalid opaque for address 0x%x",
163 ioport_opaque
[i
] = opaque
;
168 /* size is the word size in byte */
169 static int register_ioport_write(pio_addr_t start
, int length
, int size
,
170 IOPortWriteFunc
*func
, void *opaque
)
174 if (ioport_bsize(size
, &bsize
)) {
175 hw_error("register_ioport_write: invalid size");
178 for(i
= start
; i
< start
+ length
; ++i
) {
179 ioport_write_table
[bsize
][i
] = func
;
180 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
181 hw_error("register_ioport_write: invalid opaque for address 0x%x",
183 ioport_opaque
[i
] = opaque
;
188 static uint32_t ioport_readb_thunk(void *opaque
, uint32_t addr
)
190 IORange
*ioport
= opaque
;
193 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 1, &data
);
197 static uint32_t ioport_readw_thunk(void *opaque
, uint32_t addr
)
199 IORange
*ioport
= opaque
;
202 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 2, &data
);
206 static uint32_t ioport_readl_thunk(void *opaque
, uint32_t addr
)
208 IORange
*ioport
= opaque
;
211 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 4, &data
);
215 static void ioport_writeb_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
217 IORange
*ioport
= opaque
;
219 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 1, data
);
222 static void ioport_writew_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
224 IORange
*ioport
= opaque
;
226 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 2, data
);
229 static void ioport_writel_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
231 IORange
*ioport
= opaque
;
233 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 4, data
);
236 static void iorange_destructor_thunk(void *opaque
)
238 IORange
*iorange
= opaque
;
240 if (iorange
->ops
->destructor
) {
241 iorange
->ops
->destructor(iorange
);
245 void ioport_register(IORange
*ioport
)
247 register_ioport_read(ioport
->base
, ioport
->len
, 1,
248 ioport_readb_thunk
, ioport
);
249 register_ioport_read(ioport
->base
, ioport
->len
, 2,
250 ioport_readw_thunk
, ioport
);
251 register_ioport_read(ioport
->base
, ioport
->len
, 4,
252 ioport_readl_thunk
, ioport
);
253 register_ioport_write(ioport
->base
, ioport
->len
, 1,
254 ioport_writeb_thunk
, ioport
);
255 register_ioport_write(ioport
->base
, ioport
->len
, 2,
256 ioport_writew_thunk
, ioport
);
257 register_ioport_write(ioport
->base
, ioport
->len
, 4,
258 ioport_writel_thunk
, ioport
);
259 ioport_destructor_table
[ioport
->base
] = iorange_destructor_thunk
;
262 void isa_unassign_ioport(pio_addr_t start
, int length
)
266 if (ioport_destructor_table
[start
]) {
267 ioport_destructor_table
[start
](ioport_opaque
[start
]);
268 ioport_destructor_table
[start
] = NULL
;
270 for(i
= start
; i
< start
+ length
; i
++) {
271 ioport_read_table
[0][i
] = NULL
;
272 ioport_read_table
[1][i
] = NULL
;
273 ioport_read_table
[2][i
] = NULL
;
275 ioport_write_table
[0][i
] = NULL
;
276 ioport_write_table
[1][i
] = NULL
;
277 ioport_write_table
[2][i
] = NULL
;
279 ioport_opaque
[i
] = NULL
;
283 /***********************************************************/
285 void cpu_outb(pio_addr_t addr
, uint8_t val
)
287 LOG_IOPORT("outb: %04"FMT_pioaddr
" %02"PRIx8
"\n", addr
, val
);
288 trace_cpu_out(addr
, val
);
289 address_space_write(&address_space_io
, addr
, &val
, 1);
292 void cpu_outw(pio_addr_t addr
, uint16_t val
)
296 LOG_IOPORT("outw: %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
297 trace_cpu_out(addr
, val
);
299 address_space_write(&address_space_io
, addr
, buf
, 2);
302 void cpu_outl(pio_addr_t addr
, uint32_t val
)
306 LOG_IOPORT("outl: %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
307 trace_cpu_out(addr
, val
);
309 address_space_write(&address_space_io
, addr
, buf
, 4);
312 uint8_t cpu_inb(pio_addr_t addr
)
316 address_space_read(&address_space_io
, addr
, &val
, 1);
317 trace_cpu_in(addr
, val
);
318 LOG_IOPORT("inb : %04"FMT_pioaddr
" %02"PRIx8
"\n", addr
, val
);
322 uint16_t cpu_inw(pio_addr_t addr
)
327 address_space_read(&address_space_io
, addr
, buf
, 2);
329 trace_cpu_in(addr
, val
);
330 LOG_IOPORT("inw : %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
334 uint32_t cpu_inl(pio_addr_t addr
)
339 address_space_read(&address_space_io
, addr
, buf
, 4);
341 trace_cpu_in(addr
, val
);
342 LOG_IOPORT("inl : %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
346 void portio_list_init(PortioList
*piolist
,
347 const MemoryRegionPortio
*callbacks
,
348 void *opaque
, const char *name
)
352 while (callbacks
[n
].size
) {
356 piolist
->ports
= callbacks
;
358 piolist
->regions
= g_new0(MemoryRegion
*, n
);
359 piolist
->address_space
= NULL
;
360 piolist
->opaque
= opaque
;
361 piolist
->name
= name
;
364 void portio_list_destroy(PortioList
*piolist
)
366 g_free(piolist
->regions
);
369 static const MemoryRegionPortio
*find_portio(MemoryRegionPortioList
*mrpio
,
370 uint64_t offset
, unsigned size
,
373 const MemoryRegionPortio
*mrp
;
375 for (mrp
= mrpio
->ports
; mrp
->size
; ++mrp
) {
376 if (offset
>= mrp
->offset
&& offset
< mrp
->offset
+ mrp
->len
&&
378 (write
? (bool)mrp
->write
: (bool)mrp
->read
)) {
385 static uint64_t portio_read(void *opaque
, hwaddr addr
, unsigned size
)
387 MemoryRegionPortioList
*mrpio
= opaque
;
388 const MemoryRegionPortio
*mrp
= find_portio(mrpio
, addr
, size
, false);
391 data
= ((uint64_t)1 << (size
* 8)) - 1;
393 data
= mrp
->read(mrpio
->portio_opaque
, mrp
->base
+ addr
);
394 } else if (size
== 2) {
395 mrp
= find_portio(mrpio
, addr
, 1, false);
397 data
= mrp
->read(mrpio
->portio_opaque
, mrp
->base
+ addr
) |
398 (mrp
->read(mrpio
->portio_opaque
, mrp
->base
+ addr
+ 1) << 8);
403 static void portio_write(void *opaque
, hwaddr addr
, uint64_t data
,
406 MemoryRegionPortioList
*mrpio
= opaque
;
407 const MemoryRegionPortio
*mrp
= find_portio(mrpio
, addr
, size
, true);
410 mrp
->write(mrpio
->portio_opaque
, mrp
->base
+ addr
, data
);
411 } else if (size
== 2) {
412 mrp
= find_portio(mrpio
, addr
, 1, true);
414 mrp
->write(mrpio
->portio_opaque
, mrp
->base
+ addr
, data
& 0xff);
415 mrp
->write(mrpio
->portio_opaque
, mrp
->base
+ addr
+ 1, data
>> 8);
419 static const MemoryRegionOps portio_ops
= {
421 .write
= portio_write
,
422 .endianness
= DEVICE_LITTLE_ENDIAN
,
423 .valid
.unaligned
= true,
424 .impl
.unaligned
= true,
427 static void portio_list_add_1(PortioList
*piolist
,
428 const MemoryRegionPortio
*pio_init
,
429 unsigned count
, unsigned start
,
430 unsigned off_low
, unsigned off_high
)
432 MemoryRegionPortioList
*mrpio
;
435 /* Copy the sub-list and null-terminate it. */
436 mrpio
= g_malloc0(sizeof(MemoryRegionPortioList
) +
437 sizeof(MemoryRegionPortio
) * (count
+ 1));
438 mrpio
->portio_opaque
= piolist
->opaque
;
439 memcpy(mrpio
->ports
, pio_init
, sizeof(MemoryRegionPortio
) * count
);
440 memset(mrpio
->ports
+ count
, 0, sizeof(MemoryRegionPortio
));
442 /* Adjust the offsets to all be zero-based for the region. */
443 for (i
= 0; i
< count
; ++i
) {
444 mrpio
->ports
[i
].offset
-= off_low
;
445 mrpio
->ports
[i
].base
= start
+ off_low
;
449 * Use an alias so that the callback is called with an absolute address,
450 * rather than an offset relative to to start + off_low.
452 memory_region_init_io(&mrpio
->mr
, &portio_ops
, mrpio
, piolist
->name
,
454 memory_region_add_subregion(piolist
->address_space
,
455 start
+ off_low
, &mrpio
->mr
);
456 piolist
->regions
[piolist
->nr
] = &mrpio
->mr
;
460 void portio_list_add(PortioList
*piolist
,
461 MemoryRegion
*address_space
,
464 const MemoryRegionPortio
*pio
, *pio_start
= piolist
->ports
;
465 unsigned int off_low
, off_high
, off_last
, count
;
467 piolist
->address_space
= address_space
;
469 /* Handle the first entry specially. */
470 off_last
= off_low
= pio_start
->offset
;
471 off_high
= off_low
+ pio_start
->len
;
474 for (pio
= pio_start
+ 1; pio
->size
!= 0; pio
++, count
++) {
475 /* All entries must be sorted by offset. */
476 assert(pio
->offset
>= off_last
);
477 off_last
= pio
->offset
;
479 /* If we see a hole, break the region. */
480 if (off_last
> off_high
) {
481 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
,
483 /* ... and start collecting anew. */
486 off_high
= off_low
+ pio
->len
;
488 } else if (off_last
+ pio
->len
> off_high
) {
489 off_high
= off_last
+ pio
->len
;
493 /* There will always be an open sub-list. */
494 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
, off_high
);
497 void portio_list_del(PortioList
*piolist
)
499 MemoryRegionPortioList
*mrpio
;
502 for (i
= 0; i
< piolist
->nr
; ++i
) {
503 mrpio
= container_of(piolist
->regions
[i
], MemoryRegionPortioList
, mr
);
504 memory_region_del_subregion(piolist
->address_space
, &mrpio
->mr
);
505 memory_region_destroy(&mrpio
->mr
);
507 piolist
->regions
[i
] = NULL
;