1 /* 2 * QEMU educational PCI device 3 * 4 * Copyright (c) 2012-2015 Jiri Slaby 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is 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 THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "hw/pci/pci.h" 27 #include "hw/pci/msi.h" 28 #include "qemu/timer.h" 29 #include "qemu/main-loop.h" /* iothread mutex */ 30 #include "qapi/visitor.h" 31 32 #define EDU(obj) OBJECT_CHECK(EduState, obj, "edu") 33 34 #define FACT_IRQ 0x00000001 35 #define DMA_IRQ 0x00000100 36 37 #define DMA_START 0x40000 38 #define DMA_SIZE 4096 39 40 typedef struct { 41 PCIDevice pdev; 42 MemoryRegion mmio; 43 44 QemuThread thread; 45 QemuMutex thr_mutex; 46 QemuCond thr_cond; 47 bool stopping; 48 49 uint32_t addr4; 50 uint32_t fact; 51 #define EDU_STATUS_COMPUTING 0x01 52 #define EDU_STATUS_IRQFACT 0x80 53 uint32_t status; 54 55 uint32_t irq_status; 56 57 #define EDU_DMA_RUN 0x1 58 #define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1) 59 # define EDU_DMA_FROM_PCI 0 60 # define EDU_DMA_TO_PCI 1 61 #define EDU_DMA_IRQ 0x4 62 struct dma_state { 63 dma_addr_t src; 64 dma_addr_t dst; 65 dma_addr_t cnt; 66 dma_addr_t cmd; 67 } dma; 68 QEMUTimer dma_timer; 69 char dma_buf[DMA_SIZE]; 70 uint64_t dma_mask; 71 } EduState; 72 73 static bool edu_msi_enabled(EduState *edu) 74 { 75 return msi_enabled(&edu->pdev); 76 } 77 78 static void edu_raise_irq(EduState *edu, uint32_t val) 79 { 80 edu->irq_status |= val; 81 if (edu->irq_status) { 82 if (edu_msi_enabled(edu)) { 83 msi_notify(&edu->pdev, 0); 84 } else { 85 pci_set_irq(&edu->pdev, 1); 86 } 87 } 88 } 89 90 static void edu_lower_irq(EduState *edu, uint32_t val) 91 { 92 edu->irq_status &= ~val; 93 94 if (!edu->irq_status && !edu_msi_enabled(edu)) { 95 pci_set_irq(&edu->pdev, 0); 96 } 97 } 98 99 static bool within(uint32_t addr, uint32_t start, uint32_t end) 100 { 101 return start <= addr && addr < end; 102 } 103 104 static void edu_check_range(uint32_t addr, uint32_t size1, uint32_t start, 105 uint32_t size2) 106 { 107 uint32_t end1 = addr + size1; 108 uint32_t end2 = start + size2; 109 110 if (within(addr, start, end2) && 111 end1 > addr && within(end1, start, end2)) { 112 return; 113 } 114 115 hw_error("EDU: DMA range 0x%.8x-0x%.8x out of bounds (0x%.8x-0x%.8x)!", 116 addr, end1 - 1, start, end2 - 1); 117 } 118 119 static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr) 120 { 121 dma_addr_t res = addr & edu->dma_mask; 122 123 if (addr != res) { 124 printf("EDU: clamping DMA %#.16"PRIx64" to %#.16"PRIx64"!\n", addr, res); 125 } 126 127 return res; 128 } 129 130 static void edu_dma_timer(void *opaque) 131 { 132 EduState *edu = opaque; 133 bool raise_irq = false; 134 135 if (!(edu->dma.cmd & EDU_DMA_RUN)) { 136 return; 137 } 138 139 if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) { 140 uint32_t dst = edu->dma.dst; 141 edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE); 142 dst -= DMA_START; 143 pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src), 144 edu->dma_buf + dst, edu->dma.cnt); 145 } else { 146 uint32_t src = edu->dma.src; 147 edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE); 148 src -= DMA_START; 149 pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst), 150 edu->dma_buf + src, edu->dma.cnt); 151 } 152 153 edu->dma.cmd &= ~EDU_DMA_RUN; 154 if (edu->dma.cmd & EDU_DMA_IRQ) { 155 raise_irq = true; 156 } 157 158 if (raise_irq) { 159 edu_raise_irq(edu, DMA_IRQ); 160 } 161 } 162 163 static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma, 164 bool timer) 165 { 166 if (write && (edu->dma.cmd & EDU_DMA_RUN)) { 167 return; 168 } 169 170 if (write) { 171 *dma = *val; 172 } else { 173 *val = *dma; 174 } 175 176 if (timer) { 177 timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); 178 } 179 } 180 181 static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size) 182 { 183 EduState *edu = opaque; 184 uint64_t val = ~0ULL; 185 186 if (size != 4) { 187 return val; 188 } 189 190 switch (addr) { 191 case 0x00: 192 val = 0x010000edu; 193 break; 194 case 0x04: 195 val = edu->addr4; 196 break; 197 case 0x08: 198 qemu_mutex_lock(&edu->thr_mutex); 199 val = edu->fact; 200 qemu_mutex_unlock(&edu->thr_mutex); 201 break; 202 case 0x20: 203 val = atomic_read(&edu->status); 204 break; 205 case 0x24: 206 val = edu->irq_status; 207 break; 208 case 0x80: 209 dma_rw(edu, false, &val, &edu->dma.src, false); 210 break; 211 case 0x88: 212 dma_rw(edu, false, &val, &edu->dma.dst, false); 213 break; 214 case 0x90: 215 dma_rw(edu, false, &val, &edu->dma.cnt, false); 216 break; 217 case 0x98: 218 dma_rw(edu, false, &val, &edu->dma.cmd, false); 219 break; 220 } 221 222 return val; 223 } 224 225 static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, 226 unsigned size) 227 { 228 EduState *edu = opaque; 229 230 if (addr < 0x80 && size != 4) { 231 return; 232 } 233 234 if (addr >= 0x80 && size != 4 && size != 8) { 235 return; 236 } 237 238 switch (addr) { 239 case 0x04: 240 edu->addr4 = ~val; 241 break; 242 case 0x08: 243 if (atomic_read(&edu->status) & EDU_STATUS_COMPUTING) { 244 break; 245 } 246 /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only 247 * set in this function and it is under the iothread mutex. 248 */ 249 qemu_mutex_lock(&edu->thr_mutex); 250 edu->fact = val; 251 atomic_or(&edu->status, EDU_STATUS_COMPUTING); 252 qemu_cond_signal(&edu->thr_cond); 253 qemu_mutex_unlock(&edu->thr_mutex); 254 break; 255 case 0x20: 256 if (val & EDU_STATUS_IRQFACT) { 257 atomic_or(&edu->status, EDU_STATUS_IRQFACT); 258 } else { 259 atomic_and(&edu->status, ~EDU_STATUS_IRQFACT); 260 } 261 break; 262 case 0x60: 263 edu_raise_irq(edu, val); 264 break; 265 case 0x64: 266 edu_lower_irq(edu, val); 267 break; 268 case 0x80: 269 dma_rw(edu, true, &val, &edu->dma.src, false); 270 break; 271 case 0x88: 272 dma_rw(edu, true, &val, &edu->dma.dst, false); 273 break; 274 case 0x90: 275 dma_rw(edu, true, &val, &edu->dma.cnt, false); 276 break; 277 case 0x98: 278 if (!(val & EDU_DMA_RUN)) { 279 break; 280 } 281 dma_rw(edu, true, &val, &edu->dma.cmd, true); 282 break; 283 } 284 } 285 286 static const MemoryRegionOps edu_mmio_ops = { 287 .read = edu_mmio_read, 288 .write = edu_mmio_write, 289 .endianness = DEVICE_NATIVE_ENDIAN, 290 }; 291 292 /* 293 * We purposely use a thread, so that users are forced to wait for the status 294 * register. 295 */ 296 static void *edu_fact_thread(void *opaque) 297 { 298 EduState *edu = opaque; 299 300 while (1) { 301 uint32_t val, ret = 1; 302 303 qemu_mutex_lock(&edu->thr_mutex); 304 while ((atomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && 305 !edu->stopping) { 306 qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex); 307 } 308 309 if (edu->stopping) { 310 qemu_mutex_unlock(&edu->thr_mutex); 311 break; 312 } 313 314 val = edu->fact; 315 qemu_mutex_unlock(&edu->thr_mutex); 316 317 while (val > 0) { 318 ret *= val--; 319 } 320 321 /* 322 * We should sleep for a random period here, so that students are 323 * forced to check the status properly. 324 */ 325 326 qemu_mutex_lock(&edu->thr_mutex); 327 edu->fact = ret; 328 qemu_mutex_unlock(&edu->thr_mutex); 329 atomic_and(&edu->status, ~EDU_STATUS_COMPUTING); 330 331 if (atomic_read(&edu->status) & EDU_STATUS_IRQFACT) { 332 qemu_mutex_lock_iothread(); 333 edu_raise_irq(edu, FACT_IRQ); 334 qemu_mutex_unlock_iothread(); 335 } 336 } 337 338 return NULL; 339 } 340 341 static void pci_edu_realize(PCIDevice *pdev, Error **errp) 342 { 343 EduState *edu = DO_UPCAST(EduState, pdev, pdev); 344 uint8_t *pci_conf = pdev->config; 345 346 pci_config_set_interrupt_pin(pci_conf, 1); 347 348 if (msi_init(pdev, 0, 1, true, false, errp)) { 349 return; 350 } 351 352 timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); 353 354 qemu_mutex_init(&edu->thr_mutex); 355 qemu_cond_init(&edu->thr_cond); 356 qemu_thread_create(&edu->thread, "edu", edu_fact_thread, 357 edu, QEMU_THREAD_JOINABLE); 358 359 memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, 360 "edu-mmio", 1 << 20); 361 pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); 362 } 363 364 static void pci_edu_uninit(PCIDevice *pdev) 365 { 366 EduState *edu = DO_UPCAST(EduState, pdev, pdev); 367 368 qemu_mutex_lock(&edu->thr_mutex); 369 edu->stopping = true; 370 qemu_mutex_unlock(&edu->thr_mutex); 371 qemu_cond_signal(&edu->thr_cond); 372 qemu_thread_join(&edu->thread); 373 374 qemu_cond_destroy(&edu->thr_cond); 375 qemu_mutex_destroy(&edu->thr_mutex); 376 377 timer_del(&edu->dma_timer); 378 } 379 380 static void edu_obj_uint64(Object *obj, Visitor *v, const char *name, 381 void *opaque, Error **errp) 382 { 383 uint64_t *val = opaque; 384 385 visit_type_uint64(v, name, val, errp); 386 } 387 388 static void edu_instance_init(Object *obj) 389 { 390 EduState *edu = EDU(obj); 391 392 edu->dma_mask = (1UL << 28) - 1; 393 object_property_add(obj, "dma_mask", "uint64", edu_obj_uint64, 394 edu_obj_uint64, NULL, &edu->dma_mask, NULL); 395 } 396 397 static void edu_class_init(ObjectClass *class, void *data) 398 { 399 PCIDeviceClass *k = PCI_DEVICE_CLASS(class); 400 401 k->realize = pci_edu_realize; 402 k->exit = pci_edu_uninit; 403 k->vendor_id = PCI_VENDOR_ID_QEMU; 404 k->device_id = 0x11e8; 405 k->revision = 0x10; 406 k->class_id = PCI_CLASS_OTHERS; 407 } 408 409 static void pci_edu_register_types(void) 410 { 411 static const TypeInfo edu_info = { 412 .name = "edu", 413 .parent = TYPE_PCI_DEVICE, 414 .instance_size = sizeof(EduState), 415 .instance_init = edu_instance_init, 416 .class_init = edu_class_init, 417 }; 418 419 type_register_static(&edu_info); 420 } 421 type_init(pci_edu_register_types) 422