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