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.
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
];
56 static IOPortReadFunc default_ioport_readb
, default_ioport_readw
, default_ioport_readl
;
57 static IOPortWriteFunc default_ioport_writeb
, default_ioport_writew
, default_ioport_writel
;
59 static uint32_t ioport_read(int index
, uint32_t address
)
61 static IOPortReadFunc
* const default_func
[3] = {
66 IOPortReadFunc
*func
= ioport_read_table
[index
][address
];
68 func
= default_func
[index
];
69 return func(ioport_opaque
[address
], address
);
72 static void ioport_write(int index
, uint32_t address
, uint32_t data
)
74 static IOPortWriteFunc
* const default_func
[3] = {
75 default_ioport_writeb
,
76 default_ioport_writew
,
79 IOPortWriteFunc
*func
= ioport_write_table
[index
][address
];
81 func
= default_func
[index
];
82 func(ioport_opaque
[address
], address
, data
);
85 static uint32_t default_ioport_readb(void *opaque
, uint32_t address
)
87 LOG_UNUSED_IOPORT("unused inb: port=0x%04"PRIx32
"\n", address
);
91 static void default_ioport_writeb(void *opaque
, uint32_t address
, uint32_t data
)
93 LOG_UNUSED_IOPORT("unused outb: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
97 /* default is to make two byte accesses */
98 static uint32_t default_ioport_readw(void *opaque
, uint32_t address
)
101 data
= ioport_read(0, address
);
102 address
= (address
+ 1) & IOPORTS_MASK
;
103 data
|= ioport_read(0, address
) << 8;
107 static void default_ioport_writew(void *opaque
, uint32_t address
, uint32_t data
)
109 ioport_write(0, address
, data
& 0xff);
110 address
= (address
+ 1) & IOPORTS_MASK
;
111 ioport_write(0, address
, (data
>> 8) & 0xff);
114 static uint32_t default_ioport_readl(void *opaque
, uint32_t address
)
116 LOG_UNUSED_IOPORT("unused inl: port=0x%04"PRIx32
"\n", address
);
120 static void default_ioport_writel(void *opaque
, uint32_t address
, uint32_t data
)
122 LOG_UNUSED_IOPORT("unused outl: port=0x%04"PRIx32
" data=0x%02"PRIx32
"\n",
126 static int ioport_bsize(int size
, int *bsize
)
130 } else if (size
== 2) {
132 } else if (size
== 4) {
140 /* size is the word size in byte */
141 int register_ioport_read(pio_addr_t start
, int length
, int size
,
142 IOPortReadFunc
*func
, void *opaque
)
146 if (ioport_bsize(size
, &bsize
)) {
147 hw_error("register_ioport_read: invalid size");
150 for(i
= start
; i
< start
+ length
; ++i
) {
151 ioport_read_table
[bsize
][i
] = func
;
152 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
153 hw_error("register_ioport_read: invalid opaque for address 0x%x",
155 ioport_opaque
[i
] = opaque
;
160 /* size is the word size in byte */
161 int register_ioport_write(pio_addr_t start
, int length
, int size
,
162 IOPortWriteFunc
*func
, void *opaque
)
166 if (ioport_bsize(size
, &bsize
)) {
167 hw_error("register_ioport_write: invalid size");
170 for(i
= start
; i
< start
+ length
; ++i
) {
171 ioport_write_table
[bsize
][i
] = func
;
172 if (ioport_opaque
[i
] != NULL
&& ioport_opaque
[i
] != opaque
)
173 hw_error("register_ioport_write: invalid opaque for address 0x%x",
175 ioport_opaque
[i
] = opaque
;
180 static uint32_t ioport_readb_thunk(void *opaque
, uint32_t addr
)
182 IORange
*ioport
= opaque
;
185 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 1, &data
);
189 static uint32_t ioport_readw_thunk(void *opaque
, uint32_t addr
)
191 IORange
*ioport
= opaque
;
194 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 2, &data
);
198 static uint32_t ioport_readl_thunk(void *opaque
, uint32_t addr
)
200 IORange
*ioport
= opaque
;
203 ioport
->ops
->read(ioport
, addr
- ioport
->base
, 4, &data
);
207 static void ioport_writeb_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
209 IORange
*ioport
= opaque
;
211 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 1, data
);
214 static void ioport_writew_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
216 IORange
*ioport
= opaque
;
218 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 2, data
);
221 static void ioport_writel_thunk(void *opaque
, uint32_t addr
, uint32_t data
)
223 IORange
*ioport
= opaque
;
225 ioport
->ops
->write(ioport
, addr
- ioport
->base
, 4, data
);
228 void ioport_register(IORange
*ioport
)
230 register_ioport_read(ioport
->base
, ioport
->len
, 1,
231 ioport_readb_thunk
, ioport
);
232 register_ioport_read(ioport
->base
, ioport
->len
, 2,
233 ioport_readw_thunk
, ioport
);
234 register_ioport_read(ioport
->base
, ioport
->len
, 4,
235 ioport_readl_thunk
, ioport
);
236 register_ioport_write(ioport
->base
, ioport
->len
, 1,
237 ioport_writeb_thunk
, ioport
);
238 register_ioport_write(ioport
->base
, ioport
->len
, 2,
239 ioport_writew_thunk
, ioport
);
240 register_ioport_write(ioport
->base
, ioport
->len
, 4,
241 ioport_writel_thunk
, ioport
);
244 void isa_unassign_ioport(pio_addr_t start
, int length
)
248 for(i
= start
; i
< start
+ length
; i
++) {
249 ioport_read_table
[0][i
] = NULL
;
250 ioport_read_table
[1][i
] = NULL
;
251 ioport_read_table
[2][i
] = NULL
;
253 ioport_write_table
[0][i
] = NULL
;
254 ioport_write_table
[1][i
] = NULL
;
255 ioport_write_table
[2][i
] = NULL
;
257 ioport_opaque
[i
] = NULL
;
261 bool isa_is_ioport_assigned(pio_addr_t start
)
263 return (ioport_read_table
[0][start
] || ioport_write_table
[0][start
] ||
264 ioport_read_table
[1][start
] || ioport_write_table
[1][start
] ||
265 ioport_read_table
[2][start
] || ioport_write_table
[2][start
]);
268 /***********************************************************/
270 void cpu_outb(pio_addr_t addr
, uint8_t val
)
272 LOG_IOPORT("outb: %04"FMT_pioaddr
" %02"PRIx8
"\n", addr
, val
);
273 trace_cpu_out(addr
, val
);
274 ioport_write(0, addr
, val
);
277 void cpu_outw(pio_addr_t addr
, uint16_t val
)
279 LOG_IOPORT("outw: %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
280 trace_cpu_out(addr
, val
);
281 ioport_write(1, addr
, val
);
284 void cpu_outl(pio_addr_t addr
, uint32_t val
)
286 LOG_IOPORT("outl: %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
287 trace_cpu_out(addr
, val
);
288 ioport_write(2, addr
, val
);
291 uint8_t cpu_inb(pio_addr_t addr
)
294 val
= ioport_read(0, addr
);
295 trace_cpu_in(addr
, val
);
296 LOG_IOPORT("inb : %04"FMT_pioaddr
" %02"PRIx8
"\n", addr
, val
);
300 uint16_t cpu_inw(pio_addr_t addr
)
303 val
= ioport_read(1, addr
);
304 trace_cpu_in(addr
, val
);
305 LOG_IOPORT("inw : %04"FMT_pioaddr
" %04"PRIx16
"\n", addr
, val
);
309 uint32_t cpu_inl(pio_addr_t addr
)
312 val
= ioport_read(2, addr
);
313 trace_cpu_in(addr
, val
);
314 LOG_IOPORT("inl : %04"FMT_pioaddr
" %08"PRIx32
"\n", addr
, val
);
318 void portio_list_init(PortioList
*piolist
,
319 const MemoryRegionPortio
*callbacks
,
320 void *opaque
, const char *name
)
324 while (callbacks
[n
].size
) {
328 piolist
->ports
= callbacks
;
330 piolist
->regions
= g_new0(MemoryRegion
*, n
);
331 piolist
->address_space
= NULL
;
332 piolist
->opaque
= opaque
;
333 piolist
->name
= name
;
336 void portio_list_destroy(PortioList
*piolist
)
338 g_free(piolist
->regions
);
341 static void portio_list_add_1(PortioList
*piolist
,
342 const MemoryRegionPortio
*pio_init
,
343 unsigned count
, unsigned start
,
344 unsigned off_low
, unsigned off_high
)
346 MemoryRegionPortio
*pio
;
347 MemoryRegionOps
*ops
;
348 MemoryRegion
*region
;
351 /* Copy the sub-list and null-terminate it. */
352 pio
= g_new(MemoryRegionPortio
, count
+ 1);
353 memcpy(pio
, pio_init
, sizeof(MemoryRegionPortio
) * count
);
354 memset(pio
+ count
, 0, sizeof(MemoryRegionPortio
));
356 /* Adjust the offsets to all be zero-based for the region. */
357 for (i
= 0; i
< count
; ++i
) {
358 pio
[i
].offset
-= off_low
;
361 ops
= g_new0(MemoryRegionOps
, 1);
362 ops
->old_portio
= pio
;
364 region
= g_new(MemoryRegion
, 1);
365 memory_region_init_io(region
, ops
, piolist
->opaque
, piolist
->name
,
367 memory_region_set_offset(region
, start
+ off_low
);
368 memory_region_add_subregion(piolist
->address_space
,
369 start
+ off_low
, region
);
370 piolist
->regions
[piolist
->nr
++] = region
;
373 void portio_list_add(PortioList
*piolist
,
374 MemoryRegion
*address_space
,
377 const MemoryRegionPortio
*pio
, *pio_start
= piolist
->ports
;
378 unsigned int off_low
, off_high
, off_last
, count
;
380 piolist
->address_space
= address_space
;
382 /* Handle the first entry specially. */
383 off_last
= off_low
= pio_start
->offset
;
384 off_high
= off_low
+ pio_start
->len
;
387 for (pio
= pio_start
+ 1; pio
->size
!= 0; pio
++, count
++) {
388 /* All entries must be sorted by offset. */
389 assert(pio
->offset
>= off_last
);
390 off_last
= pio
->offset
;
392 /* If we see a hole, break the region. */
393 if (off_last
> off_high
) {
394 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
,
396 /* ... and start collecting anew. */
399 off_high
= off_low
+ pio
->len
;
401 } else if (off_last
+ pio
->len
> off_high
) {
402 off_high
= off_last
+ pio
->len
;
406 /* There will always be an open sub-list. */
407 portio_list_add_1(piolist
, pio_start
, count
, start
, off_low
, off_high
);
410 void portio_list_del(PortioList
*piolist
)
415 for (i
= 0; i
< piolist
->nr
; ++i
) {
416 mr
= piolist
->regions
[i
];
417 memory_region_del_subregion(piolist
->address_space
, mr
);
418 memory_region_destroy(mr
);
419 g_free((MemoryRegionOps
*)mr
->ops
);
421 piolist
->regions
[i
] = NULL
;