1 /* 2 * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <new> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <ByteOrder.h> 12 #include <KernelExport.h> 13 #include <device_manager.h> 14 15 #include <drivers/ACPI.h> 16 #include <drivers/bus/FDT.h> 17 18 #include <debug.h> 19 #include <AutoDeleterDrivers.h> 20 21 #include <acpi.h> 22 23 #include <virtio.h> 24 #include <virtio_defs.h> 25 #include "VirtioDevice.h" 26 27 28 #define VIRTIO_MMIO_DEVICE_MODULE_NAME "busses/virtio/virtio_mmio/driver_v1" 29 #define VIRTIO_MMIO_CONTROLLER_TYPE_NAME "virtio MMIO controller" 30 31 32 device_manager_info* gDeviceManager; 33 34 35 static const char * 36 virtio_get_feature_name(uint32 feature) 37 { 38 switch (feature) { 39 case VIRTIO_FEATURE_NOTIFY_ON_EMPTY: 40 return "notify on empty"; 41 case VIRTIO_FEATURE_ANY_LAYOUT: 42 return "any layout"; 43 case VIRTIO_FEATURE_RING_INDIRECT_DESC: 44 return "ring indirect"; 45 case VIRTIO_FEATURE_RING_EVENT_IDX: 46 return "ring event index"; 47 case VIRTIO_FEATURE_BAD_FEATURE: 48 return "bad feature"; 49 } 50 return NULL; 51 } 52 53 54 static void 55 virtio_dump_features(const char* title, uint32 features, 56 const char* (*get_feature_name)(uint32)) 57 { 58 char features_string[512] = ""; 59 for (uint32 i = 0; i < 32; i++) { 60 uint32 feature = features & (1 << i); 61 if (feature == 0) 62 continue; 63 const char* name = virtio_get_feature_name(feature); 64 if (name == NULL) 65 name = get_feature_name(feature); 66 if (name != NULL) { 67 strlcat(features_string, "[", sizeof(features_string)); 68 strlcat(features_string, name, sizeof(features_string)); 69 strlcat(features_string, "] ", sizeof(features_string)); 70 } 71 } 72 TRACE("%s: %s\n", title, features_string); 73 } 74 75 76 //#pragma mark Device 77 78 79 static float 80 virtio_device_supports_device(device_node* parent) 81 { 82 TRACE("supports_device(%p)\n", parent); 83 84 const char* name; 85 const char* bus; 86 87 status_t status = gDeviceManager->get_attr_string(parent, 88 B_DEVICE_PRETTY_NAME, &name, false); 89 90 if (status >= B_OK) 91 TRACE(" name: %s\n", name); 92 93 status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); 94 95 if (status < B_OK) 96 return -1.0f; 97 98 // detect virtio device from FDT 99 if (strcmp(bus, "fdt") == 0) { 100 const char* compatible; 101 status = gDeviceManager->get_attr_string(parent, "fdt/compatible", 102 &compatible, false); 103 104 if (status < B_OK) 105 return -1.0f; 106 107 if (strcmp(compatible, "virtio,mmio") != 0) 108 return 0.0f; 109 110 return 1.0f; 111 } 112 113 // detect virtio device from ACPI 114 if (strcmp(bus, "acpi") == 0) { 115 const char* hid; 116 status = gDeviceManager->get_attr_string(parent, "acpi/hid", 117 &hid, false); 118 119 if (status < B_OK) 120 return -1.0f; 121 122 if (strcmp(hid, "LNRO0005") != 0) 123 return 0.0f; 124 125 return 1.0f; 126 } 127 128 return 0.0f; 129 } 130 131 132 struct virtio_memory_range { 133 uint64 base; 134 uint64 length; 135 }; 136 137 static acpi_status 138 virtio_crs_find_address(acpi_resource *res, void *context) 139 { 140 virtio_memory_range &range = *((virtio_memory_range *)context); 141 142 if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { 143 range.base = res->data.fixed_memory32.address; 144 range.length = res->data.fixed_memory32.address_length; 145 } 146 147 return B_OK; 148 } 149 150 151 static acpi_status 152 virtio_crs_find_interrupt(acpi_resource *res, void *context) 153 { 154 uint64 &interrupt = *((uint64 *)context); 155 156 if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) 157 interrupt = res->data.extended_irq.interrupts[0]; 158 159 return B_OK; 160 } 161 162 163 static status_t 164 virtio_device_register_device(device_node* parent) 165 { 166 TRACE("register_device(%p)\n", parent); 167 168 const char* bus; 169 170 status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); 171 172 if (status < B_OK) 173 return -1.0f; 174 175 uint64 regs = 0; 176 uint64 regsLen = 0; 177 178 // initialize virtio device from FDT 179 if (strcmp(bus, "fdt") == 0) { 180 fdt_device_module_info *parentModule; 181 fdt_device* parentDev; 182 if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, 183 (void**)&parentDev)) { 184 ERROR("can't get parent node driver"); 185 return B_ERROR; 186 } 187 188 if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { 189 ERROR("no regs"); 190 return B_ERROR; 191 } 192 } 193 194 // initialize virtio device from ACPI 195 if (strcmp(bus, "acpi") == 0) { 196 acpi_device_module_info *parentModule; 197 acpi_device parentDev; 198 if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, 199 (void**)&parentDev)) { 200 ERROR("can't get parent node driver"); 201 return B_ERROR; 202 } 203 204 virtio_memory_range range = { 0, 0 }; 205 parentModule->walk_resources(parentDev, (char *)"_CRS", 206 virtio_crs_find_address, &range); 207 regs = range.base; 208 regsLen = range.length; 209 } 210 211 VirtioRegs *volatile mappedRegs; 212 AreaDeleter fRegsArea(map_physical_memory("Virtio MMIO", regs, regsLen, 213 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 214 (void **)&mappedRegs)); 215 216 if (!fRegsArea.IsSet()) { 217 ERROR("cant't map regs"); 218 return B_ERROR; 219 } 220 221 if (mappedRegs->signature != kVirtioSignature) { 222 ERROR("bad signature: 0x%08" B_PRIx32 ", should be 0x%08" B_PRIx32 "\n", 223 mappedRegs->signature, (uint32)kVirtioSignature); 224 return B_ERROR; 225 } 226 227 TRACE(" version: 0x%08" B_PRIx32 "\n", mappedRegs->version); 228 TRACE(" deviceId: 0x%08" B_PRIx32 "\n", mappedRegs->deviceId); 229 TRACE(" vendorId: 0x%08" B_PRIx32 "\n", mappedRegs->vendorId); 230 231 device_attr attrs[] = { 232 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Virtio MMIO"} }, 233 { B_DEVICE_BUS, B_STRING_TYPE, {string: "virtio"} }, 234 { "virtio/version", B_UINT32_TYPE, {ui32: mappedRegs->version} }, 235 { "virtio/device_id", B_UINT32_TYPE, {ui32: mappedRegs->deviceId} }, 236 { "virtio/type", B_UINT16_TYPE, 237 {ui16: (uint16)mappedRegs->deviceId} }, 238 { "virtio/vendor_id", B_UINT32_TYPE, {ui32: mappedRegs->vendorId} }, 239 { NULL } 240 }; 241 242 return gDeviceManager->register_node(parent, VIRTIO_MMIO_DEVICE_MODULE_NAME, 243 attrs, NULL, NULL); 244 } 245 246 247 static status_t 248 virtio_device_init_device(device_node* node, void** cookie) 249 { 250 TRACE("init_device(%p)\n", node); 251 252 DeviceNodePutter<&gDeviceManager> 253 parent(gDeviceManager->get_parent_node(node)); 254 255 const char* bus; 256 257 status_t status = gDeviceManager->get_attr_string(parent.Get(), B_DEVICE_BUS, &bus, false); 258 259 if (status < B_OK) 260 return -1.0f; 261 262 uint64 regs = 0; 263 uint64 regsLen = 0; 264 uint64 interrupt = 0; 265 266 // initialize virtio device from FDT 267 if (strcmp(bus, "fdt") == 0) { 268 fdt_device_module_info *parentModule; 269 fdt_device* parentDev; 270 if (gDeviceManager->get_driver(parent.Get(), 271 (driver_module_info**)&parentModule, (void**)&parentDev)) 272 panic("can't get parent node driver"); 273 274 TRACE(" bus: %p\n", parentModule->get_bus(parentDev)); 275 TRACE(" compatible: %s\n", (const char*)parentModule->get_prop(parentDev, 276 "compatible", NULL)); 277 278 for (uint32 i = 0; parentModule->get_reg(parentDev, i, ®s, ®sLen); 279 i++) { 280 TRACE(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", 281 i, regs, regsLen); 282 } 283 284 device_node* interruptController; 285 for (uint32 i = 0; parentModule->get_interrupt(parentDev, 286 i, &interruptController, &interrupt); i++) { 287 288 const char* name; 289 if (interruptController == NULL 290 || gDeviceManager->get_attr_string(interruptController, "fdt/name", 291 &name, false) < B_OK) { 292 name = NULL; 293 } 294 295 TRACE(" interrupt[%" B_PRIu32 "]: ('%s', 0x%" B_PRIx64 ")\n", i, 296 name, interrupt); 297 } 298 299 if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { 300 TRACE(" no regs\n"); 301 return B_ERROR; 302 } 303 304 if (!parentModule->get_interrupt(parentDev, 0, &interruptController, 305 &interrupt)) { 306 TRACE(" no interrupts\n"); 307 return B_ERROR; 308 } 309 } 310 311 // initialize virtio device from ACPI 312 if (strcmp(bus, "acpi") == 0) { 313 acpi_device_module_info *parentModule; 314 acpi_device parentDev; 315 if (gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&parentModule, 316 (void**)&parentDev)) { 317 ERROR("can't get parent node driver"); 318 return B_ERROR; 319 } 320 321 virtio_memory_range range = { 0, 0 }; 322 parentModule->walk_resources(parentDev, (char *)"_CRS", 323 virtio_crs_find_address, &range); 324 regs = range.base; 325 regsLen = range.length; 326 327 parentModule->walk_resources(parentDev, (char *)"_CRS", 328 virtio_crs_find_interrupt, &interrupt); 329 330 TRACE(" regs: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", 331 regs, regsLen); 332 TRACE(" interrupt: 0x%" B_PRIx64 "\n", 333 interrupt); 334 } 335 336 ObjectDeleter<VirtioDevice> dev(new(std::nothrow) VirtioDevice()); 337 if (!dev.IsSet()) 338 return B_NO_MEMORY; 339 340 status_t res = dev->Init(regs, regsLen, interrupt, 1); 341 if (res < B_OK) 342 return res; 343 344 *cookie = dev.Detach(); 345 return B_OK; 346 } 347 348 349 static void 350 virtio_device_uninit_device(void* cookie) 351 { 352 TRACE("uninit_device(%p)\n", cookie); 353 ObjectDeleter<VirtioDevice> dev((VirtioDevice*)cookie); 354 } 355 356 357 static status_t 358 virtio_device_register_child_devices(void* cookie) 359 { 360 TRACE("register_child_devices(%p)\n", cookie); 361 return B_OK; 362 } 363 364 365 //#pragma mark driver API 366 367 368 static status_t 369 virtio_device_negotiate_features(virtio_device cookie, uint32 supported, 370 uint32* negotiated, const char* (*get_feature_name)(uint32)) 371 { 372 TRACE("virtio_device_negotiate_features(%p)\n", cookie); 373 VirtioDevice* dev = (VirtioDevice*)cookie; 374 375 dev->fRegs->status |= kVirtioConfigSAcknowledge; 376 dev->fRegs->status |= kVirtioConfigSDriver; 377 378 uint32 features = dev->fRegs->deviceFeatures; 379 virtio_dump_features("read features", features, get_feature_name); 380 features &= supported; 381 382 // filter our own features 383 features &= (VIRTIO_FEATURE_TRANSPORT_MASK 384 | VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX); 385 *negotiated = features; 386 387 virtio_dump_features("negotiated features", features, get_feature_name); 388 389 dev->fRegs->driverFeatures = features; 390 dev->fRegs->status |= kVirtioConfigSFeaturesOk; 391 dev->fRegs->status |= kVirtioConfigSDriverOk; 392 dev->fRegs->guestPageSize = B_PAGE_SIZE; 393 394 return B_OK; 395 } 396 397 398 static status_t 399 virtio_device_clear_feature(virtio_device cookie, uint32 feature) 400 { 401 panic("not implemented"); 402 return B_ERROR; 403 } 404 405 406 static status_t 407 virtio_device_read_device_config(virtio_device cookie, uint8 offset, 408 void* buffer, size_t bufferSize) 409 { 410 TRACE("virtio_device_read_device_config(%p, %d, %" B_PRIuSIZE ")\n", cookie, 411 offset, bufferSize); 412 VirtioDevice* dev = (VirtioDevice*)cookie; 413 414 // TODO: check ARM support, ARM seems support only 32 bit aligned MMIO access. 415 vuint8* src = &dev->fRegs->config[offset]; 416 uint8* dst = (uint8*)buffer; 417 while (bufferSize > 0) { 418 uint8 size = 4; 419 if (bufferSize == 1) { 420 size = 1; 421 *dst = *src; 422 } else if (bufferSize <= 3) { 423 size = 2; 424 *(uint16*)dst = *(vuint16*)src; 425 } else 426 *(uint32*)dst = *(vuint32*)src; 427 428 dst += size; 429 bufferSize -= size; 430 src += size; 431 } 432 433 return B_OK; 434 } 435 436 437 static status_t 438 virtio_device_write_device_config(virtio_device cookie, uint8 offset, 439 const void* buffer, size_t bufferSize) 440 { 441 TRACE("virtio_device_write_device_config(%p, %d, %" B_PRIuSIZE ")\n", 442 cookie, offset, bufferSize); 443 VirtioDevice* dev = (VirtioDevice*)cookie; 444 445 // See virtio_device_read_device_config 446 uint8* src = (uint8*)buffer; 447 vuint8* dst = &dev->fRegs->config[offset]; 448 while (bufferSize > 0) { 449 uint8 size = 4; 450 if (bufferSize == 1) { 451 size = 1; 452 *dst = *src; 453 } else if (bufferSize <= 3) { 454 size = 2; 455 *(vuint16*)dst = *(uint16*)src; 456 } else 457 *(vuint32*)dst = *(uint32*)src; 458 459 dst += size; 460 bufferSize -= size; 461 src += size; 462 } 463 464 return B_OK; 465 } 466 467 468 static status_t 469 virtio_device_alloc_queues(virtio_device cookie, size_t count, 470 virtio_queue* queues) 471 { 472 TRACE("virtio_device_alloc_queues(%p, %" B_PRIuSIZE ")\n", cookie, count); 473 VirtioDevice* dev = (VirtioDevice*)cookie; 474 475 ArrayDeleter<ObjectDeleter<VirtioQueue> > newQueues(new(std::nothrow) 476 ObjectDeleter<VirtioQueue>[count]); 477 478 if (!newQueues.IsSet()) 479 return B_NO_MEMORY; 480 481 for (size_t i = 0; i < count; i++) { 482 newQueues[i].SetTo(new(std::nothrow) VirtioQueue(dev, i)); 483 484 if (!newQueues[i].IsSet()) 485 return B_NO_MEMORY; 486 487 status_t res = newQueues[i]->Init(); 488 if (res < B_OK) 489 return res; 490 } 491 492 dev->fQueueCnt = count; 493 dev->fQueues.SetTo(newQueues.Detach()); 494 495 for (size_t i = 0; i < count; i++) 496 queues[i] = dev->fQueues[i].Get(); 497 498 return B_OK; 499 } 500 501 502 static void 503 virtio_device_free_queues(virtio_device cookie) 504 { 505 TRACE("virtio_device_free_queues(%p)\n", cookie); 506 VirtioDevice* dev = (VirtioDevice*)cookie; 507 508 dev->fQueues.Unset(); 509 dev->fQueueCnt = 0; 510 } 511 512 513 static status_t 514 virtio_device_setup_interrupt(virtio_device cookie, 515 virtio_intr_func config_handler, void* driverCookie) 516 { 517 VirtioDevice* dev = (VirtioDevice*)cookie; 518 TRACE("virtio_device_setup_interrupt(%p, %#" B_PRIxADDR ")\n", dev, 519 (addr_t)config_handler); 520 521 dev->fConfigHandler = config_handler; 522 dev->fConfigHandlerCookie = driverCookie; 523 dev->fConfigHandlerRef.SetTo((config_handler == NULL) 524 ? NULL : &dev->fIrqHandler); 525 526 return B_OK; 527 } 528 529 530 static status_t 531 virtio_device_free_interrupts(virtio_device cookie) 532 { 533 VirtioDevice* dev = (VirtioDevice*)cookie; 534 TRACE("virtio_device_free_interrupts(%p)\n", dev); 535 536 for (int32 i = 0; i < dev->fQueueCnt; i++) { 537 VirtioQueue* queue = dev->fQueues[i].Get(); 538 queue->fQueueHandler = NULL; 539 queue->fQueueHandlerCookie = NULL; 540 queue->fQueueHandlerRef.Unset(); 541 } 542 543 dev->fConfigHandler = NULL; 544 dev->fConfigHandlerCookie = NULL; 545 dev->fConfigHandlerRef.Unset(); 546 547 return B_OK; 548 } 549 550 551 static status_t 552 virtio_device_queue_setup_interrupt(virtio_queue aQueue, 553 virtio_callback_func handler, void* cookie) 554 { 555 TRACE("virtio_device_queue_setup_interrupt(%p, %p)\n", aQueue, handler); 556 557 VirtioQueue* queue = (VirtioQueue*)aQueue; 558 VirtioDevice* dev = queue->fDev; 559 560 queue->fQueueHandler = handler; 561 queue->fQueueHandlerCookie = cookie; 562 queue->fQueueHandlerRef.SetTo((handler == NULL) ? NULL : &dev->fIrqHandler); 563 564 return B_OK; 565 } 566 567 568 static status_t 569 virtio_device_queue_request_v(virtio_queue aQueue, 570 const physical_entry* vector, 571 size_t readVectorCount, size_t writtenVectorCount, 572 void* cookie) 573 { 574 // TRACE("virtio_device_queue_request_v(%p, %" B_PRIuSIZE ", %" B_PRIuSIZE 575 // ", %p)\n", aQueue, readVectorCount, writtenVectorCount, cookie); 576 VirtioQueue* queue = (VirtioQueue*)aQueue; 577 578 return queue->Enqueue(vector, readVectorCount, writtenVectorCount, cookie); 579 } 580 581 582 static status_t 583 virtio_device_queue_request(virtio_queue aQueue, 584 const physical_entry* readEntry, 585 const physical_entry* writtenEntry, void* cookie) 586 { 587 VirtioQueue* queue = (VirtioQueue*)aQueue; 588 589 physical_entry vector[2]; 590 physical_entry* vectorEnd = vector; 591 592 if (readEntry != NULL) 593 *vectorEnd++ = *readEntry; 594 595 if (writtenEntry != NULL) 596 *vectorEnd++ = *writtenEntry; 597 598 return queue->Enqueue(vector, (readEntry != NULL) ? 1 : 0, 599 (writtenEntry != NULL) ? 1 : 0, cookie); 600 } 601 602 603 static bool 604 virtio_device_queue_is_full(virtio_queue queue) 605 { 606 panic("not implemented"); 607 return false; 608 } 609 610 611 static bool 612 virtio_device_queue_is_empty(virtio_queue aQueue) 613 { 614 VirtioQueue *queue = (VirtioQueue *)aQueue; 615 return queue->fUsed->idx == queue->fLastUsed; 616 } 617 618 619 static uint16 620 virtio_device_queue_size(virtio_queue aQueue) 621 { 622 VirtioQueue *queue = (VirtioQueue *)aQueue; 623 return (uint16)queue->fQueueLen; 624 } 625 626 627 static bool 628 virtio_device_queue_dequeue(virtio_queue aQueue, void** _cookie, 629 uint32* _usedLength) 630 { 631 // TRACE("virtio_device_queue_dequeue(%p)\n", aQueue); 632 VirtioQueue* queue = (VirtioQueue*)aQueue; 633 return queue->Dequeue(_cookie, _usedLength); 634 } 635 636 637 //#pragma mark - 638 639 640 module_dependency module_dependencies[] = { 641 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 642 { NULL } 643 }; 644 645 646 static virtio_device_interface sVirtioDevice = { 647 { 648 { 649 VIRTIO_MMIO_DEVICE_MODULE_NAME, 650 0, 651 NULL 652 }, 653 654 virtio_device_supports_device, 655 virtio_device_register_device, 656 virtio_device_init_device, 657 virtio_device_uninit_device, 658 virtio_device_register_child_devices, 659 NULL, // rescan 660 NULL, // device removed 661 }, 662 virtio_device_negotiate_features, 663 virtio_device_clear_feature, 664 virtio_device_read_device_config, 665 virtio_device_write_device_config, 666 virtio_device_alloc_queues, 667 virtio_device_free_queues, 668 virtio_device_setup_interrupt, 669 virtio_device_free_interrupts, 670 virtio_device_queue_setup_interrupt, 671 virtio_device_queue_request, 672 virtio_device_queue_request_v, 673 virtio_device_queue_is_full, 674 virtio_device_queue_is_empty, 675 virtio_device_queue_size, 676 virtio_device_queue_dequeue, 677 }; 678 679 680 module_info* modules[] = { 681 (module_info* )&sVirtioDevice, 682 NULL 683 }; 684