ioport.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * QEMU System Emulator
  3. *
  4. * Copyright (c) 2003-2008 Fabrice Bellard
  5. *
  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:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  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
  22. * THE SOFTWARE.
  23. */
  24. /*
  25. * splitted out ioport related stuffs from vl.c.
  26. */
  27. #include "exec/ioport.h"
  28. #include "trace.h"
  29. #include "exec/memory.h"
  30. #include "exec/address-spaces.h"
  31. //#define DEBUG_IOPORT
  32. #ifdef DEBUG_IOPORT
  33. # define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
  34. #else
  35. # define LOG_IOPORT(...) do { } while (0)
  36. #endif
  37. typedef struct MemoryRegionPortioList {
  38. MemoryRegion mr;
  39. void *portio_opaque;
  40. MemoryRegionPortio ports[];
  41. } MemoryRegionPortioList;
  42. static uint64_t unassigned_io_read(void *opaque, hwaddr addr, unsigned size)
  43. {
  44. return -1ULL;
  45. }
  46. static void unassigned_io_write(void *opaque, hwaddr addr, uint64_t val,
  47. unsigned size)
  48. {
  49. }
  50. const MemoryRegionOps unassigned_io_ops = {
  51. .read = unassigned_io_read,
  52. .write = unassigned_io_write,
  53. .endianness = DEVICE_NATIVE_ENDIAN,
  54. };
  55. void cpu_outb(pio_addr_t addr, uint8_t val)
  56. {
  57. LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
  58. trace_cpu_out(addr, val);
  59. address_space_write(&address_space_io, addr, &val, 1);
  60. }
  61. void cpu_outw(pio_addr_t addr, uint16_t val)
  62. {
  63. uint8_t buf[2];
  64. LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
  65. trace_cpu_out(addr, val);
  66. stw_p(buf, val);
  67. address_space_write(&address_space_io, addr, buf, 2);
  68. }
  69. void cpu_outl(pio_addr_t addr, uint32_t val)
  70. {
  71. uint8_t buf[4];
  72. LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
  73. trace_cpu_out(addr, val);
  74. stl_p(buf, val);
  75. address_space_write(&address_space_io, addr, buf, 4);
  76. }
  77. uint8_t cpu_inb(pio_addr_t addr)
  78. {
  79. uint8_t val;
  80. address_space_read(&address_space_io, addr, &val, 1);
  81. trace_cpu_in(addr, val);
  82. LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
  83. return val;
  84. }
  85. uint16_t cpu_inw(pio_addr_t addr)
  86. {
  87. uint8_t buf[2];
  88. uint16_t val;
  89. address_space_read(&address_space_io, addr, buf, 2);
  90. val = lduw_p(buf);
  91. trace_cpu_in(addr, val);
  92. LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
  93. return val;
  94. }
  95. uint32_t cpu_inl(pio_addr_t addr)
  96. {
  97. uint8_t buf[4];
  98. uint32_t val;
  99. address_space_read(&address_space_io, addr, buf, 4);
  100. val = ldl_p(buf);
  101. trace_cpu_in(addr, val);
  102. LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
  103. return val;
  104. }
  105. void portio_list_init(PortioList *piolist,
  106. Object *owner,
  107. const MemoryRegionPortio *callbacks,
  108. void *opaque, const char *name)
  109. {
  110. unsigned n = 0;
  111. while (callbacks[n].size) {
  112. ++n;
  113. }
  114. piolist->ports = callbacks;
  115. piolist->nr = 0;
  116. piolist->regions = g_new0(MemoryRegion *, n);
  117. piolist->address_space = NULL;
  118. piolist->opaque = opaque;
  119. piolist->owner = owner;
  120. piolist->name = name;
  121. piolist->flush_coalesced_mmio = false;
  122. }
  123. void portio_list_set_flush_coalesced(PortioList *piolist)
  124. {
  125. piolist->flush_coalesced_mmio = true;
  126. }
  127. void portio_list_destroy(PortioList *piolist)
  128. {
  129. g_free(piolist->regions);
  130. }
  131. static const MemoryRegionPortio *find_portio(MemoryRegionPortioList *mrpio,
  132. uint64_t offset, unsigned size,
  133. bool write)
  134. {
  135. const MemoryRegionPortio *mrp;
  136. for (mrp = mrpio->ports; mrp->size; ++mrp) {
  137. if (offset >= mrp->offset && offset < mrp->offset + mrp->len &&
  138. size == mrp->size &&
  139. (write ? (bool)mrp->write : (bool)mrp->read)) {
  140. return mrp;
  141. }
  142. }
  143. return NULL;
  144. }
  145. static uint64_t portio_read(void *opaque, hwaddr addr, unsigned size)
  146. {
  147. MemoryRegionPortioList *mrpio = opaque;
  148. const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, false);
  149. uint64_t data;
  150. data = ((uint64_t)1 << (size * 8)) - 1;
  151. if (mrp) {
  152. data = mrp->read(mrpio->portio_opaque, mrp->base + addr);
  153. } else if (size == 2) {
  154. mrp = find_portio(mrpio, addr, 1, false);
  155. assert(mrp);
  156. data = mrp->read(mrpio->portio_opaque, mrp->base + addr) |
  157. (mrp->read(mrpio->portio_opaque, mrp->base + addr + 1) << 8);
  158. }
  159. return data;
  160. }
  161. static void portio_write(void *opaque, hwaddr addr, uint64_t data,
  162. unsigned size)
  163. {
  164. MemoryRegionPortioList *mrpio = opaque;
  165. const MemoryRegionPortio *mrp = find_portio(mrpio, addr, size, true);
  166. if (mrp) {
  167. mrp->write(mrpio->portio_opaque, mrp->base + addr, data);
  168. } else if (size == 2) {
  169. mrp = find_portio(mrpio, addr, 1, true);
  170. assert(mrp);
  171. mrp->write(mrpio->portio_opaque, mrp->base + addr, data & 0xff);
  172. mrp->write(mrpio->portio_opaque, mrp->base + addr + 1, data >> 8);
  173. }
  174. }
  175. static const MemoryRegionOps portio_ops = {
  176. .read = portio_read,
  177. .write = portio_write,
  178. .endianness = DEVICE_LITTLE_ENDIAN,
  179. .valid.unaligned = true,
  180. .impl.unaligned = true,
  181. };
  182. static void portio_list_add_1(PortioList *piolist,
  183. const MemoryRegionPortio *pio_init,
  184. unsigned count, unsigned start,
  185. unsigned off_low, unsigned off_high)
  186. {
  187. MemoryRegionPortioList *mrpio;
  188. unsigned i;
  189. /* Copy the sub-list and null-terminate it. */
  190. mrpio = g_malloc0(sizeof(MemoryRegionPortioList) +
  191. sizeof(MemoryRegionPortio) * (count + 1));
  192. mrpio->portio_opaque = piolist->opaque;
  193. memcpy(mrpio->ports, pio_init, sizeof(MemoryRegionPortio) * count);
  194. memset(mrpio->ports + count, 0, sizeof(MemoryRegionPortio));
  195. /* Adjust the offsets to all be zero-based for the region. */
  196. for (i = 0; i < count; ++i) {
  197. mrpio->ports[i].offset -= off_low;
  198. mrpio->ports[i].base = start + off_low;
  199. }
  200. /*
  201. * Use an alias so that the callback is called with an absolute address,
  202. * rather than an offset relative to to start + off_low.
  203. */
  204. memory_region_init_io(&mrpio->mr, piolist->owner, &portio_ops, mrpio,
  205. piolist->name, off_high - off_low);
  206. if (piolist->flush_coalesced_mmio) {
  207. memory_region_set_flush_coalesced(&mrpio->mr);
  208. }
  209. memory_region_add_subregion(piolist->address_space,
  210. start + off_low, &mrpio->mr);
  211. piolist->regions[piolist->nr] = &mrpio->mr;
  212. ++piolist->nr;
  213. }
  214. void portio_list_add(PortioList *piolist,
  215. MemoryRegion *address_space,
  216. uint32_t start)
  217. {
  218. const MemoryRegionPortio *pio, *pio_start = piolist->ports;
  219. unsigned int off_low, off_high, off_last, count;
  220. piolist->address_space = address_space;
  221. /* Handle the first entry specially. */
  222. off_last = off_low = pio_start->offset;
  223. off_high = off_low + pio_start->len;
  224. count = 1;
  225. for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
  226. /* All entries must be sorted by offset. */
  227. assert(pio->offset >= off_last);
  228. off_last = pio->offset;
  229. /* If we see a hole, break the region. */
  230. if (off_last > off_high) {
  231. portio_list_add_1(piolist, pio_start, count, start, off_low,
  232. off_high);
  233. /* ... and start collecting anew. */
  234. pio_start = pio;
  235. off_low = off_last;
  236. off_high = off_low + pio->len;
  237. count = 0;
  238. } else if (off_last + pio->len > off_high) {
  239. off_high = off_last + pio->len;
  240. }
  241. }
  242. /* There will always be an open sub-list. */
  243. portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
  244. }
  245. void portio_list_del(PortioList *piolist)
  246. {
  247. MemoryRegionPortioList *mrpio;
  248. unsigned i;
  249. for (i = 0; i < piolist->nr; ++i) {
  250. mrpio = container_of(piolist->regions[i], MemoryRegionPortioList, mr);
  251. memory_region_del_subregion(piolist->address_space, &mrpio->mr);
  252. memory_region_destroy(&mrpio->mr);
  253. g_free(mrpio);
  254. piolist->regions[i] = NULL;
  255. }
  256. }