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"
32 /***********************************************************/
35 //#define DEBUG_UNUSED_IOPORT
36 //#define DEBUG_IOPORT
38 #ifdef DEBUG_UNUSED_IOPORT
39 # define LOG_UNUSED_IOPORT(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
41 # define LOG_UNUSED_IOPORT(fmt, ...) do{ } while (0)
45 # define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
47 # define LOG_IOPORT(...) do { } while (0)
50 /* XXX: use a two level table to limit memory usage */
52 static void *ioport_opaque
[MAX_IOPORTS
];
53 static IOPortReadFunc
*ioport_read_table
[3][MAX_IOPORTS
];
54 static IOPortWriteFunc
*ioport_write_table
[3][MAX_IOPORTS
];
55 static IOPortDestructor
*ioport_destructor_table
[MAX_IOPORTS
];
57 static IOPortReadFunc default_ioport_readb
, default_ioport_readw
, default_ioport_readl
;
58 static IOPortWriteFunc default_ioport_writeb
, default_ioport_writew
, default_ioport_writel
;
60 static uint32_t ioport_read(int index
, uint32_t address
)
62 static IOPortReadFunc
* const default_func
[3] = {
67 IOPortReadFunc
*func
= ioport_read_table
[index
][address
];
69 func
= default_func
[index
];
70 return func(ioport_opaque
[address
], address
);
73 static void ioport_write(int index
, uint32_t address
, uint32_t data
)
75 static IOPortWriteFunc
* const default_func
[3] = {
76 default_ioport_writeb
,
77 default_ioport_writew
,
80 IOPortWriteFunc
*func
= ioport_write_table
[index
][address
];
82 func
= default_func
[index
];
83 func(ioport_opaque
[address
], address
, data
);
86 static uint32_t default_ioport_readb(void *opaque
, uint32_t address
)
88 LOG_UNUSED_IOPORT("unused inb: port=0x%04"PRIx32
"\n", address
);
92 static void default_ioport_writeb(void *opaque
, uint32_t address
, uint32_t data
)
94 LOG_UNUSED_IOPORT("unused outb: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
98 /* default is to make two byte accesses */
99 static uint32_t default_ioport_readw(void *opaque
, uint32_t address
)
102 data
= ioport_read(0, address
);
103 address
= (address
+ 1) & IOPORTS_MASK
;
104 data
|= ioport_read(0, address
) << 8;
108 static void default_ioport_writew(void *opaque
, uint32_t address
, uint32_t data
)
110 ioport_write(0, address
, data
& 0xff);
111 address
= (address
+ 1) & IOPORTS_MASK
;
112 ioport_write(0, address
, (data
>> 8) & 0xff);
115 static uint32_t default_ioport_readl(void *opaque
, uint32_t address
)
117 LOG_UNUSED_IOPORT("unused inl: port=0x%04"PRIx32
"\n", address
);
121 static void default_ioport_writel(void *opaque
, uint32_t address
, uint32_t data
)
123 LOG_UNUSED_IOPORT("unused outl: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
127 static int ioport_bsize(int size
, int *bsize
)
131 } else if (size
== 2) {
133 } else if (size
== 4) {
141 /* size is the word size in byte */
142 int register_ioport_read(pio_addr_t start
, int length
, int size
,
143 IOPortReadFunc
*func
, void *opaque
)
147 if (ioport_bsize(size
, &bsize
)) {
148 hw_error("register_ioport_read: invalid size");
151 for(i
= start
; i
< start
+ length
; ++i
) {
152 ioport_read_table
[bsize
][i
] = func
;
153 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
154 hw_error("register_ioport_read: invalid opaque for address 0x%x",
156 ioport_opaque
[i
] = opaque
;
161 /* size is the word size in byte */
162 int register_ioport_write(pio_addr_t start
, int length
, int size
,
163 IOPortWriteFunc
*func
, void *opaque
)
167 if (ioport_bsize(size
, &bsize
)) {
168 hw_error("register_ioport_write: invalid size");
171 for(i
= start
; i
< start
+ length
; ++i
) {
172 ioport_write_table
[bsize
][i
] = func
;
173 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
174 hw_error("register_ioport_write: invalid opaque for address 0x%x",
176 ioport_opaque
[i
] = opaque
;
181 static uint32_t ioport_readb_thunk(void *opaque
, uint32_t addr
)
183 IORange
*ioport
= opaque
;
186 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 1, &data
);
190 static uint32_t ioport_readw_thunk(void *opaque
, uint32_t addr
)
192 IORange
*ioport
= opaque
;
195 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 2, &data
);
199 static uint32_t ioport_readl_thunk(void *opaque
, uint32_t addr
)
201 IORange
*ioport
= opaque
;
204 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 4, &data
);
208 static void ioport_writeb_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
210 IORange
*ioport
= opaque
;
212 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 1, data
);
215 static void ioport_writew_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
217 IORange
*ioport
= opaque
;
219 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 2, data
);
222 static void ioport_writel_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
224 IORange
*ioport
= opaque
;
226 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 4, data
);
229 static void iorange_destructor_thunk(void *opaque
)
231 IORange
*iorange
= opaque
;
233 if (iorange
->ops
->destructor
) {
234 iorange
->ops
->destructor(iorange
);
238 void ioport_register(IORange
*ioport
)
240 register_ioport_read(ioport
->base
, ioport
->len
, 1,
241 ioport_readb_thunk
, ioport
);
242 register_ioport_read(ioport
->base
, ioport
->len
, 2,
243 ioport_readw_thunk
, ioport
);
244 register_ioport_read(ioport
->base
, ioport
->len
, 4,
245 ioport_readl_thunk
, ioport
);
246 register_ioport_write(ioport
->base
, ioport
->len
, 1,
247 ioport_writeb_thunk
, ioport
);
248 register_ioport_write(ioport
->base
, ioport
->len
, 2,
249 ioport_writew_thunk
, ioport
);
250 register_ioport_write(ioport
->base
, ioport
->len
, 4,
251 ioport_writel_thunk
, ioport
);
252 ioport_destructor_table
[ioport
->base
] = iorange_destructor_thunk
;
255 void isa_unassign_ioport(pio_addr_t start
, int length
)
259 if (ioport_destructor_table
[start
]) {
260 ioport_destructor_table
[start
](ioport_opaque
[start
]);
261 ioport_destructor_table
[start
] = NULL
;
263 for(i
= start
; i
< start
+ length
; i
++) {
264 ioport_read_table
[0][i
] = NULL
;
265 ioport_read_table
[1][i
] = NULL
;
266 ioport_read_table
[2][i
] = NULL
;
268 ioport_write_table
[0][i
] = NULL
;
269 ioport_write_table
[1][i
] = NULL
;
270 ioport_write_table
[2][i
] = NULL
;
272 ioport_opaque
[i
] = NULL
;
276 bool isa_is_ioport_assigned(pio_addr_t start
)
278 return (ioport_read_table
[0][start
] || ioport_write_table
[0][start
] ||
279 ioport_read_table
[1][start
] || ioport_write_table
[1][start
] ||
280 ioport_read_table
[2][start
] || ioport_write_table
[2][start
]);
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 ioport_write(0, addr
, val
);
292 void cpu_outw(pio_addr_t addr
, uint16_t val
)
294 LOG_IOPORT("outw: %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
295 trace_cpu_out(addr
, val
);
296 ioport_write(1, addr
, val
);
299 void cpu_outl(pio_addr_t addr
, uint32_t val
)
301 LOG_IOPORT("outl: %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
302 trace_cpu_out(addr
, val
);
303 ioport_write(2, addr
, val
);
306 uint8_t cpu_inb(pio_addr_t addr
)
309 val
= ioport_read(0, addr
);
310 trace_cpu_in(addr
, val
);
311 LOG_IOPORT("inb : %04"FMT_pioaddr
" %02"PRIx8
"\n", addr
, val
);
315 uint16_t cpu_inw(pio_addr_t addr
)
318 val
= ioport_read(1, addr
);
319 trace_cpu_in(addr
, val
);
320 LOG_IOPORT("inw : %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
324 uint32_t cpu_inl(pio_addr_t addr
)
327 val
= ioport_read(2, addr
);
328 trace_cpu_in(addr
, val
);
329 LOG_IOPORT("inl : %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
333 void portio_list_init(PortioList
*piolist
,
334 const MemoryRegionPortio
*callbacks
,
335 void *opaque
, const char *name
)
339 while (callbacks
[n
].size
) {
343 piolist
->ports
= callbacks
;
345 piolist
->regions
= g_new0(MemoryRegion
*, n
);
346 piolist
->aliases
= g_new0(MemoryRegion
*, n
);
347 piolist
->address_space
= NULL
;
348 piolist
->opaque
= opaque
;
349 piolist
->name
= name
;
352 void portio_list_destroy(PortioList
*piolist
)
354 g_free(piolist
->regions
);
355 g_free(piolist
->aliases
);
358 static void portio_list_add_1(PortioList
*piolist
,
359 const MemoryRegionPortio
*pio_init
,
360 unsigned count
, unsigned start
,
361 unsigned off_low
, unsigned off_high
)
363 MemoryRegionPortio
*pio
;
364 MemoryRegionOps
*ops
;
365 MemoryRegion
*region
, *alias
;
368 /* Copy the sub-list and null-terminate it. */
369 pio
= g_new(MemoryRegionPortio
, count
+ 1);
370 memcpy(pio
, pio_init
, sizeof(MemoryRegionPortio
) * count
);
371 memset(pio
+ count
, 0, sizeof(MemoryRegionPortio
));
373 /* Adjust the offsets to all be zero-based for the region. */
374 for (i
= 0; i
< count
; ++i
) {
375 pio
[i
].offset
-= off_low
;
378 ops
= g_new0(MemoryRegionOps
, 1);
379 ops
->old_portio
= pio
;
381 region
= g_new(MemoryRegion
, 1);
382 alias
= g_new(MemoryRegion
, 1);
384 * Use an alias so that the callback is called with an absolute address,
385 * rather than an offset relative to to start + off_low.
387 memory_region_init_io(region
, ops
, piolist
->opaque
, piolist
->name
,
389 memory_region_init_alias(alias
, piolist
->name
,
390 region
, start
+ off_low
, off_high
- off_low
);
391 memory_region_add_subregion(piolist
->address_space
,
392 start
+ off_low
, alias
);
393 piolist
->regions
[piolist
->nr
] = region
;
394 piolist
->aliases
[piolist
->nr
] = alias
;
398 void portio_list_add(PortioList
*piolist
,
399 MemoryRegion
*address_space
,
402 const MemoryRegionPortio
*pio
, *pio_start
= piolist
->ports
;
403 unsigned int off_low
, off_high
, off_last
, count
;
405 piolist
->address_space
= address_space
;
407 /* Handle the first entry specially. */
408 off_last
= off_low
= pio_start
->offset
;
409 off_high
= off_low
+ pio_start
->len
;
412 for (pio
= pio_start
+ 1; pio
->size
!= 0; pio
++, count
++) {
413 /* All entries must be sorted by offset. */
414 assert(pio
->offset
>= off_last
);
415 off_last
= pio
->offset
;
417 /* If we see a hole, break the region. */
418 if (off_last
> off_high
) {
419 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
,
421 /* ... and start collecting anew. */
424 off_high
= off_low
+ pio
->len
;
426 } else if (off_last
+ pio
->len
> off_high
) {
427 off_high
= off_last
+ pio
->len
;
431 /* There will always be an open sub-list. */
432 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
, off_high
);
435 void portio_list_del(PortioList
*piolist
)
437 MemoryRegion
*mr
, *alias
;
440 for (i
= 0; i
< piolist
->nr
; ++i
) {
441 mr
= piolist
->regions
[i
];
442 alias
= piolist
->aliases
[i
];
443 memory_region_del_subregion(piolist
->address_space
, alias
);
444 memory_region_destroy(alias
);
445 memory_region_destroy(mr
);
446 g_free((MemoryRegionOps
*)mr
->ops
);
449 piolist
->regions
[i
] = NULL
;
450 piolist
->aliases
[i
] = NULL
;