📄 vmini.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
VMini.c
Abstract:
The Null miniport implementation.
This module uses the KernelIoCtl() calls to get it's jobs
done.
Functions:
--*/
#include <windows.h>
#include <pkfuncs.h>
#include <nkintr.h>
#include <ndis.h>
#include <VMini.h>
#include <zone.h>
//
// This is how much virtual address we reserve for TX or RX buffer..
// 2M each, VBridge needs to be modified if it needs more than this!!!
//
#define VIRTUAL_MEMORY_TO_ALLOC 0x200000
#define DEFAULT_RX_THREAD_PRIORITY 131
//
// Set this to non-zero when EDBG starts to use
// name event: EDBG_INTERRUPT_EVENT
//
#define EDBG_USE_NAME_EVENT 0x01
#ifndef net_short
#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
#endif
#ifdef DEBUG
DBGPARAM dpCurSettings =
{
TEXT("VMINI"),
{
TEXT("INIT"),
TEXT("SEND"),
TEXT("RECEIVE"),
TEXT("SET"),
TEXT("GET"),
TEXT("MEMORY"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("<unused>"),
TEXT("Warning"),
TEXT("Error"),
},
0xC000
};
#endif // DEBUG
//
// typedef..
//
#include <pshpack1.h>
typedef struct SNAPHeader
{
uchar eh_daddr[6];
uchar eh_saddr[6];
uchar sh_dsap;
uchar sh_ssap;
uchar sh_ctl;
uchar sh_protid[3];
ushort sh_etype;
} SNAPHeaderFormat, *pSNAPHeaderFormat;
typedef struct ENetHeader
{
uchar eh_daddr[6];
uchar eh_saddr[6];
ushort eh_type;
} ENetHeaderFormat, *pENetHeaderFormat;
typedef struct IPHeaderFormatTag
{
BYTE bVersionLength;
BYTE bTypeOfService;
UINT16 cwTotalLength;
UINT16 wIdentification;
UINT16 wFragment;
BYTE bTimeToLive;
BYTE bProtocol;
UINT16 wCRC;
DWORD dwSrcIP;
DWORD dwDestIP;
} IPHeaderFormat, *pIPHeaderFormat;
typedef struct UDPHeaderFormatTag
{
UINT16 wSrcPort;
UINT16 wDestPort;
UINT16 cwTotalUDPLength;
UINT16 wCRC;
} UDPHeaderFormat, *pUDPHeaderFormat;
#define CHADDR_LEN 16
#define SNAME_LEN 64
#define FILE_LEN 128
#define OPTIONS_LEN 312
typedef struct {
unsigned char Op;
unsigned char Htype;
unsigned char Hlen;
unsigned char Hops;
unsigned int Xid;
unsigned short Secs;
unsigned short Flags;
unsigned int Ciaddr;
unsigned int Yiaddr;
unsigned int Siaddr;
unsigned int Giaddr;
unsigned char aChaddr[CHADDR_LEN];
unsigned char aSname[SNAME_LEN];
unsigned char aFile[FILE_LEN];
unsigned char aOptions[OPTIONS_LEN];
} DHCP_PACKET, *PDHCP_PACKET;
#include <poppack.h>
//
// Forward decl.
//
VOID
VMiniMShutdownHandler(
IN PVOID Context
);
//
// Global variables.
//
STRUCT_VMINI VMini; // Miniport global var.
CRITICAL_SECTION g_csSend; // Only one send at a time.
DWORD dwTxPA = 0x00; // TX buffers..
DWORD dwTxVA;
DWORD dwTxOffset;
DWORD dwTxPAMax;
DWORD dwRxPA = 0x00; // RX buffers..
DWORD dwRxVA;
DWORD dwRxOffset;
DWORD dwRxPAMax;
////////////////////////////////////////////////////////////////////////////////
// PA2VA()
//
// Routine Description:
//
// This function is responsible in converting the PA to VA.
//
// Arguments:
//
// dwPA :: The physical address.
//
// bIsTx :: Whether this is TX buffer or RX buffer.
// We only do the conversion once with each type of the buffer.
// i.e for the very first buffer coming from VBridge.
// We then reserve VIRTUAL_MEMORY_TO_ALLOC virtual memory
// mapped to this buffer..
//
// Return Value:
//
// NULL :: If can't convert.
//
// VA :: The virtual address of the given Physical Address.
//
PUCHAR
PA2VA(DWORD dwPA, BOOL bIsTx)
{
PDWORD pdwPA;
PDWORD pdwVA;
PDWORD pdwOffset;
PDWORD pdwPAMax;
if (bIsTx)
{
pdwPA = &dwTxPA;
pdwVA = &dwTxVA;
pdwOffset = &dwTxOffset;
pdwPAMax = &dwTxPAMax;
}
else
{
pdwPA = &dwRxPA;
pdwVA = &dwRxVA;
pdwOffset = &dwRxOffset;
pdwPAMax = &dwRxPAMax;
}
if (*pdwPA != 0x00)
{
//
// Already mapped, make sure this PA is in range and calculate the VA.
//
if (dwPA >= *pdwPAMax)
return NULL;
//
// In range, calculate the VA to use..
//
return (PUCHAR)(*pdwVA + (dwPA - *pdwPA));
}
//
// Nop, first time mapping..
//
*pdwOffset = dwPA % PAGE_SIZE;
*pdwVA = (DWORD)VirtualAlloc(
0,
VIRTUAL_MEMORY_TO_ALLOC + *pdwOffset,
MEM_RESERVE,
PAGE_NOACCESS);
if (!VirtualCopy(
(PVOID)*pdwVA,
(LPVOID)(dwPA - *pdwOffset),
VIRTUAL_MEMORY_TO_ALLOC + *pdwOffset,
PAGE_READWRITE | PAGE_NOCACHE))
{
RETAILMSG (1,
(TEXT("VMini:: Failed VirtualCopy()!! PA[0x%x] Offset[0x%x]\r\n"),
dwPA,
*pdwOffset));
return NULL;
}
*pdwVA += *pdwOffset;
*pdwPA = dwPA;
*pdwPAMax = dwPA + VIRTUAL_MEMORY_TO_ALLOC;
return (PUCHAR)(*pdwVA);
} // PA2VA()
////////////////////////////////////////////////////////////////////////////////
// VirtMiniISR()
//
// Routine Description:
//
// This thread handles RX from VBridge..
// Thread will quit when VMini.vm_bHalt is set..
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
void
VirtMiniISR(void)
{
DWORD BufferAddress;
DWORD dwReturnedBytes;
PBYTE pVA;
PNDIS_BUFFER pNdisBuffer;
PNDIS_PACKET_OOB_DATA OobyDoobyData;
NDIS_STATUS Status;
#ifndef NDIS50_MINIPORT
NDIS_HANDLE SwitchHandle;
#endif
DWORD dwWaitTime;
BOOL bConvert = FALSE;
DEBUGMSG (ZONE_RECEIVE, (TEXT("VMini:: $$$$..VirtMiniISR() started..$$$$\r\n")));
//
// Create the event that we will be waiting for when kernel has
// RX packets for us.
//
VMini.vm_hInterruptEvent = CreateEvent(NULL, FALSE, FALSE, VMINI_RX_EVENT);
//
// Revert to polling mode if we fail this.
//
if (InterruptInitialize(SYSINTR_VMINI, VMini.vm_hInterruptEvent, NULL, 0x00))
{
RETAILMSG (1, (TEXT("VMini:: Successfully initialize SYSINTR_VMINI..\r\n")));
dwWaitTime = INFINITE;
}
else
{
RETAILMSG (1, (TEXT("VMini:: Warning!! Use polling mode for RX.\r\n")));
dwWaitTime = 10;
}
while(1)
{
WaitForSingleObject (VMini.vm_hInterruptEvent, dwWaitTime);
DEBUGMSG (ZONE_RECEIVE, (TEXT("RX Interrupt!\r\n")));
while (KernelIoControl (
IOCTL_VBRIDGE_GET_RX_PACKET,
NULL,
0x00,
(LPVOID)&BufferAddress,
sizeof(DWORD),
&dwReturnedBytes))
{
//
// Okay, we have a packet to indicate..
// KernelIoCtl returns us the PA hence we need to get the VA
// out of it.
//
//
// Make sure we get 0x8xxxxxxx region since on x86 the 0xAxxxxxxx
// will not work if you pass it into VirtualCopy.
//
if (BufferAddress & 0x20000000)
{
bConvert = TRUE;
BufferAddress &= ~0x20000000;
}
if (!(pVA = PA2VA(BufferAddress, FALSE)))
goto NextLoop;
DEBUGMSG (0, (TEXT("Rcvd Dest = %x-%x-%x-%x-%x-%x :: [%d] bytes.\r\n"),
pVA[0],
pVA[1],
pVA[2],
pVA[3],
pVA[4],
pVA[5],
dwReturnedBytes));
//
// Do not indicate if we are in HALT state.
//
if (VMini.vm_bHalt)
{
DEBUGMSG (1, (TEXT("VMini:: HALT! No indicate.\r\n")));
goto NextLoop;
}
//
// Now, link the VA to the NdisPacket, and prepare the
// NdisPacket for take off..
//
NdisAllocateBuffer(
&Status,
&pNdisBuffer,
VMini.NdisBufferPool,
pVA,
dwReturnedBytes);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGMSG (ZONE_ERROR, (TEXT("VMini:: Error! Bad NdisAllocateBuffer() in VMiniISR().\r\n")));
goto NextLoop;
}
NdisChainBufferAtFront(VMini.pNdisPacket, pNdisBuffer);
OobyDoobyData = NDIS_OOB_DATA_FROM_PACKET (VMini.pNdisPacket);
NdisZeroMemory (OobyDoobyData, sizeof(NDIS_PACKET_OOB_DATA));
OobyDoobyData->HeaderSize = 14;
OobyDoobyData->SizeMediaSpecificInfo = 0;
OobyDoobyData->MediaSpecificInformation = NULL;
OobyDoobyData->Status = NDIS_STATUS_RESOURCES;
//
// Final touch up just before it is sent up.
//
NdisAdjustBufferLength(
pNdisBuffer,
dwReturnedBytes
);
NdisSetPacketFlags (VMini.pNdisPacket, NDIS_FLAGS_DONT_LOOPBACK);
NdisRecalculatePacketCounts (VMini.pNdisPacket);
#if 0
//
// Use this to see packet details..
//
{
DWORD dwPhysicalBufferCount;
DWORD dwBufferCount;
DWORD dwTotalPacketLength;
NdisQueryPacket(
VMini.pNdisPacket,
&dwPhysicalBufferCount,
&dwBufferCount,
NULL,
&dwTotalPacketLength);
DEBUGMSG (1, (TEXT("VMini:: RX:: dwBufferCount[%d] - dwTotalPktLength[%d] - Actual[%d]\r\n"),
dwBufferCount,
dwTotalPacketLength,
dwReturnedBytes));
}
#endif
//
// Of it goes..
//
#ifndef NDIS50_MINIPORT
NdisIMSwitchToMiniport(
VMini.vm_VMiniportHandle,
&SwitchHandle);
#endif
NdisMIndicateReceivePacket(
VMini.vm_VMiniportHandle,
&VMini.pNdisPacket,
1);
#ifndef NDIS50_MINIPORT
NdisIMRevertBack(
VMini.vm_VMiniportHandle,
SwitchHandle);
#endif
//
// Free up all the resources..
//
NdisUnchainBufferAtFront (VMini.pNdisPacket, &pNdisBuffer);
NdisFreeBuffer(pNdisBuffer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -