VOID XenGfxGetPrivateData(XENGFX_DEVICE_EXTENSION *pXenGfxExtension) { NTSTATUS Status; PAGED_CODE(); pXenGfxExtension->PrivateData.Magic = XENGFX_D3D_MAGIC; pXenGfxExtension->PrivateData.Version = XENGFX_D3D_VERSION; // Read PCI values Status = XenGfxReadConfigSpace(pXenGfxExtension->pPhysicalDeviceObject, &(pXenGfxExtension->PrivateData.VendorId), 0, 2); if (!NT_SUCCESS(Status)) { TraceWarning(("XenGfxReadConfigSpace(VendorId) failed - error: 0x%x\n", Status)); // Set a default pXenGfxExtension->PrivateData.VendorId = XENGFX_DEFAULT_VENDORID; } Status = XenGfxReadConfigSpace(pXenGfxExtension->pPhysicalDeviceObject, &(pXenGfxExtension->PrivateData.DeviceId), 2, 2); if (!NT_SUCCESS(Status)) { TraceWarning(("XenGfxReadConfigSpace(DeviceId) failed - error: 0x%x\n", Status)); // Set a default pXenGfxExtension->PrivateData.DeviceId = XENGFX_DEFAULT_DEVICEID; } pXenGfxExtension->PrivateData.ApertureSize = PAGE_SIZE*pXenGfxExtension->GartPfns; RtlMoveMemory(&(pXenGfxExtension->PrivateData.AdapterGuid), &(pXenGfxExtension->DxgkStartInfo.AdapterGuid), sizeof(GUID)); }
/* Find the path to the backend associated with @sf. The backend path remains correct as long as @token remains extant. The caller must XmFreeMemory() the returned string. Returns NULL on error. */ static char * get_backend_path(struct scsifilt *sf, SUSPEND_TOKEN token) { char *res; char *res_nul; NTSTATUS stat; size_t s; UNREFERENCED_PARAMETER(token); stat = xenbus_read_bin(XBT_NIL, sf->frontend_path, "backend", &res, &s); if (!NT_SUCCESS(stat)) { TraceWarning(("%x reading backend path.\n", stat)); return NULL; } res_nul = XmAllocateMemory(s + 1); if (!res_nul) { TraceWarning(("Can't get %d bytes for backend path\n", s)); XmFreeMemory(res); return NULL; } memcpy(res_nul, res, s); res_nul[s] = 0; XmFreeMemory(res); return res_nul; }
VOID __XenevtchnInitIoHole(const char *module, PHYSICAL_ADDRESS base, PVOID base_va, ULONG nbytes) { if (!AustereMode && io_hole_initialized) { TraceWarning(("IO hole already initialized by %s\n", io_hole_owner)); return; } io_hole_start = base; io_hole_va_start = base_va; io_hole_nr_pages = MAX(IO_HOLE_MAX_PAGES, (nbytes / PAGE_SIZE)); /* For some reason, RtlInitializeBitmap() isn't allowed to be called above APC level, although all the other bitmap functions work at any irql. Duplicate the entire thing here. */ io_hole_in_use.SizeOfBitMap = io_hole_nr_pages; io_hole_in_use.Buffer = io_hole_bitmap; strncpy(io_hole_owner, module, sizeof(io_hole_owner)); io_hole_owner[sizeof(io_hole_owner) - 1] = '\0'; io_hole_initialized = TRUE; TraceNotice(("%s: IO hole: [%016llx,%016llx) mapped at %p\n", io_hole_owner, io_hole_start.QuadPart, io_hole_start.QuadPart + (io_hole_nr_pages * PAGE_SIZE), io_hole_va_start)); }
static BOOLEAN BalloonPopulatePfnArray( IN ULONG Requested, OUT PULONG pPopulated ) { xen_memory_reservation_t reservation; LARGE_INTEGER Start; LARGE_INTEGER End; ULONGLONG TimeDelta; BOOLEAN Slow; ULONG Populated; XM_ASSERT(Requested <= BALLOON_PFN_ARRAY_SIZE); KeQuerySystemTime(&Start); RangeSetPopMany(&(Balloon.PfnsBalloonedOut), &(Balloon.PfnArray[0]), Requested); SET_XEN_GUEST_HANDLE(reservation.extent_start, Balloon.PfnArray); reservation.extent_order = 0; reservation.mem_flags = 0; // unused reservation.domid = DOMID_SELF; reservation.nr_extents = Requested; Populated = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); if (Populated < Requested) { Balloon.PartialPopulate++; // This should not fail as we're simply handing back part of a range we'd previously popped. RangeSetAddItems(&(Balloon.PfnsBalloonedOut), &(Balloon.PfnArray[Populated]), Requested - Populated); } else if (Populated > Requested) { XM_BUG(); } RangeSetDropRseCache(&(Balloon.PfnsBalloonedOut)); TraceVerbose(("%s: %d page(s)\n", __FUNCTION__, Populated)); KeQuerySystemTime(&End); TimeDelta = (End.QuadPart - Start.QuadPart) / 10000ull; Slow = FALSE; if (TimeDelta != 0) { ULONGLONG Rate; Rate = (ULONGLONG)(Populated * 1000) / TimeDelta; if (Rate < MIN_PAGES_PER_S) { TraceWarning(("%s: ran for more than %dms\n", __FUNCTION__, TimeDelta)); Slow = TRUE; } } *pPopulated = Populated; return Slow; }
BOOLEAN XenLowerBackendInit( PXEN_LOWER XenLower) { PCHAR path; NTSTATUS status; // Note this is split from the XenLowerInit so it can be called on the resume // path in case backend values change. XXX_TODO("--XT-- All the backend path handling assumes dom0 is the backend, this will change for device domains") // XXX TODO all the backend path handling assumes dom0 is the backend. This will // not necessarily be true with device domains. The changes to support this go // beyond this module though. path = XenLowerReadXenstoreValue(XenLower->FrontendPath, "backend"); if (path == NULL) { TraceError((__FUNCTION__ ": XenLowerReadXenstoreValue() failed to return the back end path, fatal.\n")); return FALSE; } status = RtlStringCchCopyA(XenLower->BackendPath, sizeof(XenLower->BackendPath), path); XmFreeMemory(path); if (status != STATUS_SUCCESS) { XenLower->BackendPath[0] = 0; TraceError((__FUNCTION__ ": Failed to copy back end path - status: 0x%x\n", status)); return FALSE; } status = xenbus_read_domain_id(XBT_NIL, XenLower->FrontendPath, "backend-id", &XenLower->BackendDomid); if (!NT_SUCCESS(status)) { TraceWarning((__FUNCTION__ ": Failed to read backend id from %s (%x), setting to dom0\n", XenLower->FrontendPath, status)); XenLower->BackendDomid = DOMAIN_ID_0(); } // XXX TODO for now we only support a dom0 backend so check that here. Later // when we support a device domain for vusb, other domids will be fine. XXX_TODO("--XT-- For now we only support a dom0 backend so check that here"); if (unwrap_DOMAIN_ID(XenLower->BackendDomid) != unwrap_DOMAIN_ID(DOMAIN_ID_0())) { TraceError((XENTARGET ": cannot connect to backend Domid: %d, only dom0 supported currently\n", XenLower->BackendDomid)); return FALSE; } TraceInfo((__FUNCTION__ ": XenLower initialized - FrontendPath: %s BackendPath: %s BackendDomid: %d\n", XenLower->FrontendPath, XenLower->BackendPath, unwrap_DOMAIN_ID(XenLower->BackendDomid))); return TRUE; }
static NTSTATUS V4vInitializeEventChannel(PDEVICE_OBJECT fdo) { XENV4V_EXTENSION *pde = V4vGetDeviceExtension(fdo); KLOCK_QUEUE_HANDLE lqh; KeAcquireInStackQueuedSpinLock(&pde->virqLock, &lqh); if (!is_null_EVTCHN_PORT(pde->virqPort)) { KeReleaseInStackQueuedSpinLock(&lqh); TraceWarning(("V4V VIRQ already bound?\n")); return STATUS_SUCCESS; } pde->virqPort = EvtchnBindVirq(VIRQ_V4V, V4vVirqNotifyIsr, fdo); if (is_null_EVTCHN_PORT(pde->virqPort)) { KeReleaseInStackQueuedSpinLock(&lqh); TraceError(("failed to bind V4V VIRQ\n")); return STATUS_INSUFFICIENT_RESOURCES; } KeReleaseInStackQueuedSpinLock(&lqh); TraceNotice(("V4V VIRQ connected.\n")); return STATUS_SUCCESS; }
static NTSTATUS V4vCtrlListen(XENV4V_CONTEXT *ctx, V4V_LISTEN_VALUES *lvs) { LONG val; ULONG32 size; val = InterlockedExchangeAdd(&ctx->state, 0); if (val != XENV4V_STATE_BOUND) { TraceWarning(("state not BOUND, cannot complete connect listen\n")); return STATUS_INVALID_DEVICE_REQUEST; } if (lvs->backlog > V4V_SOMAXCONN) { TraceWarning(("backlog cannot be larger than V4V_SOMAXCONN: %d\n", V4V_SOMAXCONN)); return STATUS_INVALID_PARAMETER; } // Initialize the listener specific pieces of the context KeInitializeSpinLock(&ctx->u.listener.synLock); ctx->u.listener.synHead = NULL; ctx->u.listener.synTail = NULL; ctx->u.listener.synCount = 0; if (lvs->backlog == 0) { ctx->u.listener.backlog = V4V_SOMAXCONN; } else { ctx->u.listener.backlog = (LONG)lvs->backlog; } size = ctx->u.listener.backlog*sizeof(XENV4V_SYN); ctx->u.listener.synList = (XENV4V_SYN*)ExAllocatePoolWithTag(NonPagedPool, size, XENV4V_TAG); if (ctx->u.listener.synList == NULL) { TraceWarning(("listen failed, out of memory\n")); return STATUS_NO_MEMORY; } RtlZeroMemory(ctx->u.listener.synList, size); // Now it becomes a listener type for ever more InterlockedExchange(&ctx->type, XENV4V_TYPE_LISTENER); // After this transition the ring is ready to receive SYNs for new connections InterlockedExchange(&ctx->state, XENV4V_STATE_LISTENING); return STATUS_SUCCESS; }
static BOOLEAN NTAPI XenGfxInitializeEdid(PXENGFX_DEVICE_EXTENSION pXenGfxExtension) { UCHAR Sum = 0; ULONG i; UCHAR *pEdidBuf; int notDone; PUCHAR edidOffset = pXenGfxExtension->pVCrtc0 + XGFX_VCRTC_EDID; PULONG pEdid; // Allocate a single page for the VCRTC0 EDID and fetch it. pXenGfxExtension->pEdid = XenGfxAllocateContiguousPages(1); if (pXenGfxExtension->pEdid == NULL) { TraceError(("%s Failed to allocate EDID page!\n", __FUNCTION__)); return FALSE; } pEdid = (PULONG)pXenGfxExtension->pEdid; //Request memory VideoPortWriteRegisterUlong((PULONG)(pXenGfxExtension->pVCrtc0 + XGFX_VCRTC_EDID_REQUEST), 1); do { notDone = VideoPortReadRegisterUlong( (PULONG) (pXenGfxExtension->pVCrtc0 + XGFX_VCRTC_EDID_REQUEST)); }while (notDone); for (i = 0; i < 4096/sizeof(ULONG); i++) { pEdid[i] = VideoPortReadRegisterUlong( (PULONG) (edidOffset + (i * sizeof(ULONG)))); } // Check the checksum pEdidBuf = (UCHAR*)pXenGfxExtension->pEdid; for (i = 0; i < XENGFX_EDID_SIZE; i++) Sum += pEdidBuf[i]; if (Sum != 0) { TraceWarning(("%s EDID checksum is not valid.\n", __FUNCTION__)); } // The XDDM driver will not attempt to report extensions after the EDID. Clear // the Extension flag. if (pXenGfxExtension->pEdid->ExtensionFlag[0] != 0) { pXenGfxExtension->pEdid->ExtensionFlag[0] = 0; Sum = 1; } // Recalculate the checksum if needed. if (Sum != 0) { Sum = 0; pXenGfxExtension->pEdid->Checksum[0] = 0; for (i = 0; i < XENGFX_EDID_SIZE; i++) Sum += pEdidBuf[i]; pXenGfxExtension->pEdid->Checksum[0] = -Sum; } return TRUE; }
static NTSTATUS V4vCtrlConnect(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, V4V_CONNECT_VALUES *cvs, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; LONG val; XENV4V_INSERT ins = {FALSE}; val = InterlockedExchangeAdd(&ctx->state, 0); if (val != XENV4V_STATE_BOUND) { TraceWarning(("state not BOUND, cannot complete connect request\n")); return STATUS_INVALID_DEVICE_REQUEST; } // Any IRPs that are queued are given a sanity initialization V4vInitializeIrp(irp); // These stream related values are only set once during a single phase of transitioning // to a stream type. ctx->sdst = cvs->ringAddr; ctx->connId = (ULONG64)(RtlRandomEx(&pde->seed) & 0xffffffff); // Update the stream header in the IRPs buffer. The cvs pointer points to the IRPs actual // in/out buffer the IOCTL is defined to have output. cvs->sh.flags = V4V_SHF_SYN; cvs->sh.conid = (ULONG32)ctx->connId; // Now it becomes a connector type for ever more InterlockedExchange(&ctx->type, XENV4V_TYPE_CONNECTOR); // After this transition, we will still send a SYN datagram and get the ACK InterlockedExchange(&ctx->state, XENV4V_STATE_CONNECTING); // Start the connecting timer each time a context goes into this state. V4vStartConnectionTimer(pde); // Flag it irp->Tail.Overlay.DriverContext[0] = (PVOID)(ULONG_PTR)(XENV4V_PEEK_STREAM|XENV4V_PEEK_WRITE|XENV4V_PEEK_SYN|XENV4V_PEEK_IOCTL); // Always queue it to the back and marks it pending status = IoCsqInsertIrpEx(&pde->csqObject, irp, NULL, &ins); if (NT_SUCCESS(status)) { status = STATUS_PENDING; // Drive any write IO V4vProcessContextWrites(pde, ctx); } else { // Fail it in IOCTL routine and return go to disconnected state V4vStopConnectionTimer(pde, FALSE); InterlockedExchange(&ctx->state, XENV4V_STATE_DISCONNECTED); } return status; }
static NTSTATUS V4vCtrlConnectWait(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, V4V_WAIT_VALUES *wvs, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; LONG val; XENV4V_INSERT ins = {FALSE}; // This is the connect wait functionality that allows a single end to end // stream connection. This part serves as the "listening" end. val = InterlockedExchangeAdd(&ctx->state, 0); if (val != XENV4V_STATE_BOUND) { TraceWarning(("state not BOUND, cannot complete connect wait request\n")); return STATUS_INVALID_DEVICE_REQUEST; } // Any IRPs that are queued are given a sanity initialization V4vInitializeIrp(irp); // Update the stream header in the IRPs buffer. Just clear if now, later it will // be used for the ACK. wvs->sh.flags = 0; wvs->sh.conid = 0; // Now it becomes a connector type for ever more InterlockedExchange(&ctx->type, XENV4V_TYPE_CONNECTOR); // After this transition, we will wait to get a SYN and send back the ACK InterlockedExchange(&ctx->state, XENV4V_STATE_WAITING); // Flag it irp->Tail.Overlay.DriverContext[0] = (PVOID)(ULONG_PTR)(XENV4V_PEEK_STREAM|XENV4V_PEEK_READ|XENV4V_PEEK_SYN|XENV4V_PEEK_IOCTL); // Always queue it to the back and marks it pending status = IoCsqInsertIrpEx(&pde->csqObject, irp, NULL, &ins); if (NT_SUCCESS(status)) { status = STATUS_PENDING; // Drive any read IO V4vProcessContextReads(pde, ctx); } else { // Fail it in IOCTL routine and return go to disconnected state InterlockedExchange(&ctx->state, XENV4V_STATE_DISCONNECTED); } return status; }
BOOLEAN NTAPI XenGfxVbeGetModeInfo(USHORT ModeNumber, VBE_MODE_INFO* pVbeModeInfo) { const MODE_INFO_ITEM *pCurrentMode; BOOLEAN UsingLFB; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); if (!g_VbeInfoInitialized) { return FALSE; } if (pVbeModeInfo == NULL) { return FALSE; } RtlZeroMemory(pVbeModeInfo, sizeof(VBE_MODE_INFO)); UsingLFB = ((ModeNumber & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER) ? TRUE : FALSE; ModeNumber &= 0x1ff; // The spinlock is not needed since this routine just reads values from the // local mode table or from vbe ports. pCurrentMode = XenGfxFindMode(ModeNumber, UsingLFB); if (pCurrentMode == NULL) { TraceWarning(("VBE mode %04x NOT FOUND??\n", ModeNumber)); return FALSE; } TraceVerbose(("Found VBE mode 0x%04x\n", ModeNumber)); RtlCopyMemory(pVbeModeInfo, &pCurrentMode->ModeInfo, sizeof(VBE_MODE_INFO)); // Fix it up a bit. Setting WinFuncPtr for VBE_WINDOW_ATTRIBUTE_RELOCATABLE is probably not so useful... if (UsingLFB) { pVbeModeInfo->NumberOfBanks = 1; } WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_LFB_ADDRESS_H); pVbeModeInfo->PhysBasePtr = READ_PORT_USHORT((USHORT*)VBE_PORT_DATA); pVbeModeInfo->PhysBasePtr = pVbeModeInfo->PhysBasePtr << 16; TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return TRUE; }
//---------------------------------------------------------------------------------------------------------------------------- VOID Subsystem::Destroy() { Trace0Enter(""); m_State = 0; if (m_pThread) { TraceInfo(this, "Waiting for subsystem to terminate itself"); if (!m_pThread->Wait(2000)) { TraceWarning(this, "The subsystem manager timed-out whilst waiting for the subsystem to terminate. Subsystem will be forcably terminated"); m_pThread->Terminate(); } m_pThread = 0; } }
static NTSTATUS XenWorkItemDispatch( IN struct xm_thread *pSelf, IN VOID *Argument ) { KIRQL Irql; UNREFERENCED_PARAMETER(Argument); while (XmThreadWait(pSelf) >= 0) { Irql = acquire_irqsafe_lock(&WorkItemDispatchLock); while (!IsListEmpty(&PendingWorkItems)) { PLIST_ENTRY Head; XEN_WORKITEM *Item; Head = RemoveHeadList(&PendingWorkItems); Item = CurrentItem = CONTAINING_RECORD(Head, XEN_WORKITEM, List); release_irqsafe_lock(&WorkItemDispatchLock, Irql); XM_ASSERT(CurrentItem->Magic == WORKITEM_MAGIC); KeQuerySystemTime(&Item->Start); TraceVerbose(("%s: invoking '%s'\n", __FUNCTION__, CurrentItem->Name)); CurrentItem->Work(CurrentItem->Context); Irql = acquire_irqsafe_lock(&WorkItemDispatchLock); CurrentItem = NULL; release_irqsafe_lock(&WorkItemDispatchLock, Irql); XmFreeMemory(Item); Irql = acquire_irqsafe_lock(&WorkItemDispatchLock); } release_irqsafe_lock(&WorkItemDispatchLock, Irql); } TraceWarning(("%s: terminating.\n", __FUNCTION__)); return STATUS_SUCCESS; }
PVOID XenevtchnAllocIoMemory(ULONG nr_bytes, PHYSICAL_ADDRESS *pa) { KIRQL old_irql; ULONG page_nr; nr_bytes = (nr_bytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); old_irql = acquire_irqsafe_lock(&io_hole_lock); page_nr = RtlFindClearBitsAndSet(&io_hole_in_use, nr_bytes / PAGE_SIZE, 0); release_irqsafe_lock(&io_hole_lock, old_irql); if (page_nr == 0xffffffff) { TraceWarning (("Filled the io hole!\n")); return NULL; } else { pa->QuadPart = io_hole_start.QuadPart + page_nr * PAGE_SIZE; return (PVOID)((ULONG_PTR)io_hole_va_start + page_nr * PAGE_SIZE); } }
NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath) { UNREFERENCED_PARAMETER(registryPath); TraceVerbose(("====> '%s'.\n", __FUNCTION__)); PsGetVersion(&g_osMajorVersion, &g_osMinorVersion, NULL, NULL); if ((g_osMajorVersion < 5)||((g_osMajorVersion == 5)&&(g_osMinorVersion < 1))) { TraceWarning(("Windows XP or later operating systems supported!\n")); return STATUS_UNSUCCESSFUL; } TraceInfo(("Starting driver...\n")); driverObject->DriverUnload = V4vDriverUnload; driverObject->DriverExtension->AddDevice = V4vAddDevice; driverObject->MajorFunction[IRP_MJ_CREATE] = V4vDispatchCreate; driverObject->MajorFunction[IRP_MJ_CLEANUP] = V4vDispatchCleanup; driverObject->MajorFunction[IRP_MJ_CLOSE] = V4vDispatchClose; driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = V4vDispatchDeviceControl; driverObject->MajorFunction[IRP_MJ_READ] = V4vDispatchRead; driverObject->MajorFunction[IRP_MJ_WRITE] = V4vDispatchWrite; driverObject->MajorFunction[IRP_MJ_PNP] = V4vDispatchPnP; driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = V4vDispatchWmi; driverObject->MajorFunction[IRP_MJ_POWER] = V4vDispatchPower; // The rest can be handled by the system not supported routine TraceVerbose(("DriverEntry returning successfully\n")); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return STATUS_SUCCESS; }
static NTSTATUS XenLowerConnectBackendInternal( PXEN_LOWER XenLower, SUSPEND_TOKEN Token) { NTSTATUS status = STATUS_SUCCESS; XENBUS_STATE state; xenbus_transaction_t xbt; PCHAR fepath; if (is_null_EVTCHN_PORT(XenLower->EvtchnPort)) { TraceError((__FUNCTION__ ": no event channel port, this routine must be called after event channel initialization\n")); return STATUS_UNSUCCESSFUL; } //---------------------------Backend Wait Ready-------------------------------// // // Wait for backend to get ready for initialization. // status = xenbus_change_state(XBT_NIL, XenLower->FrontendPath, "state", XENBUS_STATE_INITIALISING); if (!NT_SUCCESS(status)) { TraceWarning((__FUNCTION__ ": Failed to change front end state to XENBUS_STATE_INITIALISING(%d) status: 0x%x\n", XENBUS_STATE_INITIALISING, status)); // Go on, best effort, chin up } TraceInfo((__FUNCTION__ ": Front end state set to XENBUS_STATE_INITIALISING(%d)\n", XENBUS_STATE_INITIALISING)); state = null_XENBUS_STATE(); for ( ; ; ) { // Turns out suspend tokens are not even used. state = XenbusWaitForBackendStateChange(XenLower->BackendPath, state, NULL, Token); if (same_XENBUS_STATE(state, XENBUS_STATE_INITWAIT)) { break; } if (same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) || is_null_XENBUS_STATE(state)) { TraceError((__FUNCTION__ ": backend '%s' went away before we could connect to it?\n", XenLower->BackendPath)); status = STATUS_UNSUCCESSFUL; break; } } if (status != STATUS_SUCCESS) { return status; } TraceInfo((__FUNCTION__ ": Back end state went to XENBUS_STATE_INITWAIT(%d)\n", XENBUS_STATE_INITWAIT)); //----------------------------Backend Connect---------------------------------// // // Communicate configuration to backend. // fepath = XenLower->FrontendPath; do { xenbus_transaction_start(&xbt); xenbus_write_grant_ref(xbt, fepath, "ring-ref", XenLower->SringGrantRef); xenbus_write_evtchn_port(xbt, fepath, "event-channel", XenLower->EvtchnPort); xenbus_change_state(xbt, fepath, "state", XENBUS_STATE_CONNECTED); status = xenbus_transaction_end(xbt, 0); } while (status == STATUS_RETRY); if (status != STATUS_SUCCESS) { TraceError((__FUNCTION__ ": failed to configure xenstore frontend values.\n")); return STATUS_UNSUCCESSFUL; } TraceInfo((__FUNCTION__ ": Front end state set to XENBUS_STATE_CONNECTED(%d)\n", XENBUS_STATE_CONNECTED)); // // Wait for backend to accept configuration and complete initialization. // state = null_XENBUS_STATE(); for ( ; ; ) { state = XenbusWaitForBackendStateChange(XenLower->BackendPath, state, NULL, Token); if (is_null_XENBUS_STATE(state) || same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) || same_XENBUS_STATE(state, XENBUS_STATE_CLOSED)) { TraceError((__FUNCTION__ ": Failed to connected '%s' <-> '%s' backend state: %d\n", XenLower->FrontendPath, XenLower->BackendPath, state)); status = STATUS_UNSUCCESSFUL; break; } if (same_XENBUS_STATE(state, XENBUS_STATE_CONNECTED)) { TraceNotice((__FUNCTION__ ": Connected '%s' <-> '%s' \n", XenLower->FrontendPath, XenLower->BackendPath)); TraceInfo((__FUNCTION__ ": Back end final state went to XENBUS_STATE_CONNECTED(%d)\n", XENBUS_STATE_CONNECTED)); break; } } return status; }
static NTSTATUS V4vAddDevice(PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING deviceName; PDEVICE_OBJECT fdo = NULL; PXENV4V_EXTENSION pde = NULL; LONG val; BOOLEAN symlink = FALSE; LARGE_INTEGER seed; WCHAR *szSddl = NULL; UNICODE_STRING sddlString; CHAR *szFpath = NULL; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); // We only allow one instance of this device type. If more than on pdo is created we need val = InterlockedCompareExchange(&g_deviceCreated, 1, 0); if (val != 0) { TraceWarning(("cannot instantiate more that one v4v device node.\n")); return STATUS_UNSUCCESSFUL; } do { // Create our device RtlInitUnicodeString(&deviceName, V4V_DEVICE_NAME); szSddl = g_win5Sddl; RtlInitUnicodeString(&sddlString, szSddl); status = IoCreateDeviceSecure(driverObject, sizeof(XENV4V_EXTENSION), &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &sddlString, (LPCGUID)&GUID_SD_XENV4V_CONTROL_OBJECT, &fdo); if (!NT_SUCCESS(status)) { TraceError(("failed to create device object - error: 0x%x\n", status)); fdo = NULL; break; } pde = (PXENV4V_EXTENSION)fdo->DeviceExtension; RtlZeroMemory(pde, sizeof(XENV4V_EXTENSION)); RtlStringCchCopyW(pde->symbolicLinkText, XENV4V_SYM_NAME_LEN, V4V_SYMBOLIC_NAME); RtlInitUnicodeString(&pde->symbolicLink, pde->symbolicLinkText); // Create our symbolic link status = IoCreateSymbolicLink(&pde->symbolicLink, &deviceName); if (!NT_SUCCESS(status)) { TraceError(("failed to create symbolic - error: 0x%x\n", status)); break; } symlink = TRUE; // Get our xenstore path szFpath = xenbus_find_frontend(pdo); if (szFpath == NULL) { status = STATUS_NO_SUCH_DEVICE; TraceError(("failed to locate XenStore front end path\n")); break; } // Setup the extension pde->magic = XENV4V_MAGIC; pde->pdo = pdo; pde->fdo = fdo; IoInitializeRemoveLock(&pde->removeLock, 'v4vx', 0, 0); pde->frontendPath = szFpath; szFpath = NULL; pde->state = XENV4V_DEV_STOPPED; // wait for start pde->lastPoState = PowerSystemWorking; pde->virqPort = null_EVTCHN_PORT(); KeInitializeDpc(&pde->virqDpc, V4vVirqNotifyDpc, fdo); KeInitializeSpinLock(&pde->virqLock); KeInitializeSpinLock(&pde->dpcLock); KeInitializeTimerEx(&pde->timer, NotificationTimer); KeInitializeDpc(&pde->timerDpc, V4vConnectTimerDpc, fdo); KeInitializeSpinLock(&pde->timerLock); pde->timerCounter = 0; InitializeListHead(&pde->contextList); KeInitializeSpinLock(&pde->contextLock); pde->contextCount = 0; InitializeListHead(&pde->ringList); KeInitializeSpinLock(&pde->ringLock); InitializeListHead(&pde->pendingIrpQueue); pde->pendingIrpCount = 0; KeInitializeSpinLock(&pde->queueLock); IoCsqInitializeEx(&pde->csqObject, V4vCsqInsertIrpEx, V4vCsqRemoveIrp, V4vCsqPeekNextIrp, V4vCsqAcquireLock, V4vCsqReleaseLock, V4vCsqCompleteCanceledIrp); InitializeListHead(&pde->destList); pde->destCount = 0; ExInitializeNPagedLookasideList(&pde->destLookasideList, NULL, NULL, 0, sizeof(XENV4V_DESTINATION), XENV4V_TAG, 0); KeQueryTickCount(&seed); pde->seed = seed.u.LowPart; // Now attach us to the stack pde->ldo = IoAttachDeviceToDeviceStack(fdo, pdo); if (pde->ldo == NULL) { TraceError(("failed to attach device to stack - error: 0x%x\n", status)); status = STATUS_NO_SUCH_DEVICE; break; } // Use direct IO and let the IO manager directly map user buffers; clear the init flag fdo->Flags |= DO_DIRECT_IO; fdo->Flags &= ~DO_DEVICE_INITIALIZING; // Made it here, go to connected state to be consistent xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CONNECTED); } while (FALSE); if (!NT_SUCCESS(status)) { if (fdo != NULL) { if ((pde != NULL)&&(pde->ldo != NULL)) { IoDetachDevice(pde->ldo); } if (szFpath != NULL) { XmFreeMemory(szFpath); } if (symlink) { IoDeleteSymbolicLink(&pde->symbolicLink); } IoDeleteDevice(fdo); } } TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return status; }
NDIS_STATUS MiniportInitialize ( IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE MiniportDriverContext, IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters ) { PADAPTER adapter = NULL; NDIS_STATUS ndisStatus; PCHAR path; PDEVICE_OBJECT pdo; PCHAR xenbusPath = NULL; int i; UNREFERENCED_PARAMETER(MiniportDriverContext); UNREFERENCED_PARAMETER(MiniportInitParameters); TraceVerbose(("====> '%s'.\n", __FUNCTION__)); // // Wait for xenbus to come up. SMP guests sometimes try and // initialise xennet and xenvbd in parallel when they come back // from hibernation, and that causes problems. // if (!xenbus_await_initialisation()) { ndisStatus = NDIS_STATUS_DEVICE_FAILED; goto exit; } // // 8021P support is disabled by default. // It can be turned on by specifying the appropriate PV boot option. // if (XenPVFeatureEnabled(DEBUG_NIC_8021_P)) { XennetMacOptions |= NDIS_MAC_OPTION_8021P_PRIORITY; } xenbus_write(XBT_NIL, "drivers/xenwnet", XENNET_VERSION); NdisMGetDeviceProperty(MiniportAdapterHandle, &pdo, NULL, NULL, NULL, NULL); xenbusPath = xenbus_find_frontend(pdo); if (!xenbusPath) { ndisStatus = NDIS_STATUS_ADAPTER_NOT_FOUND; goto exit; } TraceNotice(("Found '%s' frontend.\n", xenbusPath)); adapter = XmAllocateZeroedMemory(sizeof(ADAPTER)); if (adapter == NULL) { ndisStatus = NDIS_STATUS_RESOURCES; goto exit; } path = xenbusPath; xenbusPath = NULL; i = 0; do { ndisStatus = AdapterInitialize(adapter, MiniportAdapterHandle, path); if (ndisStatus != NDIS_STATUS_SUCCESS) { TraceWarning (("Waiting for backend...\n")); NdisMSleep (1000000); // 1 sec } } while ((ndisStatus != NDIS_STATUS_SUCCESS) && (++i < 30)); if (ndisStatus != NDIS_STATUS_SUCCESS) { goto exit; } exit: if (ndisStatus != NDIS_STATUS_SUCCESS) { if (adapter) { XmFreeMemory(adapter->BackendPath); adapter->BackendPath = NULL; AdapterDelete(&adapter); } if (xenbusPath) { XmFreeMemory(xenbusPath); } } TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return ndisStatus; }
/* srb is kind of half const here. We never modify it directly, but it will obviously get modified when it completes. */ static void allocate_irp_and_resubmit_srb(struct scsifilt *sf, SCSI_REQUEST_BLOCK *srb_) { const SCSI_REQUEST_BLOCK *const srb = srb_; PIRP irp; PIO_STACK_LOCATION isl; PVOID buf; PMDL mdl; PSCSI_REQUEST_BLOCK new_srb; irp = NULL; mdl = NULL; new_srb = NULL; buf = ExAllocatePoolWithTag(NonPagedPool, srb->DataTransferLength, 'ssrx'); if (!buf) goto err; memcpy(buf, srb->DataBuffer, srb->DataTransferLength); new_srb = XmAllocateZeroedMemory(sizeof(*new_srb)); if (!new_srb) goto err; new_srb->Length = sizeof(*new_srb); new_srb->Function = srb->Function; XM_ASSERT3U(new_srb->Function, ==, SRB_FUNCTION_EXECUTE_SCSI); new_srb->SrbFlags = srb->SrbFlags; new_srb->PathId = srb->PathId; new_srb->TargetId = srb->TargetId; new_srb->Lun = srb->Lun; new_srb->QueueTag = srb->QueueTag; new_srb->QueueAction = srb->QueueAction; new_srb->DataTransferLength = srb->DataTransferLength; new_srb->DataBuffer = buf; new_srb->OriginalRequest = (PVOID)srb; new_srb->CdbLength = srb->CdbLength; memcpy(new_srb->Cdb, srb->Cdb, srb->CdbLength); irp = IoAllocateIrp(2, FALSE); if (!irp) goto err; mdl = IoAllocateMdl(buf, new_srb->DataTransferLength, FALSE, FALSE, irp); if (!mdl) goto err; MmBuildMdlForNonPagedPool(mdl); IoSetNextIrpStackLocation(irp); isl = IoGetCurrentIrpStackLocation(irp); isl->Parameters.Scsi.Srb = new_srb; isl->DeviceObject = sf->fdo; IoSetCompletionRoutine(irp, redirect_irp_completion, NULL, TRUE, TRUE, TRUE); IoSetNextIrpStackLocation(irp); isl = IoGetCurrentIrpStackLocation(irp); isl->MajorFunction = IRP_MJ_SCSI; isl->MinorFunction = 0; isl->Parameters.Scsi.Srb = new_srb; isl->DeviceObject = sf->fdo; filter_process_irp(sf, irp, new_srb); return; err: TraceWarning(("Failed to set up redirected SRB\n")); if (irp) IoFreeIrp(irp); if (mdl) IoFreeMdl(mdl); if (buf) ExFreePool(buf); if (new_srb) XmFreeMemory(new_srb); queue_srb_for_error(sf, (PSCSI_REQUEST_BLOCK)srb); }
static BOOLEAN BalloonFreePfnArray( IN ULONG Requested, IN BOOLEAN Check, OUT PULONG pFreed ) { ULONG Index; ULONG Freed; MDL *Mdl; LARGE_INTEGER Start; LARGE_INTEGER End; ULONGLONG TimeDelta; BOOLEAN Slow; XM_ASSERT(Requested <= BALLOON_PFN_ARRAY_SIZE); KeQuerySystemTime(&Start); Freed = 0; if (Requested == 0) goto done; for (Index = 0; Index < Requested; Index++) { if (Balloon.PfnArray[Index] == 0) { TraceError(("%s: PFN[%d] == 0\n", __FUNCTION__, Index)); XM_BUG(); } } Mdl = &(Balloon.Mdl); Mdl->Next = NULL; Mdl->Size = (SHORT)(sizeof(MDL) + (sizeof(PFN_NUMBER) * Requested)); Mdl->MdlFlags = MDL_PAGES_LOCKED; Mdl->Process = NULL; Mdl->MappedSystemVa = NULL; Mdl->StartVa = NULL; Mdl->ByteCount = Requested << PAGE_SHIFT; Mdl->ByteOffset = 0; BalloonFreePagesFromMdl(Mdl, Check); Freed = Requested; RtlZeroMemory(Balloon.PfnArray, Freed * sizeof (PFN_NUMBER)); done: TraceVerbose(("%s: %d page(s)\n", __FUNCTION__, Freed)); KeQuerySystemTime(&End); TimeDelta = (End.QuadPart - Start.QuadPart) / 10000ull; Slow = FALSE; if (TimeDelta != 0) { ULONGLONG Rate; Rate = (ULONGLONG)(Freed * 1000) / TimeDelta; if (Rate < MIN_PAGES_PER_S) { TraceWarning(("%s: ran for more than %dms\n", __FUNCTION__, TimeDelta)); Slow = TRUE; } } *pFreed = Freed; return Slow; }
static BOOLEAN BalloonReleasePfnArray( IN ULONG Requested, OUT PULONG pReleased ) { xen_memory_reservation_t reservation; LARGE_INTEGER Start; LARGE_INTEGER End; ULONGLONG TimeDelta; BOOLEAN Slow; ULONG Index; ULONG Registered; ULONG Released; XM_ASSERT(Requested <= BALLOON_PFN_ARRAY_SIZE); KeQuerySystemTime(&Start); Released = 0; if (Requested == 0) goto done; for (Index = 0; Index < Requested; Index++) { if (Balloon.PfnArray[Index] == 0) { TraceError(("%s: PFN[%d] == 0\n", __FUNCTION__, Index)); XM_BUG(); } } Registered = RangeSetAddItems(&(Balloon.PfnsBalloonedOut), &(Balloon.PfnArray[0]), Requested); if (Registered < Requested) { TraceError(("%s: failed to register %d page(s)\n", __FUNCTION__, Requested - Registered)); if (Registered == 0) goto done; } SET_XEN_GUEST_HANDLE(reservation.extent_start, Balloon.PfnArray); reservation.extent_order = 0; reservation.mem_flags = 0; // unused reservation.domid = DOMID_SELF; reservation.nr_extents = Registered; Released = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); if (Released < Registered) { TraceWarning(("%s: partial release (%d < %d)\n", __FUNCTION__, Released, Registered)); // This should not fail as we're removing ranges we just added RangeSetRemoveItems(&(Balloon.PfnsBalloonedOut), &(Balloon.PfnArray[Released]), Registered - Released); } else if (Released > Registered) { XM_BUG(); } RtlZeroMemory(Balloon.PfnArray, Released * sizeof (PFN_NUMBER)); done: RangeSetDropRseCache(&(Balloon.PfnsBalloonedOut)); TraceVerbose(("%s: %d page(s)\n", __FUNCTION__, Released)); KeQuerySystemTime(&End); TimeDelta = (End.QuadPart - Start.QuadPart) / 10000ull; Slow = FALSE; if (TimeDelta != 0) { ULONGLONG Rate; Rate = (ULONGLONG)(Released * 1000) / TimeDelta; if (Rate < MIN_PAGES_PER_S) { TraceWarning(("%s: ran for more than %dms\n", __FUNCTION__, TimeDelta)); Slow = TRUE; } } *pReleased = Released; return Slow; }
static BOOLEAN BalloonAllocatePfnArray( IN ULONG Requested, OUT PULONG pAllocated ) { LARGE_INTEGER Start; LARGE_INTEGER End; ULONGLONG TimeDelta; BOOLEAN Slow; MDL *Mdl; ULONG Allocated; PFN_NUMBER *Array; XM_ASSERT(Requested <= BALLOON_PFN_ARRAY_SIZE); KeQuerySystemTime(&Start); Allocated = 0; Mdl = BalloonAllocatePagesForMdl(Requested); if (Mdl == NULL) { Balloon.AllocateFail++; goto done; } XM_ASSERT(Mdl->ByteOffset == 0); XM_ASSERT((Mdl->ByteCount & (PAGE_SIZE - 1)) == 0); XM_ASSERT(Mdl->MdlFlags & MDL_PAGES_LOCKED); Allocated = Mdl->ByteCount >> PAGE_SHIFT; if (Allocated < Requested) { TraceNotice(("%s: partial allocation (%d < %d)\n", __FUNCTION__, Allocated, Requested)); Balloon.PartialAllocate++; } Array = MmGetMdlPfnArray(Mdl); BalloonSortPfnArray(Array, Allocated); RtlCopyMemory(Balloon.PfnArray, Array, Allocated * sizeof (PFN_NUMBER)); ExFreePool(Mdl); done: TraceVerbose(("%s: %d page(s)\n", __FUNCTION__, Allocated)); KeQuerySystemTime(&End); TimeDelta = (End.QuadPart - Start.QuadPart) / 10000ull; Slow = FALSE; if (TimeDelta != 0) { ULONGLONG Rate; Rate = (ULONGLONG)(Allocated * 1000) / TimeDelta; if (Rate < MIN_PAGES_PER_S) { TraceWarning(("%s: ran for more than %dms\n", __FUNCTION__, TimeDelta)); Slow = TRUE; } } *pAllocated = Allocated; return Slow; }
static NTSTATUS V4vCtrlAccept(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, ULONG ioc, VOID *iob, ULONG iol, PIRP irp) { NTSTATUS status = STATUS_SUCCESS; LONG val; V4V_INIT_VALUES init; FILE_OBJECT *pfo = NULL; XENV4V_CONTEXT *actx; XENV4V_INSERT ins = {FALSE}; HANDLE fh; HANDLE rxe; V4V_ACCEPT_PRIVATE *priv; val = InterlockedExchangeAdd(&ctx->state, 0); if (val != XENV4V_STATE_LISTENING) { TraceWarning(("state not LISTENING, cannot complete accept request\n")); return STATUS_INVALID_DEVICE_REQUEST; } // Handle 32b/64b thunk sructures here and test input #if defined(_WIN64) if (ioc == V4V_IOCTL_ACCEPT_32) { V4V_ACCEPT_VALUES_32 *avs32 = (V4V_ACCEPT_VALUES_32*)iob; if (iol != sizeof(V4V_ACCEPT_VALUES_32)) { TraceError(("invalid accept values.\n")); return STATUS_INVALID_PARAMETER; } fh = avs32->fileHandle; rxe = avs32->rxEvent; priv = (V4V_ACCEPT_PRIVATE*)((UCHAR*)avs32 + FIELD_OFFSET(V4V_ACCEPT_VALUES_32, priv)); } else #endif { V4V_ACCEPT_VALUES *avs = (V4V_ACCEPT_VALUES*)iob; UNREFERENCED_PARAMETER(ioc); if (iol != sizeof(V4V_ACCEPT_VALUES)) { TraceError(("invalid accept values.\n")); return STATUS_INVALID_PARAMETER; } fh = avs->fileHandle; rxe = avs->rxEvent; priv = (V4V_ACCEPT_PRIVATE*)((UCHAR*)avs + FIELD_OFFSET(V4V_ACCEPT_VALUES, priv)); } // Any IRPs that are queued are given a sanity initialization V4vInitializeIrp(irp); // Get a reference to the file object for the handle status = ObReferenceObjectByHandle(fh, 0, *IoFileObjectType, irp->RequestorMode, &pfo, NULL); if (!NT_SUCCESS(status)) { TraceError(("failed to get a reference to the accepter file object - error: 0x%x\n", status)); return status; } actx = (XENV4V_CONTEXT*)pfo->FsContext; ObDereferenceObject(pfo); // Store the referenced acceptor context in the IOCTL buffer so we can access it at > PASSIVE later. V4vAddRefContext(pde, actx); #if defined(_WIN64) priv->q.a = (ULONG64)actx; #else priv->d.a = (ULONG32)actx; #endif // Do the base initialization of the file object context init.rxEvent = rxe; init.ringLength = ctx->ringLength; // shared ring length status = V4vCtrlInitializeFile(actx, &init, irp); if (!NT_SUCCESS(status)) { V4vReleaseContext(pde, actx); TraceError(("failed to initialize the accepter file object - error: 0x%x\n", status)); return status; } // Now initialize the accepter specific state and associate the accepter // with the listener context and ring. KeInitializeSpinLock(&actx->u.accepter.dataLock); actx->u.accepter.dataList = NULL; actx->u.accepter.dataTail = NULL; V4vAddRefContext(pde, ctx); V4vAddRefRing(pde, ctx->ringObject); actx->u.accepter.listenerContext = ctx; actx->ringObject = ctx->ringObject; // Now it becomes an accepter type for ever more InterlockedExchange(&actx->type, XENV4V_TYPE_ACCEPTER); // After this transition, we will wait for a SYN (may be one in the queue already). InterlockedExchange(&actx->state, XENV4V_STATE_ACCEPTING); // Flag it irp->Tail.Overlay.DriverContext[0] = (PVOID)(ULONG_PTR)(XENV4V_PEEK_STREAM|XENV4V_PEEK_ACCEPT|XENV4V_PEEK_IOCTL); // Always queue it to the back and marks it pending. If it fails to be queued then // the user mode call will close the new handle. status = IoCsqInsertIrpEx(&pde->csqObject, irp, NULL, &ins); if (NT_SUCCESS(status)) { status = STATUS_PENDING; // Drive any accepts V4vDoAccepts(pde, ctx); } return status; }
NTSTATUS InterruptCreate ( _In_ WDFDEVICE Device, _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceRaw, _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptResourceTranslated ) /*++ Routine Description: Helper function to create device's WDFINTERRUPT object and any other needed WDF resources that the interrupt needs for proper functioning. It assumes the first interrupt resource with which this is invoked is the device interrupt, and the second is the attach/detach interrupt. Arguments: Device - Wdf device object corresponding to the FDO InterruptResourceRaw - Raw resource for the interrupt InterruptResourceTranslated - Translated resource for the interrupt Return Value: Appropriate NTSTATUS value --*/ { NTSTATUS Status; WDF_INTERRUPT_CONFIG InterruptConfig; PCONTROLLER_CONTEXT ControllerContext; WDF_OBJECT_ATTRIBUTES Attributes; WDFINTERRUPT* InterruptToCreate; TraceEntry(); PAGED_CODE(); ControllerContext = DeviceGetControllerContext(Device); WDF_OBJECT_ATTRIBUTES_INIT(&Attributes); if (ControllerContext->DeviceInterrupt == NULL) { WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig, DeviceInterrupt_EvtInterruptIsr, DeviceInterrupt_EvtInterruptDpc); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE( &Attributes, DEVICE_INTERRUPT_CONTEXT); InterruptToCreate = &ControllerContext->DeviceInterrupt; } else if (ControllerContext->AttachDetachInterrupt == NULL) { WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig, DeviceInterrupt_EvtAttachDetachInterruptIsr, DeviceInterrupt_EvtInterruptDpc); InterruptConfig.CanWakeDevice = TRUE; InterruptConfig.PassiveHandling = TRUE; InterruptToCreate = &ControllerContext->AttachDetachInterrupt; } else { TraceWarning("Other interrupt resource [0X%X] is detected and is being" " ignored", InterruptResourceRaw->u.Interrupt.Vector); Status = STATUS_SUCCESS; goto End; } InterruptConfig.InterruptRaw = InterruptResourceRaw; InterruptConfig.InterruptTranslated = InterruptResourceTranslated; Status = WdfInterruptCreate( Device, &InterruptConfig, &Attributes, InterruptToCreate); CHK_NT_MSG(Status, "Failed to create Device interrupt"); End: TraceExit(); return Status; }
static NTSTATUS V4vCtrlBind(XENV4V_EXTENSION *pde, XENV4V_CONTEXT *ctx, V4V_BIND_VALUES *bvs) { NTSTATUS status = STATUS_SUCCESS; LONG val; KLOCK_QUEUE_HANDLE lqh; XENV4V_RING *robj; uint32_t port; // Use a simple guard variable to enforce the state transition order val = InterlockedExchangeAdd(&ctx->state, 0); if (val != XENV4V_STATE_IDLE) { TraceWarning(("state not IDLE, cannot complete bind request\n")); return STATUS_INVALID_DEVICE_REQUEST; } ASSERT(ctx->ringObject == NULL); do { if ((bvs->ringId.addr.domain != V4V_DOMID_NONE)&& (bvs->ringId.addr.domain != DOMID_INVALID_COMPAT)) { TraceWarning(("failure - ring ID domain must be V4V_DOMID_NONE - value: 0x%x\n", bvs->ringId.addr.domain)); status = STATUS_INVALID_PARAMETER; break; } robj = V4vAllocateRing(ctx->ringLength); if (robj == NULL) { TraceError(("failed to allocate the ring\n")); status = STATUS_NO_MEMORY; break; } robj->ring->id = bvs->ringId; // Have to grab this outside of lock at IRQL PASSIVE port = V4vRandomPort(pde); // Lock this section since we access the list KeAcquireInStackQueuedSpinLock(&pde->ringLock, &lqh); if (robj->ring->id.addr.port == V4V_PORT_NONE) { robj->ring->id.addr.port = V4vSparePortNumber(pde, port); } else if (V4vRingIdInUse(pde, &robj->ring->id)) { KeReleaseInStackQueuedSpinLock(&lqh); TraceWarning(("ring ID already in use, cannot bind\n")); status = STATUS_INVALID_DEVICE_REQUEST; break; } // Now register the ring. status = V4vRegisterRing(robj); if (!NT_SUCCESS(status)) { KeReleaseInStackQueuedSpinLock(&lqh); TraceError(("failed in register ring hypercall - error: 0x%x\n", status)); break; } robj->registered = TRUE; // Link it to the main list and set our pointer to it V4vLinkToRingList(pde, robj); ctx->ringObject = robj; KeReleaseInStackQueuedSpinLock(&lqh); InterlockedExchange(&ctx->type, XENV4V_TYPE_DATAGRAM); InterlockedExchange(&ctx->state, XENV4V_STATE_BOUND); } while (FALSE); if (!NT_SUCCESS(status)) { // If it failed, undo everything - this will remove it from the list if (ctx->ringObject != NULL) { V4vReleaseRing(pde, ctx->ringObject); } } return status; }
/* We've received a csum_blank packet, but we don't want to let Windows see it like. Calculate the checksum and dump it in the packet. This only works for TCP and UDP on IPv4; on anything else it's a no-op. */ static VOID FixupChecksum(PNDIS_PACKET packet) { PNDIS_BUFFER pbuf; PNDIS_BUFFER pbuf_next; UINT bufLength; UINT len; struct ethhdr *eh; struct iphdr *ih; uint32_t csum_accumulator; uint32_t *ptr; uint16_t *csum_field; NdisQueryPacket(packet, NULL, NULL, &pbuf, NULL); NdisQueryBufferSafe(pbuf, &eh, &bufLength, NormalPagePriority); if (!eh || bufLength < sizeof(*eh)) return; if (eh->proto != TPID_IPV4) { static BOOLEAN warned; if (!warned) { TraceWarning(("Asked to perform checksum calculation on non-IP ethernet prototocol %x!\n", eh->proto)); warned = TRUE; } return; } ih = (struct iphdr *)(eh + 1); bufLength -= sizeof(*eh); if (bufLength < sizeof(*ih) || bufLength < (UINT)(ih->len_version & 0x0f) * 4) return; ptr = (uint32_t *)((ULONG_PTR)ih + (ih->len_version & 0x0f)*4); len = ntohs(ih->tot_len) - (ih->len_version & 0x0f) * 4; bufLength -= (ih->len_version & 0x0f) * 4; if (bufLength > len) bufLength = len; if (ih->proto == IPPROTO_UDP) { if (bufLength < sizeof(struct udphdr)) return; csum_field = &((struct udphdr *)ptr)->checksum; } else if (ih->proto == IPPROTO_TCP) { if (bufLength < sizeof(struct tcphdr)) return; csum_field = &((struct tcphdr *)ptr)->checksum; } else { static BOOLEAN warned; /* Uh oh: don't know what this protocol is, so can't do checksum calculation for it. */ if (!warned) { TraceWarning(("Asked to perform checksum calculation for unknown protocol %d!\n", ih->proto)); warned = TRUE; } return; } if (ih->proto == IPPROTO_TCP) { struct tcp_pseudo_header tph; uint16_t csum; tph.saddr = ih->src; tph.daddr = ih->dest; tph.mbz = 0; tph.ptcl = IPPROTO_TCP; tph.length = htons((uint16_t)len); csum_accumulator = acc_ip_csum(&tph, sizeof(tph), 0); csum = fold_ip_csum(csum_accumulator); if (*csum_field != csum) TraceWarning(("invlid pseudo header checksum: expected %04x, found %04x\n", csum, *csum_field)); *csum_field = csum; } csum_accumulator = acc_ip_csum(ptr, bufLength, 0); len -= bufLength; while (len) { NdisGetNextBuffer(pbuf, &pbuf_next); if (pbuf_next == NULL) break; pbuf = pbuf_next; NdisQueryBufferSafe(pbuf, &ptr, &bufLength, NormalPagePriority); /* The buffer is already mapped into our RX buffer pool, so we should always be able to get a virtual address for it. */ XM_ASSERT(ptr != NULL); if (bufLength > len) bufLength = len; csum_accumulator = acc_ip_csum(ptr, bufLength, csum_accumulator); len -= bufLength; } *csum_field = ~fold_ip_csum(csum_accumulator); }
// This the completion routine of the continuous reader. This can called concurrently on multiprocessor system if there are // more than one readers configured. So make sure to protect access to global resources. // void HidFx2EvtUsbInterruptPipeReadComplete( WDFUSBPIPE hPipe, WDFMEMORY hBuffer, size_t cNumBytesTransferred, WDFCONTEXT pContext ) { PDEVICE_EXTENSION pDevContext = pContext; BOOLEAN fInTimerQueue; unsigned char *pbSwitchState = NULL; unsigned char bCurrentSwitchState = 0; unsigned char bPrevSwitchState = 0; unsigned char bToggledSwitch = 0; UNREFERENCED_PARAMETER(cNumBytesTransferred); UNREFERENCED_PARAMETER(hPipe); TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); // Interrupt endpoints sends switch state when first started or when resuming from suspend. // We need to ignore that data since user did not change the switch state. if (pDevContext->fIsPowerUpSwitchState) { pDevContext->fIsPowerUpSwitchState = FALSE; TraceInfo(DBG_INIT, "(%!FUNC!) Dropping interrupt message since received during powerup/resume\n"); return; } // Make sure that there is data in the read packet. // Depending on the device specification, it is possible for it to return a 0 length read in certain conditions. if (cNumBytesTransferred == 0) { TraceWarning(DBG_INIT, "(%!FUNC!) Zero length read occured on the Interrupt Pipe's Continuous Reader\n"); return; } pbSwitchState = WdfMemoryGetBuffer(hBuffer, NULL); bCurrentSwitchState = ~(*pbSwitchState); // switchs are inverted on hardware boards bCurrentSwitchState &= RADIO_SWITCH_BUTTONS_BIT_MASK; //Mask off everything except the actual radio switch bit bPrevSwitchState = pDevContext->bCurrentSwitchState; if (bPrevSwitchState ^ bCurrentSwitchState) // make sure we toggled the radio switch { switch(pDevContext->driverMode) { // If it's a slider switch we want 0->1 and 1->0 transitions. case DM_SLIDER_SWITCH: case DM_SLIDER_SWITCH_AND_LED: bToggledSwitch = bCurrentSwitchState; // A timer is started for 10 ms everytime there is a switch toggled fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); break; //If it's a button so we only report 0->1 transitions case DM_BUTTON: case DM_BUTTON_AND_LED: bToggledSwitch = (bPrevSwitchState ^ bCurrentSwitchState) & bCurrentSwitchState; if (bToggledSwitch != 0) { // A timer is started for 10 ms everytime there is a switch toggled on fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); } break; // Ignore button presses if LED only case DM_LED_ONLY: default: break; } // Store switch state in device context pDevContext->bCurrentSwitchState = bCurrentSwitchState; pDevContext->bLatestToggledSwitch = bToggledSwitch; } else { TraceInfo(DBG_INIT, "(%!FUNC!) Not a radio switch toggle\n"); } TraceInfo(DBG_INIT, "(%!FUNC!) Switch 0x%x, prevSwitch:0x%x, X0R:0x%x\n", bCurrentSwitchState, bPrevSwitchState, bToggledSwitch); TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n"); }
VOID ReceiverHandleNotification( IN PRECEIVER Receiver ) /*++ Routine Description: Interrupt handler for receive processing Put the received packets into an array and call NdisMIndicateReceivePacket If we run low on RFDs, allocate another one Arguments: Adapter Pointer to our adapter Return Value: None --*/ { PADAPTER Adapter = Receiver->Common.Adapter; RING_IDX prod; int more_work; PNDIS_PACKET PacketArray[XENNET_DEF_RFDS]; NDIS_STATUS PacketStatus[XENNET_DEF_RFDS]; UINT PacketCount; if (!RING_HAS_UNCONSUMED_RESPONSES(&Receiver->Common.Ring)) return; NdisDprAcquireSpinLock(&Receiver->Common.Lock); if (Receiver->Common.Adapter->media_disconnect) { NdisDprReleaseSpinLock(&Receiver->Common.Lock); return; } if (__RING_IDX_DIFFERENCE(Receiver->Common.Ring.req_prod_pvt, Receiver->Common.Ring.sring->rsp_prod) > NET_RX_RING_SIZE) TraceWarning(("Strange: rsp_prod ahead of req_prod (%d vs %d (s %d))\n", Receiver->Common.Ring.sring->rsp_prod, Receiver->Common.Ring.req_prod_pvt, Receiver->Common.Ring.sring->req_prod)); PacketCount = 0; top: prod = Receiver->Common.Ring.sring->rsp_prod; XsMemoryBarrier(); while (!RING_IDXS_EQ(Receiver->Common.Ring.rsp_cons, prod)) { PNDIS_PACKET packet; ULONG totFrags; NDIS_STATUS status; status = ReceiverReceivePacket(Receiver, &packet, &totFrags); if (status != NDIS_STATUS_SUCCESS) continue; TraceProfile(("%s(%s, %p)\n", __FUNCTION__, Adapter->XenbusPrefix, packet)); // See http://msdn.microsoft.com/en-us/library/ms797610.aspx if (Receiver->LowResources == 2 || (Receiver->LowResources == 1 && totFrags > 1)) { status = NDIS_STATUS_RESOURCES; NDIS_SET_PACKET_STATUS(packet, status); } PacketArray[PacketCount] = packet; PacketStatus[PacketCount] = status; PacketCount++; if (PacketCount == XENNET_DEF_RFDS) { ULONG Index; Receiver->Common.Frames += PacketCount; Receiver->nRxInNdis += PacketCount; if (Receiver->nRxInNdis >= Receiver->nRxInNdisMax) Receiver->nRxInNdisMax = Receiver->nRxInNdis; NdisDprReleaseSpinLock(&Receiver->Common.Lock); NdisMIndicateReceivePacket( Receiver->Common.Adapter->AdapterHandle, PacketArray, PacketCount); NdisDprAcquireSpinLock(&Receiver->Common.Lock); for (Index = 0; Index < PacketCount; Index++) { if (PacketStatus[Index] == NDIS_STATUS_RESOURCES) { ReceiverReleasePacket(Receiver, PacketArray[Index]); Receiver->nRxInNdis--; } else { XM_ASSERT(PacketStatus[Index] == NDIS_STATUS_SUCCESS); } } PacketCount = 0; ReceiverSwizzle(Receiver); } } RING_FINAL_CHECK_FOR_RESPONSES(&Receiver->Common.Ring, more_work); if (more_work) goto top; if (PacketCount != 0) { ULONG Index; Receiver->Common.Frames += PacketCount; Receiver->nRxInNdis += PacketCount; if (Receiver->nRxInNdis >= Receiver->nRxInNdisMax) Receiver->nRxInNdisMax = Receiver->nRxInNdis; NdisDprReleaseSpinLock(&Receiver->Common.Lock); NdisMIndicateReceivePacket( Receiver->Common.Adapter->AdapterHandle, PacketArray, PacketCount); NdisDprAcquireSpinLock(&Receiver->Common.Lock); for (Index = 0; Index < PacketCount; Index++) { if (PacketStatus[Index] == NDIS_STATUS_RESOURCES) { ReceiverReleasePacket(Receiver, PacketArray[Index]); Receiver->nRxInNdis--; } else { XM_ASSERT(PacketStatus[Index] == NDIS_STATUS_SUCCESS); } } PacketCount = 0; } // Swizzle unconditionally to make sure we replenish the ring even if // nothing was passed to NDIS. ReceiverSwizzle(Receiver); NdisDprReleaseSpinLock(&Receiver->Common.Lock); /* XXX Should maybe adjust size of packet pool from here. */ }
BOOLEAN NTAPI XenGfxVbeSetMode(USHORT ModeNumber) { const MODE_INFO_ITEM *pCurrentMode; BOOLEAN UsingLFB; USHORT FlagLFB, FlagNoClear; USHORT StrideAlign; TraceVerbose(("====> '%s'.\n", __FUNCTION__)); if (!g_VbeInfoInitialized) { return FALSE; } ModeNumber &= 0x1FF; if (ModeNumber < VBE_MODE_VESA_DEFINED) { TraceError(("Could not set non-VBE mode!\n")); return FALSE; } // Get mode attributes UsingLFB = ((ModeNumber & VBE_MODE_LINEAR_FRAME_BUFFER) == VBE_MODE_LINEAR_FRAME_BUFFER) ? TRUE : FALSE; FlagLFB = (UsingLFB) ? VBE_DISPI_LFB_ENABLED : 0; FlagNoClear = ((ModeNumber & VBE_MODE_PRESERVE_DISPLAY_MEMORY) == VBE_MODE_PRESERVE_DISPLAY_MEMORY) ? VBE_DISPI_NOCLEARMEM : 0; pCurrentMode = XenGfxFindMode(ModeNumber, UsingLFB); if (pCurrentMode == NULL) { TraceWarning(("VBE mode %04x NOT FOUND (and not set)??\n", ModeNumber)); return FALSE; } TraceVerbose(("Set VBE mode 0x%04x (xres=0x%04x / yres=0x%04x / bpp=0x%02x) found.\n", pCurrentMode->ModeNumber, pCurrentMode->ModeInfo.XResolution, pCurrentMode->ModeInfo.YResolution, pCurrentMode->ModeInfo.BitsPerPixel)); // Need to lock here - this is going to change the mode and the state of the // emulated video card. XenGfxInt10SpinLock((UCHAR*)VGA_PORT_RANGE_BASE); // Disable while setting VESA modes. WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_ENABLE); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, VBE_DISPI_DISABLED); // N.B. don't need to worry about setting up 4 BPP modes for XenVesa // Set BPP, X and Y res, stride, bank WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_BPP); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, pCurrentMode->ModeInfo.BitsPerPixel); WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_XRES); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, pCurrentMode->ModeInfo.XResolution); WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_YRES); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, pCurrentMode->ModeInfo.YResolution); //New feature... StrideAlign = XenGfxVbeGetAlignedStride(pCurrentMode->ModeInfo.BytesPerScanLine); WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_STRIDE); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, StrideAlign); WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_BANK); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, 0); // Store some of the VGA port values as in the vBIOS. Note we only need to write our shadow // ports at this point since we switched to exclusive shadow use. WRITE_PORT_USHORT((USHORT*)VGA_PORT_VBE_MODE, ModeNumber); WRITE_PORT_USHORT((USHORT*)VGA_PORT_VIDEO_CTL, (0x60|FlagNoClear)); // Enable new VESA mode WRITE_PORT_USHORT((USHORT*)VBE_PORT_INDEX, VBE_DISPI_INDEX_ENABLE); WRITE_PORT_USHORT((USHORT*)VBE_PORT_DATA, VBE_DISPI_ENABLED|FlagLFB|FlagNoClear); XenGfxInt10SpinUnlock((UCHAR*)VGA_PORT_RANGE_BASE); TraceVerbose(("<==== '%s'.\n", __FUNCTION__)); return TRUE; }