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/bus/FDT.h> 16 17 #include <debug.h> 18 #include <AutoDeleterDrivers.h> 19 20 #include <virtio.h> 21 #include <virtio_defs.h> 22 #include "VirtioDevice.h" 23 24 25 #define VIRTIO_MMIO_DEVICE_MODULE_NAME "busses/virtio/virtio_mmio/driver_v1" 26 #define VIRTIO_MMIO_CONTROLLER_TYPE_NAME "virtio MMIO controller" 27 28 29 device_manager_info* gDeviceManager; 30 31 32 static const char * 33 virtio_get_feature_name(uint32 feature) 34 { 35 switch (feature) { 36 case VIRTIO_FEATURE_NOTIFY_ON_EMPTY: 37 return "notify on empty"; 38 case VIRTIO_FEATURE_ANY_LAYOUT: 39 return "any layout"; 40 case VIRTIO_FEATURE_RING_INDIRECT_DESC: 41 return "ring indirect"; 42 case VIRTIO_FEATURE_RING_EVENT_IDX: 43 return "ring event index"; 44 case VIRTIO_FEATURE_BAD_FEATURE: 45 return "bad feature"; 46 } 47 return NULL; 48 } 49 50 51 static void 52 virtio_dump_features(const char* title, uint32 features, 53 const char* (*get_feature_name)(uint32)) 54 { 55 char features_string[512] = ""; 56 for (uint32 i = 0; i < 32; i++) { 57 uint32 feature = features & (1 << i); 58 if (feature == 0) 59 continue; 60 const char* name = virtio_get_feature_name(feature); 61 if (name == NULL) 62 name = get_feature_name(feature); 63 if (name != NULL) { 64 strlcat(features_string, "[", sizeof(features_string)); 65 strlcat(features_string, name, sizeof(features_string)); 66 strlcat(features_string, "] ", sizeof(features_string)); 67 } 68 } 69 TRACE("%s: %s\n", title, features_string); 70 } 71 72 73 //#pragma mark Device 74 75 76 static float 77 virtio_device_supports_device(device_node* parent) 78 { 79 TRACE("supports_device(%p)\n", parent); 80 81 const char* name; 82 const char* bus; 83 const char* compatible; 84 85 status_t status = gDeviceManager->get_attr_string(parent, 86 B_DEVICE_PRETTY_NAME, &name, false); 87 88 if (status >= B_OK) 89 dprintf(" name: %s\n", name); 90 91 status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); 92 93 if (status < B_OK) 94 return -1.0f; 95 96 status = gDeviceManager->get_attr_string(parent, "fdt/compatible", 97 &compatible, false); 98 99 if (status < B_OK) 100 return -1.0f; 101 102 if (strcmp(bus, "fdt") != 0) 103 return 0.0f; 104 105 if (strcmp(compatible, "virtio,mmio") != 0) 106 return 0.0f; 107 108 return 1.0f; 109 } 110 111 112 static status_t 113 virtio_device_register_device(device_node* parent) 114 { 115 TRACE("register_device(%p)\n", parent); 116 117 fdt_device_module_info *parentModule; 118 fdt_device* parentDev; 119 if (gDeviceManager->get_driver(parent, (driver_module_info**)&parentModule, 120 (void**)&parentDev)) { 121 ERROR("can't get parent node driver"); 122 return B_ERROR; 123 } 124 125 uint64 regs, regsLen; 126 if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { 127 ERROR("no regs"); 128 return B_ERROR; 129 } 130 131 VirtioRegs *volatile mappedRegs; 132 AreaDeleter fRegsArea(map_physical_memory("Virtio MMIO", regs, regsLen, 133 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, 134 (void **)&mappedRegs)); 135 136 if (!fRegsArea.IsSet()) { 137 ERROR("cant't map regs"); 138 return B_ERROR; 139 } 140 141 if (mappedRegs->signature != kVirtioSignature) { 142 ERROR("bad signature: 0x%08" B_PRIx32 ", should be 0x%08" B_PRIx32 "\n", 143 mappedRegs->signature, (uint32)kVirtioSignature); 144 return B_ERROR; 145 } 146 147 dprintf(" version: 0x%08" B_PRIx32 "\n", mappedRegs->version); 148 dprintf(" deviceId: 0x%08" B_PRIx32 "\n", mappedRegs->deviceId); 149 dprintf(" vendorId: 0x%08" B_PRIx32 "\n", mappedRegs->vendorId); 150 151 device_attr attrs[] = { 152 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Virtio MMIO"} }, 153 { B_DEVICE_BUS, B_STRING_TYPE, {string: "virtio"} }, 154 { "virtio/version", B_UINT32_TYPE, {ui32: mappedRegs->version} }, 155 { "virtio/device_id", B_UINT32_TYPE, {ui32: mappedRegs->deviceId} }, 156 { "virtio/type", B_UINT16_TYPE, 157 {ui16: (uint16)mappedRegs->deviceId} }, 158 { "virtio/vendor_id", B_UINT32_TYPE, {ui32: mappedRegs->vendorId} }, 159 { NULL } 160 }; 161 162 return gDeviceManager->register_node(parent, VIRTIO_MMIO_DEVICE_MODULE_NAME, 163 attrs, NULL, NULL); 164 } 165 166 167 static status_t 168 virtio_device_init_device(device_node* node, void** cookie) 169 { 170 TRACE("init_device(%p)\n", node); 171 172 DeviceNodePutter<&gDeviceManager> 173 parent(gDeviceManager->get_parent_node(node)); 174 175 fdt_device_module_info *parentModule; 176 fdt_device* parentDev; 177 if (gDeviceManager->get_driver(parent.Get(), 178 (driver_module_info**)&parentModule, (void**)&parentDev)) 179 panic("can't get parent node driver"); 180 181 dprintf(" bus: %p\n", parentModule->get_bus(parentDev)); 182 dprintf(" compatible: %s\n", (const char*)parentModule->get_prop(parentDev, 183 "compatible", NULL)); 184 185 uint64 regs; 186 uint64 regsLen; 187 for (uint32 i = 0; parentModule->get_reg(parentDev, i, ®s, ®sLen); 188 i++) { 189 dprintf(" reg[%" B_PRIu32 "]: (0x%" B_PRIx64 ", 0x%" B_PRIx64 ")\n", 190 i, regs, regsLen); 191 } 192 193 device_node* interruptController; 194 uint64 interrupt; 195 for (uint32 i = 0; parentModule->get_interrupt(parentDev, 196 i, &interruptController, &interrupt); i++) { 197 198 const char* name; 199 if (interruptController == NULL 200 || gDeviceManager->get_attr_string(interruptController, "fdt/name", 201 &name, false) < B_OK) { 202 name = NULL; 203 } 204 205 dprintf(" interrupt[%" B_PRIu32 "]: ('%s', 0x%" B_PRIx64 ")\n", i, 206 name, interrupt); 207 } 208 209 if (!parentModule->get_reg(parentDev, 0, ®s, ®sLen)) { 210 dprintf(" no regs\n"); 211 return B_ERROR; 212 } 213 214 if (!parentModule->get_interrupt(parentDev, 0, &interruptController, 215 &interrupt)) { 216 dprintf(" no interrupts\n"); 217 return B_ERROR; 218 } 219 220 ObjectDeleter<VirtioDevice> dev(new(std::nothrow) VirtioDevice()); 221 if (!dev.IsSet()) 222 return B_NO_MEMORY; 223 224 status_t res = dev->Init(regs, regsLen, interrupt, 1); 225 if (res < B_OK) 226 return res; 227 228 *cookie = dev.Detach(); 229 return B_OK; 230 } 231 232 233 static void 234 virtio_device_uninit_device(void* cookie) 235 { 236 TRACE("uninit_device(%p)\n", cookie); 237 ObjectDeleter<VirtioDevice> dev((VirtioDevice*)cookie); 238 } 239 240 241 static status_t 242 virtio_device_register_child_devices(void* cookie) 243 { 244 TRACE("register_child_devices(%p)\n", cookie); 245 return B_OK; 246 } 247 248 249 //#pragma mark driver API 250 251 252 static status_t 253 virtio_device_negotiate_features(virtio_device cookie, uint32 supported, 254 uint32* negotiated, const char* (*get_feature_name)(uint32)) 255 { 256 TRACE("virtio_device_negotiate_features(%p)\n", cookie); 257 VirtioDevice* dev = (VirtioDevice*)cookie; 258 259 dev->fRegs->status |= kVirtioConfigSAcknowledge; 260 dev->fRegs->status |= kVirtioConfigSDriver; 261 262 uint32 features = dev->fRegs->deviceFeatures; 263 virtio_dump_features("read features", features, get_feature_name); 264 features &= supported; 265 266 // filter our own features 267 features &= (VIRTIO_FEATURE_TRANSPORT_MASK 268 | VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX); 269 *negotiated = features; 270 271 virtio_dump_features("negotiated features", features, get_feature_name); 272 273 dev->fRegs->driverFeatures = features; 274 dev->fRegs->status |= kVirtioConfigSFeaturesOk; 275 dev->fRegs->status |= kVirtioConfigSDriverOk; 276 dev->fRegs->guestPageSize = B_PAGE_SIZE; 277 278 return B_OK; 279 } 280 281 282 static status_t 283 virtio_device_clear_feature(virtio_device cookie, uint32 feature) 284 { 285 panic("not implemented"); 286 return B_ERROR; 287 } 288 289 290 static status_t 291 virtio_device_read_device_config(virtio_device cookie, uint8 offset, 292 void* buffer, size_t bufferSize) 293 { 294 TRACE("virtio_device_read_device_config(%p, %d, %" B_PRIuSIZE ")\n", cookie, 295 offset, bufferSize); 296 297 VirtioDevice* dev = (VirtioDevice*)cookie; 298 memcpy(buffer, (void*)(dev->fRegs->config + offset), bufferSize); 299 300 return B_OK; 301 } 302 303 304 static status_t 305 virtio_device_write_device_config(virtio_device cookie, uint8 offset, 306 const void* buffer, size_t bufferSize) 307 { 308 TRACE("virtio_device_write_device_config(%p, %d, %" B_PRIuSIZE ")\n", 309 cookie, offset, bufferSize); 310 VirtioDevice* dev = (VirtioDevice*)cookie; 311 memcpy((void*)(dev->fRegs->config + offset), buffer, bufferSize); 312 return B_OK; 313 } 314 315 316 static status_t 317 virtio_device_alloc_queues(virtio_device cookie, size_t count, 318 virtio_queue* queues) 319 { 320 TRACE("virtio_device_alloc_queues(%p, %" B_PRIuSIZE ")\n", cookie, count); 321 VirtioDevice* dev = (VirtioDevice*)cookie; 322 323 ArrayDeleter<ObjectDeleter<VirtioQueue> > newQueues(new(std::nothrow) 324 ObjectDeleter<VirtioQueue>[count]); 325 326 if (!newQueues.IsSet()) 327 return B_NO_MEMORY; 328 329 for (size_t i = 0; i < count; i++) { 330 newQueues[i].SetTo(new(std::nothrow) VirtioQueue(dev, i)); 331 332 if (!newQueues[i].IsSet()) 333 return B_NO_MEMORY; 334 335 status_t res = newQueues[i]->Init(); 336 if (res < B_OK) 337 return res; 338 } 339 340 dev->fQueueCnt = count; 341 dev->fQueues.SetTo(newQueues.Detach()); 342 343 for (size_t i = 0; i < count; i++) 344 queues[i] = dev->fQueues[i].Get(); 345 346 return B_OK; 347 } 348 349 350 static void 351 virtio_device_free_queues(virtio_device cookie) 352 { 353 TRACE("virtio_device_free_queues(%p)\n", cookie); 354 VirtioDevice* dev = (VirtioDevice*)cookie; 355 356 dev->fQueues.Unset(); 357 dev->fQueueCnt = 0; 358 } 359 360 361 static status_t 362 virtio_device_setup_interrupt(virtio_device cookie, 363 virtio_intr_func config_handler, void* driverCookie) 364 { 365 VirtioDevice* dev = (VirtioDevice*)cookie; 366 TRACE("virtio_device_setup_interrupt(%p, %#" B_PRIxADDR ")\n", dev, 367 (addr_t)config_handler); 368 369 dev->fConfigHandler = config_handler; 370 dev->fConfigHandlerCookie = driverCookie; 371 dev->fConfigHandlerRef.SetTo((config_handler == NULL) 372 ? NULL : &dev->fIrqHandler); 373 374 return B_OK; 375 } 376 377 378 static status_t 379 virtio_device_free_interrupts(virtio_device cookie) 380 { 381 VirtioDevice* dev = (VirtioDevice*)cookie; 382 TRACE("virtio_device_free_interrupts(%p)\n", dev); 383 384 for (int32 i = 0; i < dev->fQueueCnt; i++) { 385 VirtioQueue* queue = dev->fQueues[i].Get(); 386 queue->fQueueHandler = NULL; 387 queue->fQueueHandlerCookie = NULL; 388 queue->fQueueHandlerRef.Unset(); 389 } 390 391 dev->fConfigHandler = NULL; 392 dev->fConfigHandlerCookie = NULL; 393 dev->fConfigHandlerRef.Unset(); 394 395 return B_OK; 396 } 397 398 399 static status_t 400 virtio_device_queue_setup_interrupt(virtio_queue aQueue, 401 virtio_callback_func handler, void* cookie) 402 { 403 TRACE("virtio_device_queue_setup_interrupt(%p, %p)\n", aQueue, handler); 404 405 VirtioQueue* queue = (VirtioQueue*)aQueue; 406 VirtioDevice* dev = queue->fDev; 407 408 queue->fQueueHandler = handler; 409 queue->fQueueHandlerCookie = cookie; 410 queue->fQueueHandlerRef.SetTo((handler == NULL) ? NULL : &dev->fIrqHandler); 411 412 return B_OK; 413 } 414 415 416 static status_t 417 virtio_device_queue_request_v(virtio_queue aQueue, 418 const physical_entry* vector, 419 size_t readVectorCount, size_t writtenVectorCount, 420 void* cookie) 421 { 422 // TRACE("virtio_device_queue_request_v(%p, %" B_PRIuSIZE ", %" B_PRIuSIZE 423 // ", %p)\n", aQueue, readVectorCount, writtenVectorCount, cookie); 424 VirtioQueue* queue = (VirtioQueue*)aQueue; 425 426 return queue->Enqueue(vector, readVectorCount, writtenVectorCount, cookie); 427 } 428 429 430 static status_t 431 virtio_device_queue_request(virtio_queue aQueue, 432 const physical_entry* readEntry, 433 const physical_entry* writtenEntry, void* cookie) 434 { 435 VirtioQueue* queue = (VirtioQueue*)aQueue; 436 437 physical_entry vector[2]; 438 physical_entry* vectorEnd = vector; 439 440 if (readEntry != NULL) 441 *vectorEnd++ = *readEntry; 442 443 if (writtenEntry != NULL) 444 *vectorEnd++ = *writtenEntry; 445 446 return queue->Enqueue(vector, (readEntry != NULL) ? 1 : 0, 447 (writtenEntry != NULL) ? 1 : 0, cookie); 448 } 449 450 451 static bool 452 virtio_device_queue_is_full(virtio_queue queue) 453 { 454 panic("not implemented"); 455 return false; 456 } 457 458 459 static bool 460 virtio_device_queue_is_empty(virtio_queue aQueue) 461 { 462 VirtioQueue *queue = (VirtioQueue *)aQueue; 463 return queue->fUsed->idx == queue->fLastUsed; 464 } 465 466 467 static uint16 468 virtio_device_queue_size(virtio_queue aQueue) 469 { 470 VirtioQueue *queue = (VirtioQueue *)aQueue; 471 return (uint16)queue->fQueueLen; 472 } 473 474 475 static bool 476 virtio_device_queue_dequeue(virtio_queue aQueue, void** _cookie, 477 uint32* _usedLength) 478 { 479 // TRACE("virtio_device_queue_dequeue(%p)\n", aQueue); 480 VirtioQueue* queue = (VirtioQueue*)aQueue; 481 return queue->Dequeue(_cookie, _usedLength); 482 } 483 484 485 //#pragma mark - 486 487 488 module_dependency module_dependencies[] = { 489 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, 490 { NULL } 491 }; 492 493 494 static virtio_device_interface sVirtioDevice = { 495 { 496 { 497 VIRTIO_MMIO_DEVICE_MODULE_NAME, 498 0, 499 NULL 500 }, 501 502 virtio_device_supports_device, 503 virtio_device_register_device, 504 virtio_device_init_device, 505 virtio_device_uninit_device, 506 virtio_device_register_child_devices, 507 NULL, // rescan 508 NULL, // device removed 509 }, 510 virtio_device_negotiate_features, 511 virtio_device_clear_feature, 512 virtio_device_read_device_config, 513 virtio_device_write_device_config, 514 virtio_device_alloc_queues, 515 virtio_device_free_queues, 516 virtio_device_setup_interrupt, 517 virtio_device_free_interrupts, 518 virtio_device_queue_setup_interrupt, 519 virtio_device_queue_request, 520 virtio_device_queue_request_v, 521 virtio_device_queue_is_full, 522 virtio_device_queue_is_empty, 523 virtio_device_queue_size, 524 virtio_device_queue_dequeue, 525 }; 526 527 528 module_info* modules[] = { 529 (module_info* )&sVirtioDevice, 530 NULL 531 }; 532