NTSTATUS BalloonInit( IN WDFOBJECT WdfDevice ) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); u32 hostFeatures; u32 guestFeatures; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> BalloonInit\n"); VirtIODeviceReset(&devCtx->VDevice); VirtIODeviceAddStatus(&devCtx->VDevice, VIRTIO_CONFIG_S_ACKNOWLEDGE); VirtIODeviceAddStatus(&devCtx->VDevice, VIRTIO_CONFIG_S_DRIVER); do { if (!devCtx->InfVirtQueue) { devCtx->InfVirtQueue = FindVirtualQueue(&devCtx->VDevice, 0); } else { VirtIODeviceRenewQueue(devCtx->InfVirtQueue); } if (!devCtx->InfVirtQueue) { status = STATUS_INSUFFICIENT_RESOURCES; break; } if (!devCtx->DefVirtQueue) { devCtx->DefVirtQueue = FindVirtualQueue(&devCtx->VDevice, 1); } else { VirtIODeviceRenewQueue(devCtx->DefVirtQueue); } if (!devCtx->DefVirtQueue) { status = STATUS_INSUFFICIENT_RESOURCES; break; } guestFeatures = 0; hostFeatures = VirtIODeviceReadHostFeatures(&devCtx->VDevice); if(VirtIOIsFeatureEnabled(hostFeatures, VIRTIO_BALLOON_F_STATS_VQ)) { BOOLEAN bNeedBuffer = FALSE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> VIRTIO_BALLOON_F_STATS_VQ\n"); if(!devCtx->StatVirtQueue) { devCtx->StatVirtQueue = FindVirtualQueue(&devCtx->VDevice, 2); bNeedBuffer = TRUE; } else { VirtIODeviceRenewQueue(devCtx->StatVirtQueue); } if(!devCtx->StatVirtQueue) { status = STATUS_INSUFFICIENT_RESOURCES; break; } if (bNeedBuffer) { VIO_SG sg; sg.physAddr = MmGetPhysicalAddress(devCtx->MemStats); sg.ulSize = sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR; if(devCtx->StatVirtQueue->vq_ops->add_buf(devCtx->StatVirtQueue, &sg, 1, 0, devCtx, NULL, 0) < 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "<-> %s :: Cannot add buffer\n", __FUNCTION__); } } devCtx->StatVirtQueue->vq_ops->kick(devCtx->StatVirtQueue); VirtIOFeatureEnable(guestFeatures, VIRTIO_BALLOON_F_STATS_VQ); } } while(FALSE); VirtIODeviceWriteGuestFeatures(&devCtx->VDevice, guestFeatures); if(NT_SUCCESS(status)) { VirtIODeviceAddStatus(&devCtx->VDevice, VIRTIO_CONFIG_S_DRIVER_OK); } else { VirtIODeviceAddStatus(&devCtx->VDevice, VIRTIO_CONFIG_S_FAILED); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- BalloonInit\n"); return status; }
NTSTATUS VIOSerialEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesRaw, IN WDFCMRESLIST ResourcesTranslated) { int nListSize = 0; PCM_PARTIAL_RESOURCE_DESCRIPTOR pResDescriptor; int i = 0; PPORTS_DEVICE pContext = GetPortsDevice(Device); bool bPortFound = FALSE; NTSTATUS status = STATUS_SUCCESS; UINT nr_ports, max_queues, size_to_allocate; BOOLEAN MessageSignaled = FALSE; USHORT Interrupts = 0; u32 u32HostFeatures; u32 u32GuestFeatures = 0; 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: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Interrupt Level: 0x%08x, Vector: 0x%08x\n", pResDescriptor->u.Interrupt.Level, pResDescriptor->u.Interrupt.Vector); Interrupts += 1; MessageSignaled = !!(pResDescriptor->Flags & (CM_RESOURCE_INTERRUPT_LATCHED | CM_RESOURCE_INTERRUPT_MESSAGE)); break; } } } if(!bPortFound) { TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "%s>>> %s", __FUNCTION__, "IO port wasn't found!\n"); return STATUS_DEVICE_CONFIGURATION_ERROR; } VirtIODeviceInitialize(pContext->pIODevice, (ULONG_PTR)pContext->pPortBase, size_to_allocate); VirtIODeviceSetMSIXUsed(pContext->pIODevice, MessageSignaled); VirtIODeviceReset(pContext->pIODevice); VirtIODeviceAddStatus(pContext->pIODevice, VIRTIO_CONFIG_S_ACKNOWLEDGE); if (MessageSignaled) { WriteVirtIODeviceWord( pContext->pIODevice->addr + VIRTIO_MSI_CONFIG_VECTOR, Interrupts); Interrupts = ReadVirtIODeviceWord( pContext->pIODevice->addr + VIRTIO_MSI_CONFIG_VECTOR); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "MessageSignaled: %d Interrupts: %x.\n", MessageSignaled, Interrupts); pContext->consoleConfig.max_nr_ports = 1; u32HostFeatures = VirtIODeviceReadHostFeatures(pContext->pIODevice); if(pContext->isHostMultiport = VirtIOIsFeatureEnabled(u32HostFeatures, VIRTIO_CONSOLE_F_MULTIPORT)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "We have multiport host\n"); VirtIOFeatureEnable(u32GuestFeatures, 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); } } VirtIODeviceWriteGuestFeatures(pContext->pIODevice, u32GuestFeatures); 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; }