You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ioport.c 9.0KB

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