ioport.c 9.0 KB

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