BOOLEAN VirtRngEvtInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId) { PDEVICE_CONTEXT context = GetDeviceContext( WdfInterruptGetDevice(Interrupt)); WDF_INTERRUPT_INFO info; BOOLEAN serviced; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> %!FUNC! Interrupt: %p MessageId: %u", Interrupt, MessageId); WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(context->WdfInterrupt, &info); if ((info.MessageSignaled && (MessageId == 0)) || VirtIODeviceISR(&context->VirtDevice)) { WdfInterruptQueueDpcForIsr(Interrupt); serviced = TRUE; } else { serviced = FALSE; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- %!FUNC!"); return serviced; }
BOOLEAN VioCryptInterruptIsr(IN WDFINTERRUPT Interrupt, IN ULONG MessageId) { PDEVICE_CONTEXT context = GetDeviceContext( WdfInterruptGetDevice(Interrupt)); WDF_INTERRUPT_INFO info; BOOLEAN processed; WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(context->WdfInterrupt, &info); processed = ((info.MessageSignaled && (MessageId == 0)) || VirtIOWdfGetISRStatus(&context->VDevice)); if (processed) { WdfInterruptQueueDpcForIsr(Interrupt); } Trace(TRACE_LEVEL_VERBOSE, "[%s] %sprocessed", __FUNCTION__, processed ? "" : "not "); return processed; }
VOID VIOSerialHandleCtrlMsg( IN WDFDEVICE Device, IN PPORT_BUFFER buf ) { PPORTS_DEVICE pContext = GetPortsDevice(Device); PVIRTIO_CONSOLE_CONTROL cpkt; PVIOSERIAL_PORT port; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); cpkt = (PVIRTIO_CONSOLE_CONTROL)((ULONG_PTR)buf->va_buf + buf->offset); port = VIOSerialFindPortById(Device, cpkt->id); if (!port && (cpkt->event != VIRTIO_CONSOLE_PORT_ADD)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Invalid index %u in control packet\n", cpkt->id); } switch (cpkt->event) { case VIRTIO_CONSOLE_PORT_ADD: if (port) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_PORT_ADD id = %d\n", cpkt->id); break; } if (cpkt->id >= pContext->consoleConfig.max_nr_ports) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Out-of-bound id %u\n", cpkt->id); break; } VIOSerialAddPort(Device, cpkt->id); break; case VIRTIO_CONSOLE_PORT_REMOVE: if (!port) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_REMOVE invalid id = %d\n", cpkt->id); break; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_PORT_REMOVE id = %d\n", cpkt->id); VIOSerialRemovePort(Device, port); break; case VIRTIO_CONSOLE_CONSOLE_PORT: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_CONSOLE_PORT id = %d value = %u\n", cpkt->id, cpkt->value); if (cpkt->value) { VIOSerialInitPortConsole(Device,port); } break; case VIRTIO_CONSOLE_RESIZE: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VIRTIO_CONSOLE_RESIZE id = %d\n", cpkt->id); break; case VIRTIO_CONSOLE_PORT_OPEN: if (port) { BOOLEAN Connected = (BOOLEAN)cpkt->value; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_OPEN id = %d, HostConnected = %d\n", cpkt->id, Connected); if (port->HostConnected != Connected) { VIOSerialPortPnpNotify(Device, port, Connected); } // Someone is listening. Trigger a check to see if we have // something waiting to be told. if (port->HostConnected) { WDF_INTERRUPT_INFO info; WDFINTERRUPT *interrupt; WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(pContext->QueuesInterrupt, &info); // Check if MSI is enabled and notify the right interrupt. interrupt = (info.Vector == 0) ? &pContext->WdfInterrupt : &pContext->QueuesInterrupt; WdfInterruptQueueDpcForIsr(*interrupt); } } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "VIRTIO_CONSOLE_PORT_OPEN invalid id = %d\n", cpkt->id); } break; case VIRTIO_CONSOLE_PORT_NAME: if (port) { VIOSerialPortCreateName(Device, port, buf); } break; default: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "%s UNKNOWN event = %d\n", __FUNCTION__, cpkt->event); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); }
NTSTATUS BalloonEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN foundPort = FALSE; PHYSICAL_ADDRESS PortBasePA = {0}; ULONG PortLength = 0; ULONG i; WDF_INTERRUPT_INFO interruptInfo; PDEVICE_CONTEXT devCtx = NULL; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> %s\n", __FUNCTION__); UNREFERENCED_PARAMETER(ResourceList); PAGED_CODE(); devCtx = GetDeviceContext(Device); for (i=0; i < WdfCmResourceListGetCount(ResourceListTranslated); i++) { desc = WdfCmResourceListGetDescriptor( ResourceListTranslated, i ); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfResourceCmGetDescriptor failed\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypePort: if (!foundPort && desc->u.Port.Length >= 0x20) { devCtx->PortMapped = (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; PortBasePA = desc->u.Port.Start; PortLength = desc->u.Port.Length; foundPort = TRUE; if (devCtx->PortMapped) { devCtx->PortBase = (PUCHAR) MmMapIoSpace( PortBasePA, PortLength, MmNonCached ); if (!devCtx->PortBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Unable to map port range %08I64X, length %d\n", PortBasePA.QuadPart, PortLength); return STATUS_INSUFFICIENT_RESOURCES; } devCtx->PortCount = PortLength; } else { devCtx->PortBase = (PUCHAR)(ULONG_PTR) PortBasePA.QuadPart; devCtx->PortCount = PortLength; } } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-> Port Resource [%08I64X-%08I64X]\n", desc->u.Port.Start.QuadPart, desc->u.Port.Start.QuadPart + desc->u.Port.Length); break; default: break; } } if (!foundPort) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Missing resources\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } WDF_INTERRUPT_INFO_INIT(&interruptInfo); WdfInterruptGetInfo(devCtx->WdfInterrupt, &interruptInfo); VirtIODeviceInitialize(&devCtx->VDevice, (ULONG_PTR)devCtx->PortBase, sizeof(devCtx->VDevice)); VirtIODeviceSetMSIXUsed(&devCtx->VDevice, interruptInfo.MessageSignaled); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__); return status; }
NTSTATUS VIOSerialEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesRaw, IN WDFCMRESLIST ResourcesTranslated) { int nListSize = 0; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor; WDF_INTERRUPT_INFO interruptInfo; int i = 0; PPORTS_DEVICE pContext = GetPortsDevice(Device); bool bPortFound = FALSE; NTSTATUS status = STATUS_SUCCESS; UINT nr_ports, max_queues, size_to_allocate; UNREFERENCED_PARAMETER(ResourcesRaw); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<--> %s\n", __FUNCTION__); max_queues = 64; // 2 for each of max 32 ports size_to_allocate = VirtIODeviceSizeRequired((USHORT)max_queues); pContext->pIODevice = (VirtIODevice *)ExAllocatePoolWithTag( NonPagedPool, size_to_allocate, VIOSERIAL_DRIVER_MEMORY_TAG); if (NULL == pContext->pIODevice) { return STATUS_INSUFFICIENT_RESOURCES; } nListSize = WdfCmResourceListGetCount(ResourcesTranslated); for (i = 0; i < nListSize; i++) { if(pResDescriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i)) { switch(pResDescriptor->Type) { case CmResourceTypePort : pContext->bPortMapped = (pResDescriptor->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; pContext->PortBasePA = pResDescriptor->u.Port.Start; pContext->uPortLength = pResDescriptor->u.Port.Length; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IO Port Info [%08I64X-%08I64X]\n", pResDescriptor->u.Port.Start.QuadPart, pResDescriptor->u.Port.Start.QuadPart + pResDescriptor->u.Port.Length); if (pContext->bPortMapped ) { pContext->pPortBase = MmMapIoSpace(pContext->PortBasePA, pContext->uPortLength, MmNonCached); if (!pContext->pPortBase) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> Failed to map IO port!\n", __FUNCTION__); return STATUS_INSUFFICIENT_RESOURCES; } } else { pContext->pPortBase = (PVOID)(ULONG_PTR)pContext->PortBasePA.QuadPart; } bPortFound = TRUE; break; case CmResourceTypeInterrupt: break; } } } if(!bPortFound) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> %s", __FUNCTION__, "IO port wasn't found!\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } WDF_INTERRUPT_INFO_INIT(&interruptInfo); WdfInterruptGetInfo(pContext->WdfInterrupt, &interruptInfo); VirtIODeviceInitialize(pContext->pIODevice, (ULONG_PTR)pContext->pPortBase, size_to_allocate); VirtIODeviceSetMSIXUsed(pContext->pIODevice, interruptInfo.MessageSignaled); VirtIODeviceReset(pContext->pIODevice); VirtIODeviceAddStatus(pContext->pIODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE); pContext->consoleConfig.max_nr_ports = 1; if(pContext->isHostMultiport = VirtIODeviceGetHostFeature(pContext->pIODevice, VIRTIO_CONSOLE_F_MULTIPORT)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "We have multiport host\n"); VirtIODeviceEnableGuestFeature(pContext->pIODevice, VIRTIO_CONSOLE_F_MULTIPORT); VirtIODeviceGet(pContext->pIODevice, FIELD_OFFSET(CONSOLE_CONFIG, max_nr_ports), &pContext->consoleConfig.max_nr_ports, sizeof(pContext->consoleConfig.max_nr_ports)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "VirtIOConsoleConfig->max_nr_ports %d\n", pContext->consoleConfig.max_nr_ports); if (pContext->consoleConfig.max_nr_ports > pContext->pIODevice->maxQueues / 2) { pContext->consoleConfig.max_nr_ports = pContext->pIODevice->maxQueues / 2; TraceEvents(TRACE_LEVEL_WARNING, DBG_PNP, "VirtIOConsoleConfig->max_nr_ports limited to %d\n", pContext->consoleConfig.max_nr_ports); } } if(pContext->isHostMultiport) { WDF_OBJECT_ATTRIBUTES attributes; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Device; status = WdfSpinLockCreate( &attributes, &pContext->CVqLock ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfSpinLockCreate failed 0x%x\n", status); return status; } } else { //FIXME // VIOSerialAddPort(Device, 0); } nr_ports = pContext->consoleConfig.max_nr_ports; pContext->in_vqs = (struct virtqueue**)ExAllocatePoolWithTag( NonPagedPool, nr_ports * sizeof(struct virtqueue*), VIOSERIAL_DRIVER_MEMORY_TAG); if(pContext->in_vqs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,"ExAllocatePoolWithTag failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } memset(pContext->in_vqs, 0, nr_ports * sizeof(struct virtqueue*)); pContext->out_vqs = (struct virtqueue**)ExAllocatePoolWithTag( NonPagedPool, nr_ports * sizeof(struct virtqueue*), VIOSERIAL_DRIVER_MEMORY_TAG ); if(pContext->out_vqs == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "ExAllocatePoolWithTag failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } memset(pContext->out_vqs, 0, nr_ports * sizeof(struct virtqueue*)); pContext->DeviceOK = TRUE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); return status; }
static NTSTATUS VIOSerialInitAllQueues( IN WDFOBJECT Device) { NTSTATUS status = STATUS_SUCCESS; PPORTS_DEVICE pContext = GetPortsDevice(Device); UINT nr_ports, i, j; USHORT ControlVector, QueuesVector; WDF_INTERRUPT_INFO info; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__); WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(pContext->WdfInterrupt, &info); ControlVector = info.MessageSignaled ? 0 : VIRTIO_MSI_NO_VECTOR; WDF_INTERRUPT_INFO_INIT(&info); WdfInterruptGetInfo(pContext->QueuesInterrupt, &info); QueuesVector = (ControlVector != VIRTIO_MSI_NO_VECTOR) ? (info.Vector ? 1 : 0) : VIRTIO_MSI_NO_VECTOR; nr_ports = pContext->consoleConfig.max_nr_ports; if(pContext->isHostMultiport) { nr_ports++; } for(i = 0, j = 0; i < nr_ports; i++) { if(i == 1) // Control Port { if (pContext->c_ivq) VirtIODeviceRenewQueue(pContext->c_ivq); else pContext->c_ivq = FindVirtualQueue(pContext->pIODevice, 2, ControlVector); if (pContext->c_ovq) VirtIODeviceRenewQueue(pContext->c_ovq); else pContext->c_ovq = FindVirtualQueue(pContext->pIODevice, 3, ControlVector); } else { if (pContext->in_vqs[j]) VirtIODeviceRenewQueue(pContext->in_vqs[j]); else pContext->in_vqs[j] = FindVirtualQueue(pContext->pIODevice, i * 2, QueuesVector); if (pContext->out_vqs[j]) VirtIODeviceRenewQueue(pContext->out_vqs[j]); else pContext->out_vqs[j] = FindVirtualQueue(pContext->pIODevice, (i * 2) + 1, QueuesVector); ++j; } } if (pContext->isHostMultiport && (pContext->c_ovq == NULL)) { status = STATUS_NOT_FOUND; } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return status; }