Staging: hv: add the Hyper-V virtual bus
This is the virtual bus that all of the Linux Hyper-V drivers use. Signed-off-by: Hank Janssen <hjanssen@microsoft.com> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
ab05778195
Коммит
3e7ee4902f
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CHANNEL_H_
|
||||
#define _CHANNEL_H_
|
||||
|
||||
#include "osd.h"
|
||||
#include "ChannelMgmt.h"
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
|
||||
// The format must be the same as VMDATA_GPA_DIRECT
|
||||
typedef struct _VMBUS_CHANNEL_PACKET_PAGE_BUFFER {
|
||||
UINT16 Type;
|
||||
UINT16 DataOffset8;
|
||||
UINT16 Length8;
|
||||
UINT16 Flags;
|
||||
UINT64 TransactionId;
|
||||
UINT32 Reserved;
|
||||
UINT32 RangeCount;
|
||||
PAGE_BUFFER Range[MAX_PAGE_BUFFER_COUNT];
|
||||
} VMBUS_CHANNEL_PACKET_PAGE_BUFFER;
|
||||
|
||||
|
||||
// The format must be the same as VMDATA_GPA_DIRECT
|
||||
typedef struct _VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER {
|
||||
UINT16 Type;
|
||||
UINT16 DataOffset8;
|
||||
UINT16 Length8;
|
||||
UINT16 Flags;
|
||||
UINT64 TransactionId;
|
||||
UINT32 Reserved;
|
||||
UINT32 RangeCount; // Always 1 in this case
|
||||
MULTIPAGE_BUFFER Range;
|
||||
} VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// Routines
|
||||
//
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelOpen(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
UINT32 SendRingBufferSize,
|
||||
UINT32 RecvRingBufferSize,
|
||||
PVOID UserData,
|
||||
UINT32 UserDataLen,
|
||||
PFN_CHANNEL_CALLBACK pfnOnChannelCallback,
|
||||
PVOID Context
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChannelClose(
|
||||
VMBUS_CHANNEL *Channel
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelSendPacket(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
const PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId,
|
||||
VMBUS_PACKET_TYPE Type,
|
||||
UINT32 Flags
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelSendPacketPageBuffer(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
PAGE_BUFFER PageBuffers[],
|
||||
UINT32 PageCount,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelSendPacketMultiPageBuffer(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
MULTIPAGE_BUFFER *MultiPageBuffer,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelEstablishGpadl(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
PVOID Kbuffer, // from kmalloc()
|
||||
UINT32 Size, // page-size multiple
|
||||
UINT32 *GpadlHandle
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelTeardownGpadl(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
UINT32 GpadlHandle
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelRecvPacket(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32* BufferActualLen,
|
||||
UINT64* RequestId
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelRecvPacketRaw(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32* BufferActualLen,
|
||||
UINT64* RequestId
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChannelOnChannelEvent(
|
||||
VMBUS_CHANNEL *Channel
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChannelGetDebugInfo(
|
||||
VMBUS_CHANNEL *Channel,
|
||||
VMBUS_CHANNEL_DEBUG_INFO *DebugInfo
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChannelOnTimer(
|
||||
void *Context
|
||||
);
|
||||
#endif //_CHANNEL_H_
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "VmbusPrivate.h"
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelOpen(
|
||||
PDEVICE_OBJECT Device,
|
||||
UINT32 SendBufferSize,
|
||||
UINT32 RecvRingBufferSize,
|
||||
PVOID UserData,
|
||||
UINT32 UserDataLen,
|
||||
VMBUS_CHANNEL_CALLBACK ChannelCallback,
|
||||
PVOID Context
|
||||
)
|
||||
{
|
||||
return VmbusChannelOpen( (VMBUS_CHANNEL*)Device->context,
|
||||
SendBufferSize,
|
||||
RecvRingBufferSize,
|
||||
UserData,
|
||||
UserDataLen,
|
||||
ChannelCallback,
|
||||
Context);
|
||||
}
|
||||
|
||||
|
||||
INTERNAL void
|
||||
IVmbusChannelClose(
|
||||
PDEVICE_OBJECT Device
|
||||
)
|
||||
{
|
||||
VmbusChannelClose((VMBUS_CHANNEL*)Device->context);
|
||||
}
|
||||
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelSendPacket(
|
||||
PDEVICE_OBJECT Device,
|
||||
const PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId,
|
||||
UINT32 Type,
|
||||
UINT32 Flags
|
||||
)
|
||||
{
|
||||
return VmbusChannelSendPacket((VMBUS_CHANNEL*)Device->context,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
RequestId,
|
||||
Type,
|
||||
Flags);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelSendPacketPageBuffer(
|
||||
PDEVICE_OBJECT Device,
|
||||
PAGE_BUFFER PageBuffers[],
|
||||
UINT32 PageCount,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId
|
||||
)
|
||||
{
|
||||
return VmbusChannelSendPacketPageBuffer((VMBUS_CHANNEL*)Device->context,
|
||||
PageBuffers,
|
||||
PageCount,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
RequestId);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelSendPacketMultiPageBuffer(
|
||||
PDEVICE_OBJECT Device,
|
||||
MULTIPAGE_BUFFER *MultiPageBuffer,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT64 RequestId
|
||||
)
|
||||
{
|
||||
return VmbusChannelSendPacketMultiPageBuffer((VMBUS_CHANNEL*)Device->context,
|
||||
MultiPageBuffer,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
RequestId);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelRecvPacket (
|
||||
PDEVICE_OBJECT Device,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32* BufferActualLen,
|
||||
UINT64* RequestId
|
||||
)
|
||||
{
|
||||
return VmbusChannelRecvPacket((VMBUS_CHANNEL*)Device->context,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
BufferActualLen,
|
||||
RequestId);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelRecvPacketRaw(
|
||||
PDEVICE_OBJECT Device,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32* BufferActualLen,
|
||||
UINT64* RequestId
|
||||
)
|
||||
{
|
||||
return VmbusChannelRecvPacketRaw((VMBUS_CHANNEL*)Device->context,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
BufferActualLen,
|
||||
RequestId);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelEstablishGpadl(
|
||||
PDEVICE_OBJECT Device,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32* GpadlHandle
|
||||
)
|
||||
{
|
||||
return VmbusChannelEstablishGpadl((VMBUS_CHANNEL*)Device->context,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
GpadlHandle);
|
||||
}
|
||||
|
||||
INTERNAL int
|
||||
IVmbusChannelTeardownGpadl(
|
||||
PDEVICE_OBJECT Device,
|
||||
UINT32 GpadlHandle
|
||||
)
|
||||
{
|
||||
return VmbusChannelTeardownGpadl((VMBUS_CHANNEL*)Device->context,
|
||||
GpadlHandle);
|
||||
|
||||
}
|
||||
|
||||
INTERNAL void
|
||||
GetChannelInterface(
|
||||
VMBUS_CHANNEL_INTERFACE *ChannelInterface
|
||||
)
|
||||
{
|
||||
ChannelInterface->Open = IVmbusChannelOpen;
|
||||
ChannelInterface->Close = IVmbusChannelClose;
|
||||
ChannelInterface->SendPacket = IVmbusChannelSendPacket;
|
||||
ChannelInterface->SendPacketPageBuffer = IVmbusChannelSendPacketPageBuffer;
|
||||
ChannelInterface->SendPacketMultiPageBuffer = IVmbusChannelSendPacketMultiPageBuffer;
|
||||
ChannelInterface->RecvPacket = IVmbusChannelRecvPacket;
|
||||
ChannelInterface->RecvPacketRaw = IVmbusChannelRecvPacketRaw;
|
||||
ChannelInterface->EstablishGpadl = IVmbusChannelEstablishGpadl;
|
||||
ChannelInterface->TeardownGpadl = IVmbusChannelTeardownGpadl;
|
||||
ChannelInterface->GetInfo = GetChannelInfo;
|
||||
}
|
||||
|
||||
|
||||
INTERNAL void
|
||||
GetChannelInfo(
|
||||
PDEVICE_OBJECT Device,
|
||||
DEVICE_INFO *DeviceInfo
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_DEBUG_INFO debugInfo;
|
||||
|
||||
if (Device->context)
|
||||
{
|
||||
VmbusChannelGetDebugInfo((VMBUS_CHANNEL*)Device->context, &debugInfo);
|
||||
|
||||
DeviceInfo->ChannelId = debugInfo.RelId;
|
||||
DeviceInfo->ChannelState = debugInfo.State;
|
||||
memcpy(&DeviceInfo->ChannelType, &debugInfo.InterfaceType, sizeof(GUID));
|
||||
memcpy(&DeviceInfo->ChannelInstance, &debugInfo.InterfaceInstance, sizeof(GUID));
|
||||
|
||||
DeviceInfo->MonitorId = debugInfo.MonitorId;
|
||||
|
||||
DeviceInfo->ServerMonitorPending = debugInfo.ServerMonitorPending;
|
||||
DeviceInfo->ServerMonitorLatency = debugInfo.ServerMonitorLatency;
|
||||
DeviceInfo->ServerMonitorConnectionId = debugInfo.ServerMonitorConnectionId;
|
||||
|
||||
DeviceInfo->ClientMonitorPending = debugInfo.ClientMonitorPending;
|
||||
DeviceInfo->ClientMonitorLatency = debugInfo.ClientMonitorLatency;
|
||||
DeviceInfo->ClientMonitorConnectionId = debugInfo.ClientMonitorConnectionId;
|
||||
|
||||
DeviceInfo->Inbound.InterruptMask = debugInfo.Inbound.CurrentInterruptMask;
|
||||
DeviceInfo->Inbound.ReadIndex = debugInfo.Inbound.CurrentReadIndex;
|
||||
DeviceInfo->Inbound.WriteIndex = debugInfo.Inbound.CurrentWriteIndex;
|
||||
DeviceInfo->Inbound.BytesAvailToRead = debugInfo.Inbound.BytesAvailToRead;
|
||||
DeviceInfo->Inbound.BytesAvailToWrite = debugInfo.Inbound.BytesAvailToWrite;
|
||||
|
||||
DeviceInfo->Outbound.InterruptMask = debugInfo.Outbound.CurrentInterruptMask;
|
||||
DeviceInfo->Outbound.ReadIndex = debugInfo.Outbound.CurrentReadIndex;
|
||||
DeviceInfo->Outbound.WriteIndex = debugInfo.Outbound.CurrentWriteIndex;
|
||||
DeviceInfo->Outbound.BytesAvailToRead = debugInfo.Outbound.BytesAvailToRead;
|
||||
DeviceInfo->Outbound.BytesAvailToWrite = debugInfo.Outbound.BytesAvailToWrite;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CHANNEL_INTERFACE_H_
|
||||
#define _CHANNEL_INTERFACE_H_
|
||||
|
||||
#include "VmbusApi.h"
|
||||
|
||||
INTERNAL void
|
||||
GetChannelInterface(
|
||||
VMBUS_CHANNEL_INTERFACE *ChannelInterface
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
GetChannelInfo(
|
||||
PDEVICE_OBJECT Device,
|
||||
DEVICE_INFO *DeviceInfo
|
||||
);
|
||||
|
||||
#endif // _CHANNEL_INTERFACE_H_
|
|
@ -0,0 +1,826 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "osd.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include "VmbusPrivate.h"
|
||||
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
|
||||
//
|
||||
// Data types
|
||||
//
|
||||
|
||||
typedef void (*PFN_CHANNEL_MESSAGE_HANDLER)(VMBUS_CHANNEL_MESSAGE_HEADER* msg);
|
||||
|
||||
typedef struct _VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY {
|
||||
VMBUS_CHANNEL_MESSAGE_TYPE messageType;
|
||||
PFN_CHANNEL_MESSAGE_HANDLER messageHandler;
|
||||
} VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY;
|
||||
|
||||
//
|
||||
// Internal routines
|
||||
//
|
||||
|
||||
static void
|
||||
VmbusChannelOnOffer(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
static void
|
||||
VmbusChannelOnOpenResult(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelOnOfferRescind(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelOnGpadlCreated(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelOnGpadlTorndown(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelOnOffersDelivered(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelOnVersionResponse(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelProcessOffer(
|
||||
PVOID context
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusChannelProcessRescindOffer(
|
||||
PVOID context
|
||||
);
|
||||
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
|
||||
#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 4
|
||||
|
||||
const GUID gSupportedDeviceClasses[MAX_NUM_DEVICE_CLASSES_SUPPORTED]= {
|
||||
//{ba6163d9-04a1-4d29-b605-72e2ffb1dc7f}
|
||||
{.Data = {0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f}},// Storage - SCSI
|
||||
//{F8615163-DF3E-46c5-913F-F2D2F965ED0E}
|
||||
{.Data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}}, // Network
|
||||
//{CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A}
|
||||
{.Data = {0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c, 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A}}, // Input
|
||||
//{32412632-86cb-44a2-9b5c-50d1417354f5}
|
||||
{.Data = {0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5}}, // IDE
|
||||
|
||||
};
|
||||
|
||||
// Channel message dispatch table
|
||||
VMBUS_CHANNEL_MESSAGE_TABLE_ENTRY gChannelMessageTable[ChannelMessageCount]= {
|
||||
{ChannelMessageInvalid, NULL},
|
||||
{ChannelMessageOfferChannel, VmbusChannelOnOffer},
|
||||
{ChannelMessageRescindChannelOffer, VmbusChannelOnOfferRescind},
|
||||
{ChannelMessageRequestOffers, NULL},
|
||||
{ChannelMessageAllOffersDelivered, VmbusChannelOnOffersDelivered},
|
||||
{ChannelMessageOpenChannel, NULL},
|
||||
{ChannelMessageOpenChannelResult, VmbusChannelOnOpenResult},
|
||||
{ChannelMessageCloseChannel, NULL},
|
||||
{ChannelMessageGpadlHeader, NULL},
|
||||
{ChannelMessageGpadlBody, NULL},
|
||||
{ChannelMessageGpadlCreated, VmbusChannelOnGpadlCreated},
|
||||
{ChannelMessageGpadlTeardown, NULL},
|
||||
{ChannelMessageGpadlTorndown, VmbusChannelOnGpadlTorndown},
|
||||
{ChannelMessageRelIdReleased, NULL},
|
||||
{ChannelMessageInitiateContact, NULL},
|
||||
{ChannelMessageVersionResponse, VmbusChannelOnVersionResponse},
|
||||
{ChannelMessageUnload, NULL},
|
||||
};
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
AllocVmbusChannel()
|
||||
|
||||
Description:
|
||||
Allocate and initialize a vmbus channel object
|
||||
|
||||
--*/
|
||||
VMBUS_CHANNEL* AllocVmbusChannel(void)
|
||||
{
|
||||
VMBUS_CHANNEL* channel;
|
||||
|
||||
channel = (VMBUS_CHANNEL*) MemAllocAtomic(sizeof(VMBUS_CHANNEL));
|
||||
if (!channel)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(channel, 0,sizeof(VMBUS_CHANNEL));
|
||||
channel->InboundLock = SpinlockCreate();
|
||||
if (!channel->InboundLock)
|
||||
{
|
||||
MemFree(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel->PollTimer = TimerCreate(VmbusChannelOnTimer, channel);
|
||||
if (!channel->PollTimer)
|
||||
{
|
||||
SpinlockClose(channel->InboundLock);
|
||||
MemFree(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//channel->dataWorkQueue = WorkQueueCreate("data");
|
||||
channel->ControlWQ = WorkQueueCreate("control");
|
||||
if (!channel->ControlWQ)
|
||||
{
|
||||
TimerClose(channel->PollTimer);
|
||||
SpinlockClose(channel->InboundLock);
|
||||
MemFree(channel);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
ReleaseVmbusChannel()
|
||||
|
||||
Description:
|
||||
Release the vmbus channel object itself
|
||||
|
||||
--*/
|
||||
static inline void ReleaseVmbusChannel(void* Context)
|
||||
{
|
||||
VMBUS_CHANNEL* channel = (VMBUS_CHANNEL*)Context;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
DPRINT_DBG(VMBUS, "releasing channel (%p)", channel);
|
||||
WorkQueueClose(channel->ControlWQ);
|
||||
DPRINT_DBG(VMBUS, "channel released (%p)", channel);
|
||||
|
||||
MemFree(channel);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
FreeVmbusChannel()
|
||||
|
||||
Description:
|
||||
Release the resources used by the vmbus channel object
|
||||
|
||||
--*/
|
||||
void FreeVmbusChannel(VMBUS_CHANNEL* Channel)
|
||||
{
|
||||
SpinlockClose(Channel->InboundLock);
|
||||
TimerClose(Channel->PollTimer);
|
||||
|
||||
// We have to release the channel's workqueue/thread in the vmbus's workqueue/thread context
|
||||
// ie we can't destroy ourselves.
|
||||
WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, ReleaseVmbusChannel, (void*)Channel);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelProcessOffer()
|
||||
|
||||
Description:
|
||||
Process the offer by creating a channel/device associated with this offer
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelProcessOffer(
|
||||
PVOID context
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
VMBUS_CHANNEL* newChannel=(VMBUS_CHANNEL*)context;
|
||||
LIST_ENTRY* anchor;
|
||||
LIST_ENTRY* curr;
|
||||
BOOL fNew=TRUE;
|
||||
VMBUS_CHANNEL* channel;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Make sure this is a new offer
|
||||
SpinlockAcquire(gVmbusConnection.ChannelLock);
|
||||
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
|
||||
{
|
||||
channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
|
||||
|
||||
if (!memcmp(&channel->OfferMsg.Offer.InterfaceType, &newChannel->OfferMsg.Offer.InterfaceType,sizeof(GUID)) &&
|
||||
!memcmp(&channel->OfferMsg.Offer.InterfaceInstance, &newChannel->OfferMsg.Offer.InterfaceInstance, sizeof(GUID)))
|
||||
{
|
||||
fNew = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fNew)
|
||||
{
|
||||
INSERT_TAIL_LIST(&gVmbusConnection.ChannelList, &newChannel->ListEntry);
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelLock);
|
||||
|
||||
if (!fNew)
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "Ignoring duplicate offer for relid (%d)", newChannel->OfferMsg.ChildRelId);
|
||||
FreeVmbusChannel(newChannel);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the process of binding this offer to the driver
|
||||
// We need to set the DeviceObject field before calling VmbusChildDeviceAdd()
|
||||
newChannel->DeviceObject = VmbusChildDeviceCreate(
|
||||
newChannel->OfferMsg.Offer.InterfaceType,
|
||||
newChannel->OfferMsg.Offer.InterfaceInstance,
|
||||
newChannel);
|
||||
|
||||
DPRINT_DBG(VMBUS, "child device object allocated - %p", newChannel->DeviceObject);
|
||||
|
||||
// Add the new device to the bus. This will kick off device-driver binding
|
||||
// which eventually invokes the device driver's AddDevice() method.
|
||||
ret = VmbusChildDeviceAdd(newChannel->DeviceObject);
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to add child device object (relid %d)",
|
||||
newChannel->OfferMsg.ChildRelId);
|
||||
|
||||
SpinlockAcquire(gVmbusConnection.ChannelLock);
|
||||
REMOVE_ENTRY_LIST(&newChannel->ListEntry);
|
||||
SpinlockRelease(gVmbusConnection.ChannelLock);
|
||||
|
||||
FreeVmbusChannel(newChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This state is used to indicate a successful open so that when we do close the channel normally,
|
||||
// we can cleanup properly
|
||||
newChannel->State = CHANNEL_OPEN_STATE;
|
||||
}
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelProcessRescindOffer()
|
||||
|
||||
Description:
|
||||
Rescind the offer by initiating a device removal
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelProcessRescindOffer(
|
||||
PVOID context
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL* channel=(VMBUS_CHANNEL*)context;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
VmbusChildDeviceRemove(channel->DeviceObject);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnOffer()
|
||||
|
||||
Description:
|
||||
Handler for channel offers from vmbus in parent partition. We ignore all offers except
|
||||
network and storage offers. For each network and storage offers, we create a channel object
|
||||
and queue a work item to the channel object to process the offer synchronously
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnOffer(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_OFFER_CHANNEL* offer = (VMBUS_CHANNEL_OFFER_CHANNEL*)hdr;
|
||||
VMBUS_CHANNEL* newChannel;
|
||||
|
||||
GUID *guidType;
|
||||
GUID *guidInstance;
|
||||
int i;
|
||||
int fSupported=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
for (i=0; i<MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++)
|
||||
{
|
||||
if (memcmp(&offer->Offer.InterfaceType, &gSupportedDeviceClasses[i], sizeof(GUID)) == 0)
|
||||
{
|
||||
fSupported = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fSupported)
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "Ignoring channel offer notification for child relid %d", offer->ChildRelId);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
guidType = &offer->Offer.InterfaceType;
|
||||
guidInstance = &offer->Offer.InterfaceInstance;
|
||||
|
||||
DPRINT_INFO(VMBUS, "Channel offer notification - child relid %d monitor id %d allocated %d, "
|
||||
"type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x} "
|
||||
"instance {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
|
||||
offer->ChildRelId,
|
||||
offer->MonitorId,
|
||||
offer->MonitorAllocated,
|
||||
guidType->Data[3], guidType->Data[2], guidType->Data[1], guidType->Data[0], guidType->Data[5], guidType->Data[4], guidType->Data[7], guidType->Data[6], guidType->Data[8], guidType->Data[9], guidType->Data[10], guidType->Data[11], guidType->Data[12], guidType->Data[13], guidType->Data[14], guidType->Data[15],
|
||||
guidInstance->Data[3], guidInstance->Data[2], guidInstance->Data[1], guidInstance->Data[0], guidInstance->Data[5], guidInstance->Data[4], guidInstance->Data[7], guidInstance->Data[6], guidInstance->Data[8], guidInstance->Data[9], guidInstance->Data[10], guidInstance->Data[11], guidInstance->Data[12], guidInstance->Data[13], guidInstance->Data[14], guidInstance->Data[15]);
|
||||
|
||||
// Allocate the channel object and save this offer.
|
||||
newChannel = AllocVmbusChannel();
|
||||
if (!newChannel)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to allocate channel object");
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINT_DBG(VMBUS, "channel object allocated - %p", newChannel);
|
||||
|
||||
memcpy(&newChannel->OfferMsg, offer, sizeof(VMBUS_CHANNEL_OFFER_CHANNEL));
|
||||
newChannel->MonitorGroup = (UINT8)offer->MonitorId / 32;
|
||||
newChannel->MonitorBit = (UINT8)offer->MonitorId % 32;
|
||||
|
||||
// TODO: Make sure the offer comes from our parent partition
|
||||
WorkQueueQueueWorkItem(newChannel->ControlWQ, VmbusChannelProcessOffer, newChannel);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnOfferRescind()
|
||||
|
||||
Description:
|
||||
Rescind offer handler. We queue a work item to process this offer
|
||||
synchronously
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnOfferRescind(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_RESCIND_OFFER* rescind = (VMBUS_CHANNEL_RESCIND_OFFER*)hdr;
|
||||
VMBUS_CHANNEL* channel;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
channel = GetChannelFromRelId(rescind->ChildRelId);
|
||||
if (channel == NULL)
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "channel not found for relId %d", rescind->ChildRelId);
|
||||
return;
|
||||
}
|
||||
|
||||
WorkQueueQueueWorkItem(channel->ControlWQ, VmbusChannelProcessRescindOffer, channel);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnOffersDelivered()
|
||||
|
||||
Description:
|
||||
This is invoked when all offers have been delivered.
|
||||
Nothing to do here.
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnOffersDelivered(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
DPRINT_ENTER(VMBUS);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnOpenResult()
|
||||
|
||||
Description:
|
||||
Open result handler. This is invoked when we received a response
|
||||
to our channel open request. Find the matching request, copy the
|
||||
response and signal the requesting thread.
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnOpenResult(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_OPEN_RESULT* result = (VMBUS_CHANNEL_OPEN_RESULT*)hdr;
|
||||
LIST_ENTRY* anchor;
|
||||
LIST_ENTRY* curr;
|
||||
VMBUS_CHANNEL_MSGINFO* msgInfo;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER* requestHeader;
|
||||
VMBUS_CHANNEL_OPEN_CHANNEL* openMsg;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
DPRINT_DBG(VMBUS, "vmbus open result - %d", result->Status);
|
||||
|
||||
// Find the open msg, copy the result and signal/unblock the wait event
|
||||
SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
|
||||
{
|
||||
msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
|
||||
requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
|
||||
|
||||
if (requestHeader->MessageType == ChannelMessageOpenChannel)
|
||||
{
|
||||
openMsg = (VMBUS_CHANNEL_OPEN_CHANNEL*)msgInfo->Msg;
|
||||
if (openMsg->ChildRelId == result->ChildRelId &&
|
||||
openMsg->OpenId == result->OpenId)
|
||||
{
|
||||
memcpy(&msgInfo->Response.OpenResult, result, sizeof(VMBUS_CHANNEL_OPEN_RESULT));
|
||||
WaitEventSet(msgInfo->WaitEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnGpadlCreated()
|
||||
|
||||
Description:
|
||||
GPADL created handler. This is invoked when we received a response
|
||||
to our gpadl create request. Find the matching request, copy the
|
||||
response and signal the requesting thread.
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnGpadlCreated(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_GPADL_CREATED *gpadlCreated = (VMBUS_CHANNEL_GPADL_CREATED*)hdr;
|
||||
LIST_ENTRY *anchor;
|
||||
LIST_ENTRY *curr;
|
||||
VMBUS_CHANNEL_MSGINFO *msgInfo;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
|
||||
VMBUS_CHANNEL_GPADL_HEADER *gpadlHeader;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
DPRINT_DBG(VMBUS, "vmbus gpadl created result - %d", gpadlCreated->CreationStatus);
|
||||
|
||||
// Find the establish msg, copy the result and signal/unblock the wait event
|
||||
SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
|
||||
{
|
||||
msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
|
||||
requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
|
||||
|
||||
if (requestHeader->MessageType == ChannelMessageGpadlHeader)
|
||||
{
|
||||
gpadlHeader = (VMBUS_CHANNEL_GPADL_HEADER*)requestHeader;
|
||||
|
||||
if ((gpadlCreated->ChildRelId == gpadlHeader->ChildRelId) &&
|
||||
(gpadlCreated->Gpadl == gpadlHeader->Gpadl))
|
||||
{
|
||||
memcpy(&msgInfo->Response.GpadlCreated, gpadlCreated, sizeof(VMBUS_CHANNEL_GPADL_CREATED));
|
||||
WaitEventSet(msgInfo->WaitEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnGpadlTorndown()
|
||||
|
||||
Description:
|
||||
GPADL torndown handler. This is invoked when we received a response
|
||||
to our gpadl teardown request. Find the matching request, copy the
|
||||
response and signal the requesting thread.
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnGpadlTorndown(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL_GPADL_TORNDOWN* gpadlTorndown = (VMBUS_CHANNEL_GPADL_TORNDOWN*)hdr;
|
||||
LIST_ENTRY* anchor;
|
||||
LIST_ENTRY* curr;
|
||||
VMBUS_CHANNEL_MSGINFO* msgInfo;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
|
||||
VMBUS_CHANNEL_GPADL_TEARDOWN *gpadlTeardown;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Find the open msg, copy the result and signal/unblock the wait event
|
||||
SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
|
||||
{
|
||||
msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
|
||||
requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
|
||||
|
||||
if (requestHeader->MessageType == ChannelMessageGpadlTeardown)
|
||||
{
|
||||
gpadlTeardown = (VMBUS_CHANNEL_GPADL_TEARDOWN*)requestHeader;
|
||||
|
||||
if (gpadlTorndown->Gpadl == gpadlTeardown->Gpadl)
|
||||
{
|
||||
memcpy(&msgInfo->Response.GpadlTorndown, gpadlTorndown, sizeof(VMBUS_CHANNEL_GPADL_TORNDOWN));
|
||||
WaitEventSet(msgInfo->WaitEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelOnVersionResponse()
|
||||
|
||||
Description:
|
||||
Version response handler. This is invoked when we received a response
|
||||
to our initiate contact request. Find the matching request, copy the
|
||||
response and signal the requesting thread.
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusChannelOnVersionResponse(
|
||||
PVMBUS_CHANNEL_MESSAGE_HEADER hdr
|
||||
)
|
||||
{
|
||||
LIST_ENTRY* anchor;
|
||||
LIST_ENTRY* curr;
|
||||
VMBUS_CHANNEL_MSGINFO *msgInfo;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER *requestHeader;
|
||||
VMBUS_CHANNEL_INITIATE_CONTACT *initiate;
|
||||
VMBUS_CHANNEL_VERSION_RESPONSE *versionResponse = (VMBUS_CHANNEL_VERSION_RESPONSE*)hdr;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelMsgList)
|
||||
{
|
||||
msgInfo = (VMBUS_CHANNEL_MSGINFO*) curr;
|
||||
requestHeader = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
|
||||
|
||||
if (requestHeader->MessageType == ChannelMessageInitiateContact)
|
||||
{
|
||||
initiate = (VMBUS_CHANNEL_INITIATE_CONTACT*)requestHeader;
|
||||
memcpy(&msgInfo->Response.VersionResponse, versionResponse, sizeof(VMBUS_CHANNEL_VERSION_RESPONSE));
|
||||
WaitEventSet(msgInfo->WaitEvent);
|
||||
}
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnChannelMessage()
|
||||
|
||||
Description:
|
||||
Handler for channel protocol messages.
|
||||
This is invoked in the vmbus worker thread context.
|
||||
|
||||
--*/
|
||||
VOID
|
||||
VmbusOnChannelMessage(
|
||||
void *Context
|
||||
)
|
||||
{
|
||||
HV_MESSAGE *msg=(HV_MESSAGE*)Context;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER* hdr;
|
||||
int size;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
hdr = (VMBUS_CHANNEL_MESSAGE_HEADER*)msg->u.Payload;
|
||||
size=msg->Header.PayloadSize;
|
||||
|
||||
DPRINT_DBG(VMBUS, "message type %d size %d", hdr->MessageType, size);
|
||||
|
||||
if (hdr->MessageType >= ChannelMessageCount)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Received invalid channel message type %d size %d", hdr->MessageType, size);
|
||||
PrintBytes((unsigned char *)msg->u.Payload, size);
|
||||
MemFree(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gChannelMessageTable[hdr->MessageType].messageHandler)
|
||||
{
|
||||
gChannelMessageTable[hdr->MessageType].messageHandler(hdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Unhandled channel message type %d", hdr->MessageType);
|
||||
}
|
||||
|
||||
// Free the msg that was allocated in VmbusOnMsgDPC()
|
||||
MemFree(msg);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelRequestOffers()
|
||||
|
||||
Description:
|
||||
Send a request to get all our pending offers.
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusChannelRequestOffers(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
VMBUS_CHANNEL_MESSAGE_HEADER* msg;
|
||||
VMBUS_CHANNEL_MSGINFO* msgInfo;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
msgInfo =
|
||||
(VMBUS_CHANNEL_MSGINFO*)MemAlloc(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
|
||||
ASSERT(msgInfo != NULL);
|
||||
|
||||
msgInfo->WaitEvent = WaitEventCreate();
|
||||
msg = (VMBUS_CHANNEL_MESSAGE_HEADER*)msgInfo->Msg;
|
||||
|
||||
msg->MessageType = ChannelMessageRequestOffers;
|
||||
|
||||
/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
|
||||
INSERT_TAIL_LIST(&gVmbusConnection.channelMsgList, &msgInfo->msgListEntry);
|
||||
SpinlockRelease(gVmbusConnection.channelMsgLock);*/
|
||||
|
||||
ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_MESSAGE_HEADER));
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Unable to request offers - %d", ret);
|
||||
|
||||
/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
|
||||
REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
|
||||
SpinlockRelease(gVmbusConnection.channelMsgLock);*/
|
||||
|
||||
goto Cleanup;
|
||||
}
|
||||
//WaitEventWait(msgInfo->waitEvent);
|
||||
|
||||
/*SpinlockAcquire(gVmbusConnection.channelMsgLock);
|
||||
REMOVE_ENTRY_LIST(&msgInfo->msgListEntry);
|
||||
SpinlockRelease(gVmbusConnection.channelMsgLock);*/
|
||||
|
||||
|
||||
Cleanup:
|
||||
if (msgInfo)
|
||||
{
|
||||
WaitEventClose(msgInfo->WaitEvent);
|
||||
MemFree(msgInfo);
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChannelReleaseUnattachedChannels()
|
||||
|
||||
Description:
|
||||
Release channels that are unattached/unconnected ie (no drivers associated)
|
||||
|
||||
--*/
|
||||
void
|
||||
VmbusChannelReleaseUnattachedChannels(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *entry;
|
||||
VMBUS_CHANNEL *channel;
|
||||
VMBUS_CHANNEL *start=NULL;
|
||||
|
||||
SpinlockAcquire(gVmbusConnection.ChannelLock);
|
||||
|
||||
while (!IsListEmpty(&gVmbusConnection.ChannelList))
|
||||
{
|
||||
entry = TOP_LIST_ENTRY(&gVmbusConnection.ChannelList);
|
||||
channel = CONTAINING_RECORD(entry, VMBUS_CHANNEL, ListEntry);
|
||||
|
||||
if (channel == start)
|
||||
break;
|
||||
|
||||
if (!channel->DeviceObject->Driver)
|
||||
{
|
||||
REMOVE_ENTRY_LIST(&channel->ListEntry);
|
||||
DPRINT_INFO(VMBUS, "Releasing unattached device object %p", channel->DeviceObject);
|
||||
|
||||
VmbusChildDeviceRemove(channel->DeviceObject);
|
||||
FreeVmbusChannel(channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!start)
|
||||
{
|
||||
start = channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpinlockRelease(gVmbusConnection.ChannelLock);
|
||||
}
|
||||
|
||||
// eof
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _CHANNEL_MGMT_H_
|
||||
#define _CHANNEL_MGMT_H_
|
||||
|
||||
#include "osd.h"
|
||||
#include "List.h"
|
||||
#include "RingBuffer.h"
|
||||
|
||||
#include "VmbusChannelInterface.h"
|
||||
#include "ChannelMessages.h"
|
||||
|
||||
|
||||
|
||||
typedef void (*PFN_CHANNEL_CALLBACK)(PVOID context);
|
||||
|
||||
typedef enum {
|
||||
CHANNEL_OFFER_STATE,
|
||||
CHANNEL_OPENING_STATE,
|
||||
CHANNEL_OPEN_STATE,
|
||||
} VMBUS_CHANNEL_STATE;
|
||||
|
||||
typedef struct _VMBUS_CHANNEL {
|
||||
LIST_ENTRY ListEntry;
|
||||
|
||||
DEVICE_OBJECT* DeviceObject;
|
||||
|
||||
HANDLE PollTimer; // SA-111 workaround
|
||||
|
||||
VMBUS_CHANNEL_STATE State;
|
||||
|
||||
VMBUS_CHANNEL_OFFER_CHANNEL OfferMsg;
|
||||
// These are based on the OfferMsg.MonitorId. Save it here for easy access.
|
||||
UINT8 MonitorGroup;
|
||||
UINT8 MonitorBit;
|
||||
|
||||
UINT32 RingBufferGpadlHandle;
|
||||
|
||||
// Allocated memory for ring buffer
|
||||
VOID* RingBufferPages;
|
||||
UINT32 RingBufferPageCount;
|
||||
RING_BUFFER_INFO Outbound; // send to parent
|
||||
RING_BUFFER_INFO Inbound; // receive from parent
|
||||
HANDLE InboundLock;
|
||||
HANDLE ControlWQ;
|
||||
|
||||
// Channel callback are invoked in this workqueue context
|
||||
//HANDLE dataWorkQueue;
|
||||
|
||||
PFN_CHANNEL_CALLBACK OnChannelCallback;
|
||||
PVOID ChannelCallbackContext;
|
||||
|
||||
} VMBUS_CHANNEL;
|
||||
|
||||
|
||||
typedef struct _VMBUS_CHANNEL_DEBUG_INFO {
|
||||
UINT32 RelId;
|
||||
VMBUS_CHANNEL_STATE State;
|
||||
GUID InterfaceType;
|
||||
GUID InterfaceInstance;
|
||||
UINT32 MonitorId;
|
||||
UINT32 ServerMonitorPending;
|
||||
UINT32 ServerMonitorLatency;
|
||||
UINT32 ServerMonitorConnectionId;
|
||||
UINT32 ClientMonitorPending;
|
||||
UINT32 ClientMonitorLatency;
|
||||
UINT32 ClientMonitorConnectionId;
|
||||
|
||||
RING_BUFFER_DEBUG_INFO Inbound;
|
||||
RING_BUFFER_DEBUG_INFO Outbound;
|
||||
} VMBUS_CHANNEL_DEBUG_INFO;
|
||||
|
||||
|
||||
typedef union {
|
||||
VMBUS_CHANNEL_VERSION_SUPPORTED VersionSupported;
|
||||
VMBUS_CHANNEL_OPEN_RESULT OpenResult;
|
||||
VMBUS_CHANNEL_GPADL_TORNDOWN GpadlTorndown;
|
||||
VMBUS_CHANNEL_GPADL_CREATED GpadlCreated;
|
||||
VMBUS_CHANNEL_VERSION_RESPONSE VersionResponse;
|
||||
} VMBUS_CHANNEL_MESSAGE_RESPONSE;
|
||||
|
||||
|
||||
// Represents each channel msg on the vmbus connection
|
||||
// This is a variable-size data structure depending on
|
||||
// the msg type itself
|
||||
typedef struct _VMBUS_CHANNEL_MSGINFO {
|
||||
// Bookkeeping stuff
|
||||
LIST_ENTRY MsgListEntry;
|
||||
|
||||
// So far, this is only used to handle gpadl body message
|
||||
LIST_ENTRY SubMsgList;
|
||||
|
||||
// Synchronize the request/response if needed
|
||||
HANDLE WaitEvent;
|
||||
|
||||
VMBUS_CHANNEL_MESSAGE_RESPONSE Response;
|
||||
|
||||
UINT32 MessageSize;
|
||||
// The channel message that goes out on the "wire".
|
||||
// It will contain at minimum the VMBUS_CHANNEL_MESSAGE_HEADER header
|
||||
unsigned char Msg[0];
|
||||
} VMBUS_CHANNEL_MSGINFO;
|
||||
|
||||
|
||||
//
|
||||
// Routines
|
||||
//
|
||||
|
||||
INTERNAL VMBUS_CHANNEL*
|
||||
AllocVmbusChannel(
|
||||
void
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
FreeVmbusChannel(
|
||||
VMBUS_CHANNEL *Channel
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusOnChannelMessage(
|
||||
void *Context
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChannelRequestOffers(
|
||||
void
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChannelReleaseUnattachedChannels(
|
||||
void
|
||||
);
|
||||
|
||||
#endif //_CHANNEL_MGMT_H_
|
|
@ -0,0 +1,432 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include "VmbusPrivate.h"
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
|
||||
|
||||
VMBUS_CONNECTION gVmbusConnection = {
|
||||
.ConnectState = Disconnected,
|
||||
.NextGpadlHandle = 0xE1E10,
|
||||
};
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusConnect()
|
||||
|
||||
Description:
|
||||
Sends a connect request on the partition service connection
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusConnect(
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
VMBUS_CHANNEL_MSGINFO *msgInfo=NULL;
|
||||
VMBUS_CHANNEL_INITIATE_CONTACT *msg;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Make sure we are not connecting or connected
|
||||
if (gVmbusConnection.ConnectState != Disconnected)
|
||||
return -1;
|
||||
|
||||
// Initialize the vmbus connection
|
||||
gVmbusConnection.ConnectState = Connecting;
|
||||
gVmbusConnection.WorkQueue = WorkQueueCreate("vmbusQ");
|
||||
|
||||
INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelMsgList);
|
||||
gVmbusConnection.ChannelMsgLock = SpinlockCreate();
|
||||
|
||||
INITIALIZE_LIST_HEAD(&gVmbusConnection.ChannelList);
|
||||
gVmbusConnection.ChannelLock = SpinlockCreate();
|
||||
|
||||
// Setup the vmbus event connection for channel interrupt abstraction stuff
|
||||
gVmbusConnection.InterruptPage = PageAlloc(1);
|
||||
if (gVmbusConnection.InterruptPage == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
gVmbusConnection.RecvInterruptPage = gVmbusConnection.InterruptPage;
|
||||
gVmbusConnection.SendInterruptPage = (void*)((ULONG_PTR)gVmbusConnection.InterruptPage + (PAGE_SIZE >> 1));
|
||||
|
||||
// Setup the monitor notification facility. The 1st page for parent->child and the 2nd page for child->parent
|
||||
gVmbusConnection.MonitorPages = PageAlloc(2);
|
||||
if (gVmbusConnection.MonitorPages == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
msgInfo = (VMBUS_CHANNEL_MSGINFO*)MemAllocZeroed(sizeof(VMBUS_CHANNEL_MSGINFO) + sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
|
||||
if (msgInfo == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
msgInfo->WaitEvent = WaitEventCreate();
|
||||
msg = (VMBUS_CHANNEL_INITIATE_CONTACT*)msgInfo->Msg;
|
||||
|
||||
msg->Header.MessageType = ChannelMessageInitiateContact;
|
||||
msg->VMBusVersionRequested = VMBUS_REVISION_NUMBER;
|
||||
msg->InterruptPage = GetPhysicalAddress(gVmbusConnection.InterruptPage);
|
||||
msg->MonitorPage1 = GetPhysicalAddress(gVmbusConnection.MonitorPages);
|
||||
msg->MonitorPage2 = GetPhysicalAddress((PVOID)((ULONG_PTR)gVmbusConnection.MonitorPages + PAGE_SIZE));
|
||||
|
||||
// Add to list before we send the request since we may receive the response
|
||||
// before returning from this routine
|
||||
SpinlockAcquire(gVmbusConnection.ChannelMsgLock);
|
||||
INSERT_TAIL_LIST(&gVmbusConnection.ChannelMsgList, &msgInfo->MsgListEntry);
|
||||
SpinlockRelease(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
DPRINT_DBG(VMBUS, "Vmbus connection - interrupt pfn %llx, monitor1 pfn %llx,, monitor2 pfn %llx",
|
||||
msg->InterruptPage, msg->MonitorPage1, msg->MonitorPage2);
|
||||
|
||||
DPRINT_DBG(VMBUS, "Sending channel initiate msg...");
|
||||
|
||||
ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_INITIATE_CONTACT));
|
||||
if (ret != 0)
|
||||
{
|
||||
REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
// Wait for the connection response
|
||||
WaitEventWait(msgInfo->WaitEvent);
|
||||
|
||||
REMOVE_ENTRY_LIST(&msgInfo->MsgListEntry);
|
||||
|
||||
// Check if successful
|
||||
if (msgInfo->Response.VersionResponse.VersionSupported)
|
||||
{
|
||||
DPRINT_INFO(VMBUS, "Vmbus connected!!");
|
||||
gVmbusConnection.ConnectState = Connected;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Vmbus connection failed!!...current version (%d) not supported", VMBUS_REVISION_NUMBER);
|
||||
ret = -1;
|
||||
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
|
||||
WaitEventClose(msgInfo->WaitEvent);
|
||||
MemFree(msgInfo);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return 0;
|
||||
|
||||
Cleanup:
|
||||
|
||||
gVmbusConnection.ConnectState = Disconnected;
|
||||
|
||||
WorkQueueClose(gVmbusConnection.WorkQueue);
|
||||
SpinlockClose(gVmbusConnection.ChannelLock);
|
||||
SpinlockClose(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
if (gVmbusConnection.InterruptPage)
|
||||
{
|
||||
PageFree(gVmbusConnection.InterruptPage, 1);
|
||||
gVmbusConnection.InterruptPage = NULL;
|
||||
}
|
||||
|
||||
if (gVmbusConnection.MonitorPages)
|
||||
{
|
||||
PageFree(gVmbusConnection.MonitorPages, 2);
|
||||
gVmbusConnection.MonitorPages = NULL;
|
||||
}
|
||||
|
||||
if (msgInfo)
|
||||
{
|
||||
if (msgInfo->WaitEvent)
|
||||
WaitEventClose(msgInfo->WaitEvent);
|
||||
|
||||
MemFree(msgInfo);
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusDisconnect()
|
||||
|
||||
Description:
|
||||
Sends a disconnect request on the partition service connection
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusDisconnect(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
VMBUS_CHANNEL_UNLOAD *msg;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Make sure we are connected
|
||||
if (gVmbusConnection.ConnectState != Connected)
|
||||
return -1;
|
||||
|
||||
msg = MemAllocZeroed(sizeof(VMBUS_CHANNEL_UNLOAD));
|
||||
|
||||
msg->MessageType = ChannelMessageUnload;
|
||||
|
||||
ret = VmbusPostMessage(msg, sizeof(VMBUS_CHANNEL_UNLOAD));
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
PageFree(gVmbusConnection.InterruptPage, 1);
|
||||
|
||||
// TODO: iterate thru the msg list and free up
|
||||
|
||||
SpinlockClose(gVmbusConnection.ChannelMsgLock);
|
||||
|
||||
WorkQueueClose(gVmbusConnection.WorkQueue);
|
||||
|
||||
gVmbusConnection.ConnectState = Disconnected;
|
||||
|
||||
DPRINT_INFO(VMBUS, "Vmbus disconnected!!");
|
||||
|
||||
Cleanup:
|
||||
if (msg)
|
||||
{
|
||||
MemFree(msg);
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetChannelFromRelId()
|
||||
|
||||
Description:
|
||||
Get the channel object given its child relative id (ie channel id)
|
||||
|
||||
--*/
|
||||
VMBUS_CHANNEL*
|
||||
GetChannelFromRelId(
|
||||
UINT32 relId
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL* channel;
|
||||
VMBUS_CHANNEL* foundChannel=NULL;
|
||||
LIST_ENTRY* anchor;
|
||||
LIST_ENTRY* curr;
|
||||
|
||||
SpinlockAcquire(gVmbusConnection.ChannelLock);
|
||||
ITERATE_LIST_ENTRIES(anchor, curr, &gVmbusConnection.ChannelList)
|
||||
{
|
||||
channel = CONTAINING_RECORD(curr, VMBUS_CHANNEL, ListEntry);
|
||||
|
||||
if (channel->OfferMsg.ChildRelId == relId)
|
||||
{
|
||||
foundChannel = channel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SpinlockRelease(gVmbusConnection.ChannelLock);
|
||||
|
||||
return foundChannel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusProcessChannelEvent()
|
||||
|
||||
Description:
|
||||
Process a channel event notification
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusProcessChannelEvent(
|
||||
PVOID context
|
||||
)
|
||||
{
|
||||
VMBUS_CHANNEL* channel;
|
||||
UINT32 relId = (UINT32)(ULONG_PTR)context;
|
||||
|
||||
ASSERT(relId > 0);
|
||||
|
||||
// Find the channel based on this relid and invokes
|
||||
// the channel callback to process the event
|
||||
channel = GetChannelFromRelId(relId);
|
||||
|
||||
if (channel)
|
||||
{
|
||||
VmbusChannelOnChannelEvent(channel);
|
||||
//WorkQueueQueueWorkItem(channel->dataWorkQueue, VmbusChannelOnChannelEvent, (void*)channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "channel not found for relid - %d.", relId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnEvents()
|
||||
|
||||
Description:
|
||||
Handler for events
|
||||
|
||||
--*/
|
||||
VOID
|
||||
VmbusOnEvents(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
int dword;
|
||||
//int maxdword = PAGE_SIZE >> 3; // receive size is 1/2 page and divide that by 4 bytes
|
||||
int maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
|
||||
int bit;
|
||||
int relid;
|
||||
UINT32* recvInterruptPage = gVmbusConnection.RecvInterruptPage;
|
||||
//VMBUS_CHANNEL_MESSAGE* receiveMsg;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Check events
|
||||
if (recvInterruptPage)
|
||||
{
|
||||
for (dword = 0; dword < maxdword; dword++)
|
||||
{
|
||||
if (recvInterruptPage[dword])
|
||||
{
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (BitTestAndClear(&recvInterruptPage[dword], bit))
|
||||
{
|
||||
relid = (dword << 5) + bit;
|
||||
|
||||
DPRINT_DBG(VMBUS, "event detected for relid - %d", relid);
|
||||
|
||||
if (relid == 0) // special case - vmbus channel protocol msg
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "invalid relid - %d", relid);
|
||||
|
||||
continue; }
|
||||
else
|
||||
{
|
||||
//QueueWorkItem(VmbusProcessEvent, (void*)relid);
|
||||
//ret = WorkQueueQueueWorkItem(gVmbusConnection.workQueue, VmbusProcessChannelEvent, (void*)relid);
|
||||
VmbusProcessChannelEvent((void*)(ULONG_PTR)relid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusPostMessage()
|
||||
|
||||
Description:
|
||||
Send a msg on the vmbus's message connection
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusPostMessage(
|
||||
PVOID buffer,
|
||||
SIZE_T bufferLen
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
HV_CONNECTION_ID connId;
|
||||
|
||||
|
||||
connId.AsUINT32 =0;
|
||||
connId.u.Id = VMBUS_MESSAGE_CONNECTION_ID;
|
||||
ret = HvPostMessage(
|
||||
connId,
|
||||
1,
|
||||
buffer,
|
||||
bufferLen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusSetEvent()
|
||||
|
||||
Description:
|
||||
Send an event notification to the parent
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusSetEvent(UINT32 childRelId)
|
||||
{
|
||||
int ret=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Each UINT32 represents 32 channels
|
||||
BitSet((UINT32*)gVmbusConnection.SendInterruptPage + (childRelId >> 5), childRelId & 31);
|
||||
ret = HvSignalEvent();
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,672 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "logging.h"
|
||||
#include "VmbusPrivate.h"
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
|
||||
// The one and only
|
||||
HV_CONTEXT gHvContext={
|
||||
.SynICInitialized = FALSE,
|
||||
.HypercallPage = NULL,
|
||||
.SignalEventParam = NULL,
|
||||
.SignalEventBuffer = NULL,
|
||||
};
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvQueryHypervisorPresence()
|
||||
|
||||
Description:
|
||||
Query the cpuid for presense of windows hypervisor
|
||||
|
||||
--*/
|
||||
static int
|
||||
HvQueryHypervisorPresence (
|
||||
void
|
||||
)
|
||||
{
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
unsigned int op;
|
||||
|
||||
eax = 0;
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
op = HvCpuIdFunctionVersionAndFeatures;
|
||||
do_cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
return (ecx & HV_PRESENT_BIT);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvQueryHypervisorInfo()
|
||||
|
||||
Description:
|
||||
Get version info of the windows hypervisor
|
||||
|
||||
--*/
|
||||
static int
|
||||
HvQueryHypervisorInfo (
|
||||
void
|
||||
)
|
||||
{
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
unsigned int maxLeaf;
|
||||
unsigned int op;
|
||||
|
||||
//
|
||||
// Its assumed that this is called after confirming that Viridian is present.
|
||||
// Query id and revision.
|
||||
//
|
||||
|
||||
eax = 0;
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
op = HvCpuIdFunctionHvVendorAndMaxFunction;
|
||||
do_cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
DPRINT_INFO(VMBUS, "Vendor ID: %c%c%c%c%c%c%c%c%c%c%c%c",
|
||||
(ebx & 0xFF),
|
||||
((ebx >> 8) & 0xFF),
|
||||
((ebx >> 16) & 0xFF),
|
||||
((ebx >> 24) & 0xFF),
|
||||
(ecx & 0xFF),
|
||||
((ecx >> 8) & 0xFF),
|
||||
((ecx >> 16) & 0xFF),
|
||||
((ecx >> 24) & 0xFF),
|
||||
(edx & 0xFF),
|
||||
((edx >> 8) & 0xFF),
|
||||
((edx >> 16) & 0xFF),
|
||||
((edx >> 24) & 0xFF));
|
||||
|
||||
maxLeaf = eax;
|
||||
eax = 0;
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
op = HvCpuIdFunctionHvInterface;
|
||||
do_cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
|
||||
DPRINT_INFO(VMBUS, "Interface ID: %c%c%c%c",
|
||||
(eax & 0xFF),
|
||||
((eax >> 8) & 0xFF),
|
||||
((eax >> 16) & 0xFF),
|
||||
((eax >> 24) & 0xFF));
|
||||
|
||||
if (maxLeaf >= HvCpuIdFunctionMsHvVersion) {
|
||||
eax = 0;
|
||||
ebx = 0;
|
||||
ecx = 0;
|
||||
edx = 0;
|
||||
op = HvCpuIdFunctionMsHvVersion;
|
||||
do_cpuid(op, &eax, &ebx, &ecx, &edx);
|
||||
DPRINT_INFO(VMBUS, "OS Build:%d-%d.%d-%d-%d.%d",
|
||||
eax,
|
||||
ebx >> 16,
|
||||
ebx & 0xFFFF,
|
||||
ecx,
|
||||
edx >> 24,
|
||||
edx & 0xFFFFFF);
|
||||
}
|
||||
return maxLeaf;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvDoHypercall()
|
||||
|
||||
Description:
|
||||
Invoke the specified hypercall
|
||||
|
||||
--*/
|
||||
static UINT64
|
||||
HvDoHypercall (
|
||||
UINT64 Control,
|
||||
void* Input,
|
||||
void* Output
|
||||
)
|
||||
{
|
||||
#ifdef x86_64
|
||||
UINT64 hvStatus=0;
|
||||
UINT64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
|
||||
UINT64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
|
||||
volatile void* hypercallPage = gHvContext.HypercallPage;
|
||||
|
||||
DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
|
||||
Control,
|
||||
inputAddress,
|
||||
Input,
|
||||
outputAddress,
|
||||
Output,
|
||||
hypercallPage);
|
||||
|
||||
__asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
|
||||
__asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
|
||||
|
||||
DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
|
||||
|
||||
return hvStatus;
|
||||
|
||||
#else
|
||||
|
||||
UINT32 controlHi = Control >> 32;
|
||||
UINT32 controlLo = Control & 0xFFFFFFFF;
|
||||
UINT32 hvStatusHi = 1;
|
||||
UINT32 hvStatusLo = 1;
|
||||
UINT64 inputAddress = (Input) ? GetPhysicalAddress(Input) : 0;
|
||||
UINT32 inputAddressHi = inputAddress >> 32;
|
||||
UINT32 inputAddressLo = inputAddress & 0xFFFFFFFF;
|
||||
UINT64 outputAddress = (Output) ?GetPhysicalAddress(Output) : 0;
|
||||
UINT32 outputAddressHi = outputAddress >> 32;
|
||||
UINT32 outputAddressLo = outputAddress & 0xFFFFFFFF;
|
||||
volatile void* hypercallPage = gHvContext.HypercallPage;
|
||||
|
||||
DPRINT_DBG(VMBUS, "Hypercall <control %llx input %p output %p>",
|
||||
Control,
|
||||
Input,
|
||||
Output);
|
||||
|
||||
__asm__ __volatile__ ("call *%8" : "=d"(hvStatusHi), "=a"(hvStatusLo) : "d" (controlHi), "a" (controlLo), "b" (inputAddressHi), "c" (inputAddressLo), "D"(outputAddressHi), "S"(outputAddressLo), "m" (hypercallPage));
|
||||
|
||||
|
||||
DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatusLo | ((UINT64)hvStatusHi << 32));
|
||||
|
||||
return (hvStatusLo | ((UINT64)hvStatusHi << 32));
|
||||
#endif // x86_64
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvInit()
|
||||
|
||||
Description:
|
||||
Main initialization routine. This routine must be called
|
||||
before any other routines in here are called
|
||||
|
||||
--*/
|
||||
static int
|
||||
HvInit (
|
||||
void
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
int maxLeaf;
|
||||
HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
|
||||
void* virtAddr=0;
|
||||
ULONG_PTR physAddr=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
memset(gHvContext.synICEventPage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
|
||||
memset(gHvContext.synICMessagePage, 0, sizeof(HANDLE)*MAX_NUM_CPUS);
|
||||
|
||||
if (!HvQueryHypervisorPresence())
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "No Windows hypervisor detected!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
DPRINT_INFO(VMBUS, "Windows hypervisor detected! Retrieving more info...");
|
||||
|
||||
maxLeaf = HvQueryHypervisorInfo();
|
||||
//HvQueryHypervisorFeatures(maxLeaf);
|
||||
|
||||
// Determine if we are running on xenlinux (ie x2v shim) or native linux
|
||||
gHvContext.GuestId = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
|
||||
|
||||
if (gHvContext.GuestId == 0)
|
||||
{
|
||||
// Write our OS info
|
||||
WriteMsr(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
|
||||
|
||||
gHvContext.GuestId = HV_LINUX_GUEST_ID;
|
||||
}
|
||||
|
||||
// See if the hypercall page is already set
|
||||
hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
|
||||
|
||||
if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
|
||||
{
|
||||
// Allocate the hypercall page memory
|
||||
//virtAddr = PageAlloc(1);
|
||||
virtAddr = VirtualAllocExec(PAGE_SIZE);
|
||||
|
||||
if (!virtAddr)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to allocate hypercall page!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
hypercallMsr.Enable = 1;
|
||||
//hypercallMsr.GuestPhysicalAddress = Logical2PhysicalAddr(virtAddr) >> PAGE_SHIFT;
|
||||
hypercallMsr.GuestPhysicalAddress = Virtual2Physical(virtAddr) >> PAGE_SHIFT;
|
||||
WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
|
||||
|
||||
// Confirm that hypercall page did get setup.
|
||||
hypercallMsr.AsUINT64 = 0;
|
||||
hypercallMsr.AsUINT64 = ReadMsr(HV_X64_MSR_HYPERCALL);
|
||||
|
||||
if (!hypercallMsr.Enable)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to set hypercall page!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
gHvContext.HypercallPage = virtAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Unknown guest id (0x%llx)!!", gHvContext.GuestId);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
DPRINT_INFO(VMBUS, "Hypercall page VA=0x%08x, PA=0x%08x",
|
||||
(unsigned long)gHvContext.HypercallPage,
|
||||
(unsigned long)hypercallMsr.GuestPhysicalAddress << PAGE_SHIFT);
|
||||
|
||||
// Setup the global signal event param for the signal event hypercall
|
||||
gHvContext.SignalEventBuffer = MemAlloc(sizeof(HV_INPUT_SIGNAL_EVENT_BUFFER));
|
||||
if (!gHvContext.SignalEventBuffer)
|
||||
{
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
gHvContext.SignalEventParam = (PHV_INPUT_SIGNAL_EVENT)(ALIGN_UP((ULONG_PTR)gHvContext.SignalEventBuffer, HV_HYPERCALL_PARAM_ALIGN));
|
||||
gHvContext.SignalEventParam->ConnectionId.AsUINT32 = 0;
|
||||
gHvContext.SignalEventParam->ConnectionId.u.Id = VMBUS_EVENT_CONNECTION_ID;
|
||||
gHvContext.SignalEventParam->FlagNumber = 0;
|
||||
gHvContext.SignalEventParam->RsvdZ = 0;
|
||||
|
||||
//DPRINT_DBG(VMBUS, "My id %llu", HvGetCurrentPartitionId());
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
|
||||
Cleanup:
|
||||
if (virtAddr)
|
||||
{
|
||||
if (hypercallMsr.Enable)
|
||||
{
|
||||
hypercallMsr.AsUINT64 = 0;
|
||||
WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
|
||||
}
|
||||
|
||||
VirtualFree(virtAddr);
|
||||
}
|
||||
ret = -1;
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvCleanup()
|
||||
|
||||
Description:
|
||||
Cleanup routine. This routine is called normally during driver unloading or exiting.
|
||||
|
||||
--*/
|
||||
void
|
||||
HvCleanup (
|
||||
void
|
||||
)
|
||||
{
|
||||
HV_X64_MSR_HYPERCALL_CONTENTS hypercallMsr;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
if (gHvContext.SignalEventBuffer)
|
||||
{
|
||||
MemFree(gHvContext.SignalEventBuffer);
|
||||
gHvContext.SignalEventBuffer = NULL;
|
||||
gHvContext.SignalEventParam = NULL;
|
||||
}
|
||||
|
||||
if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
|
||||
{
|
||||
if (gHvContext.HypercallPage)
|
||||
{
|
||||
hypercallMsr.AsUINT64 = 0;
|
||||
WriteMsr(HV_X64_MSR_HYPERCALL, hypercallMsr.AsUINT64);
|
||||
VirtualFree(gHvContext.HypercallPage);
|
||||
gHvContext.HypercallPage = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvPostMessage()
|
||||
|
||||
Description:
|
||||
Post a message using the hypervisor message IPC. This
|
||||
involves a hypercall.
|
||||
|
||||
--*/
|
||||
HV_STATUS
|
||||
HvPostMessage(
|
||||
HV_CONNECTION_ID connectionId,
|
||||
HV_MESSAGE_TYPE messageType,
|
||||
PVOID payload,
|
||||
SIZE_T payloadSize
|
||||
)
|
||||
{
|
||||
struct alignedInput {
|
||||
UINT64 alignment8;
|
||||
HV_INPUT_POST_MESSAGE msg;
|
||||
};
|
||||
|
||||
PHV_INPUT_POST_MESSAGE alignedMsg;
|
||||
HV_STATUS status;
|
||||
ULONG_PTR addr;
|
||||
|
||||
if (payloadSize > HV_MESSAGE_PAYLOAD_BYTE_COUNT)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr = (ULONG_PTR)MemAllocAtomic(sizeof(struct alignedInput));
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
alignedMsg = (PHV_INPUT_POST_MESSAGE)(ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN));
|
||||
|
||||
alignedMsg->ConnectionId = connectionId;
|
||||
alignedMsg->MessageType = messageType;
|
||||
alignedMsg->PayloadSize = payloadSize;
|
||||
memcpy((void*)alignedMsg->Payload, payload, payloadSize);
|
||||
|
||||
status = HvDoHypercall(HvCallPostMessage, alignedMsg, 0) & 0xFFFF;
|
||||
|
||||
MemFree((void*)addr);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvSignalEvent()
|
||||
|
||||
Description:
|
||||
Signal an event on the specified connection using the hypervisor event IPC. This
|
||||
involves a hypercall.
|
||||
|
||||
--*/
|
||||
HV_STATUS
|
||||
HvSignalEvent(
|
||||
)
|
||||
{
|
||||
HV_STATUS status;
|
||||
|
||||
status = HvDoHypercall(HvCallSignalEvent, gHvContext.SignalEventParam, 0) & 0xFFFF;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvSynicInit()
|
||||
|
||||
Description:
|
||||
Initialize the Synthethic Interrupt Controller. If it is already initialized by
|
||||
another entity (ie x2v shim), we need to retrieve the initialized message and event pages.
|
||||
Otherwise, we create and initialize the message and event pages.
|
||||
|
||||
--*/
|
||||
int
|
||||
HvSynicInit (
|
||||
UINT32 irqVector
|
||||
)
|
||||
{
|
||||
UINT64 version;
|
||||
HV_SYNIC_SIMP simp;
|
||||
HV_SYNIC_SIEFP siefp;
|
||||
HV_SYNIC_SINT sharedSint;
|
||||
HV_SYNIC_SCONTROL sctrl;
|
||||
UINT64 guestID;
|
||||
int ret=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
if (!gHvContext.HypercallPage)
|
||||
{
|
||||
DPRINT_EXIT(VMBUS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Check the version
|
||||
version = ReadMsr(HV_X64_MSR_SVERSION);
|
||||
|
||||
DPRINT_INFO(VMBUS, "SynIC version: %llx", version);
|
||||
|
||||
// TODO: Handle SMP
|
||||
if (gHvContext.GuestId == HV_XENLINUX_GUEST_ID)
|
||||
{
|
||||
DPRINT_INFO(VMBUS, "Skipping SIMP and SIEFP setup since it is already set.");
|
||||
|
||||
simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
|
||||
siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
|
||||
|
||||
DPRINT_DBG(VMBUS, "Simp: %llx, Sifep: %llx", simp.AsUINT64, siefp.AsUINT64);
|
||||
|
||||
// Determine if we are running on xenlinux (ie x2v shim) or native linux
|
||||
guestID = ReadMsr(HV_X64_MSR_GUEST_OS_ID);
|
||||
|
||||
if (guestID == HV_LINUX_GUEST_ID)
|
||||
{
|
||||
gHvContext.synICMessagePage[0] = GetVirtualAddress(simp.BaseSimpGpa << PAGE_SHIFT);
|
||||
gHvContext.synICEventPage[0] = GetVirtualAddress(siefp.BaseSiefpGpa << PAGE_SHIFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unknown guest id!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", gHvContext.synICMessagePage[0], gHvContext.synICEventPage[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gHvContext.synICMessagePage[0] = PageAlloc(1);
|
||||
if (gHvContext.synICMessagePage[0] == NULL)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
gHvContext.synICEventPage[0] = PageAlloc(1);
|
||||
if (gHvContext.synICEventPage[0] == NULL)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!");
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
//
|
||||
// Setup the Synic's message page
|
||||
//
|
||||
simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
|
||||
simp.SimpEnabled = 1;
|
||||
simp.BaseSimpGpa = GetPhysicalAddress(gHvContext.synICMessagePage[0]) >> PAGE_SHIFT;
|
||||
|
||||
DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", simp.AsUINT64);
|
||||
|
||||
WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
|
||||
|
||||
//
|
||||
// Setup the Synic's event page
|
||||
//
|
||||
siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
|
||||
siefp.SiefpEnabled = 1;
|
||||
siefp.BaseSiefpGpa = GetPhysicalAddress(gHvContext.synICEventPage[0]) >> PAGE_SHIFT;
|
||||
|
||||
DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", siefp.AsUINT64);
|
||||
|
||||
WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
|
||||
}
|
||||
//
|
||||
// Setup the interception SINT.
|
||||
//
|
||||
//WriteMsr((HV_X64_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX),
|
||||
// interceptionSint.AsUINT64);
|
||||
|
||||
//
|
||||
// Setup the shared SINT.
|
||||
//
|
||||
sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
|
||||
|
||||
sharedSint.AsUINT64 = 0;
|
||||
sharedSint.Vector = irqVector; //HV_SHARED_SINT_IDT_VECTOR + 0x20;
|
||||
sharedSint.Masked = FALSE;
|
||||
sharedSint.AutoEoi = TRUE;
|
||||
|
||||
DPRINT_DBG(VMBUS, "HV_X64_MSR_SINT1 msr set to: %llx", sharedSint.AsUINT64);
|
||||
|
||||
WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
|
||||
|
||||
// Enable the global synic bit
|
||||
sctrl.AsUINT64 = ReadMsr(HV_X64_MSR_SCONTROL);
|
||||
sctrl.Enable = 1;
|
||||
|
||||
WriteMsr(HV_X64_MSR_SCONTROL, sctrl.AsUINT64);
|
||||
|
||||
gHvContext.SynICInitialized = TRUE;
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
|
||||
Cleanup:
|
||||
ret = -1;
|
||||
|
||||
if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
|
||||
{
|
||||
if (gHvContext.synICEventPage[0])
|
||||
{
|
||||
PageFree(gHvContext.synICEventPage[0],1);
|
||||
}
|
||||
|
||||
if (gHvContext.synICMessagePage[0])
|
||||
{
|
||||
PageFree(gHvContext.synICMessagePage[0], 1);
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
HvSynicCleanup()
|
||||
|
||||
Description:
|
||||
Cleanup routine for HvSynicInit().
|
||||
|
||||
--*/
|
||||
VOID
|
||||
HvSynicCleanup(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
HV_SYNIC_SINT sharedSint;
|
||||
HV_SYNIC_SIMP simp;
|
||||
HV_SYNIC_SIEFP siefp;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
if (!gHvContext.SynICInitialized)
|
||||
{
|
||||
DPRINT_EXIT(VMBUS);
|
||||
return;
|
||||
}
|
||||
|
||||
sharedSint.AsUINT64 = ReadMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT);
|
||||
|
||||
sharedSint.Masked = 1;
|
||||
|
||||
// Disable the interrupt
|
||||
WriteMsr(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64);
|
||||
|
||||
// Disable and free the resources only if we are running as native linux
|
||||
// since in xenlinux, we are sharing the resources with the x2v shim
|
||||
if (gHvContext.GuestId == HV_LINUX_GUEST_ID)
|
||||
{
|
||||
simp.AsUINT64 = ReadMsr(HV_X64_MSR_SIMP);
|
||||
simp.SimpEnabled = 0;
|
||||
simp.BaseSimpGpa = 0;
|
||||
|
||||
WriteMsr(HV_X64_MSR_SIMP, simp.AsUINT64);
|
||||
|
||||
siefp.AsUINT64 = ReadMsr(HV_X64_MSR_SIEFP);
|
||||
siefp.SiefpEnabled = 0;
|
||||
siefp.BaseSiefpGpa = 0;
|
||||
|
||||
WriteMsr(HV_X64_MSR_SIEFP, siefp.AsUINT64);
|
||||
|
||||
PageFree(gHvContext.synICMessagePage[0], 1);
|
||||
PageFree(gHvContext.synICEventPage[0], 1);
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
// eof
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __HV_H__
|
||||
#define __HV_H__
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
#include "HvTypes.h"
|
||||
#include "HvStatus.h"
|
||||
//#include "HvVmApi.h"
|
||||
//#include "HvKeApi.h"
|
||||
//#include "HvMmApi.h"
|
||||
//#include "HvCpuApi.h"
|
||||
#include "HvHalApi.h"
|
||||
#include "HvVpApi.h"
|
||||
//#include "HvTrApi.h"
|
||||
#include "HvSynicApi.h"
|
||||
//#include "HvAmApi.h"
|
||||
//#include "HvHkApi.h"
|
||||
//#include "HvValApi.h"
|
||||
#include "HvHcApi.h"
|
||||
#include "HvPtApi.h"
|
||||
|
||||
enum
|
||||
{
|
||||
VMBUS_MESSAGE_CONNECTION_ID = 1,
|
||||
VMBUS_MESSAGE_PORT_ID = 1,
|
||||
VMBUS_EVENT_CONNECTION_ID = 2,
|
||||
VMBUS_EVENT_PORT_ID = 2,
|
||||
VMBUS_MONITOR_CONNECTION_ID = 3,
|
||||
VMBUS_MONITOR_PORT_ID = 3,
|
||||
VMBUS_MESSAGE_SINT = 2
|
||||
};
|
||||
//
|
||||
// #defines
|
||||
//
|
||||
#define HV_PRESENT_BIT 0x80000000
|
||||
|
||||
#define HV_XENLINUX_GUEST_ID_LO 0x00000000
|
||||
#define HV_XENLINUX_GUEST_ID_HI 0x0B00B135
|
||||
#define HV_XENLINUX_GUEST_ID (((UINT64)HV_XENLINUX_GUEST_ID_HI << 32) | HV_XENLINUX_GUEST_ID_LO)
|
||||
|
||||
#define HV_LINUX_GUEST_ID_LO 0x00000000
|
||||
#define HV_LINUX_GUEST_ID_HI 0xB16B00B5
|
||||
#define HV_LINUX_GUEST_ID (((UINT64)HV_LINUX_GUEST_ID_HI << 32) | HV_LINUX_GUEST_ID_LO)
|
||||
|
||||
#define HV_CPU_POWER_MANAGEMENT (1 << 0)
|
||||
#define HV_RECOMMENDATIONS_MAX 4
|
||||
|
||||
#define HV_X64_MAX 5
|
||||
#define HV_CAPS_MAX 8
|
||||
|
||||
|
||||
#define HV_HYPERCALL_PARAM_ALIGN sizeof(UINT64)
|
||||
|
||||
//
|
||||
// Service definitions
|
||||
//
|
||||
#define HV_SERVICE_PARENT_PORT (0)
|
||||
#define HV_SERVICE_PARENT_CONNECTION (0)
|
||||
|
||||
#define HV_SERVICE_CONNECT_RESPONSE_SUCCESS (0)
|
||||
#define HV_SERVICE_CONNECT_RESPONSE_INVALID_PARAMETER (1)
|
||||
#define HV_SERVICE_CONNECT_RESPONSE_UNKNOWN_SERVICE (2)
|
||||
#define HV_SERVICE_CONNECT_RESPONSE_CONNECTION_REJECTED (3)
|
||||
|
||||
#define HV_SERVICE_CONNECT_REQUEST_MESSAGE_ID (1)
|
||||
#define HV_SERVICE_CONNECT_RESPONSE_MESSAGE_ID (2)
|
||||
#define HV_SERVICE_DISCONNECT_REQUEST_MESSAGE_ID (3)
|
||||
#define HV_SERVICE_DISCONNECT_RESPONSE_MESSAGE_ID (4)
|
||||
#define HV_SERVICE_MAX_MESSAGE_ID (4)
|
||||
|
||||
#define HV_SERVICE_PROTOCOL_VERSION (0x0010)
|
||||
#define HV_CONNECT_PAYLOAD_BYTE_COUNT 64
|
||||
|
||||
//#define VMBUS_REVISION_NUMBER 6
|
||||
//#define VMBUS_PORT_ID 11 // Our local vmbus's port and connection id. Anything >0 is fine
|
||||
|
||||
// 628180B8-308D-4c5e-B7DB-1BEB62E62EF4
|
||||
static const GUID VMBUS_SERVICE_ID = {.Data = {0xb8, 0x80, 0x81, 0x62, 0x8d, 0x30, 0x5e, 0x4c, 0xb7, 0xdb, 0x1b, 0xeb, 0x62, 0xe6, 0x2e, 0xf4} };
|
||||
|
||||
#define MAX_NUM_CPUS 1
|
||||
|
||||
|
||||
typedef struct {
|
||||
UINT64 Align8;
|
||||
HV_INPUT_SIGNAL_EVENT Event;
|
||||
} HV_INPUT_SIGNAL_EVENT_BUFFER;
|
||||
|
||||
typedef struct {
|
||||
UINT64 GuestId; // XenLinux or native Linux. If XenLinux, the hypercall and synic pages has already been initialized
|
||||
void* HypercallPage;
|
||||
|
||||
BOOL SynICInitialized;
|
||||
// This is used as an input param to HvCallSignalEvent hypercall. The input param is immutable
|
||||
// in our usage and must be dynamic mem (vs stack or global).
|
||||
HV_INPUT_SIGNAL_EVENT_BUFFER *SignalEventBuffer;
|
||||
HV_INPUT_SIGNAL_EVENT *SignalEventParam; // 8-bytes aligned of the buffer above
|
||||
|
||||
HANDLE synICMessagePage[MAX_NUM_CPUS];
|
||||
HANDLE synICEventPage[MAX_NUM_CPUS];
|
||||
} HV_CONTEXT;
|
||||
|
||||
extern HV_CONTEXT gHvContext;
|
||||
|
||||
|
||||
//
|
||||
// Inline routines
|
||||
//
|
||||
static inline unsigned long long ReadMsr(int msr)
|
||||
{
|
||||
unsigned long long val;
|
||||
|
||||
RDMSR(msr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void WriteMsr(int msr, UINT64 val)
|
||||
{
|
||||
WRMSR(msr, val);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Hv Interface
|
||||
//
|
||||
INTERNAL int
|
||||
HvInit(
|
||||
VOID
|
||||
);
|
||||
|
||||
INTERNAL VOID
|
||||
HvCleanup(
|
||||
VOID
|
||||
);
|
||||
|
||||
INTERNAL HV_STATUS
|
||||
HvPostMessage(
|
||||
HV_CONNECTION_ID connectionId,
|
||||
HV_MESSAGE_TYPE messageType,
|
||||
PVOID payload,
|
||||
SIZE_T payloadSize
|
||||
);
|
||||
|
||||
INTERNAL HV_STATUS
|
||||
HvSignalEvent(
|
||||
VOID
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
HvSynicInit(
|
||||
UINT32 irqVector
|
||||
);
|
||||
|
||||
INTERNAL VOID
|
||||
HvSynicCleanup(
|
||||
VOID
|
||||
);
|
||||
|
||||
#endif // __HV_H__
|
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "logging.h"
|
||||
#include "RingBuffer.h"
|
||||
|
||||
//
|
||||
// #defines
|
||||
//
|
||||
|
||||
// Amount of space to write to
|
||||
#define BYTES_AVAIL_TO_WRITE(r, w, z) ((w) >= (r))?((z) - ((w) - (r))):((r) - (w))
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetRingBufferAvailBytes()
|
||||
|
||||
Description:
|
||||
Get number of bytes available to read and to write to
|
||||
for the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline void
|
||||
GetRingBufferAvailBytes(RING_BUFFER_INFO *rbi, UINT32 *read, UINT32 *write)
|
||||
{
|
||||
UINT32 read_loc,write_loc;
|
||||
|
||||
// Capture the read/write indices before they changed
|
||||
read_loc = rbi->RingBuffer->ReadIndex;
|
||||
write_loc = rbi->RingBuffer->WriteIndex;
|
||||
|
||||
*write = BYTES_AVAIL_TO_WRITE(read_loc, write_loc, rbi->RingDataSize);
|
||||
*read = rbi->RingDataSize - *write;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetNextWriteLocation()
|
||||
|
||||
Description:
|
||||
Get the next write location for the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline UINT32
|
||||
GetNextWriteLocation(RING_BUFFER_INFO* RingInfo)
|
||||
{
|
||||
UINT32 next = RingInfo->RingBuffer->WriteIndex;
|
||||
|
||||
ASSERT(next < RingInfo->RingDataSize);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
SetNextWriteLocation()
|
||||
|
||||
Description:
|
||||
Set the next write location for the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline void
|
||||
SetNextWriteLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextWriteLocation)
|
||||
{
|
||||
RingInfo->RingBuffer->WriteIndex = NextWriteLocation;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetNextReadLocation()
|
||||
|
||||
Description:
|
||||
Get the next read location for the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline UINT32
|
||||
GetNextReadLocation(RING_BUFFER_INFO* RingInfo)
|
||||
{
|
||||
UINT32 next = RingInfo->RingBuffer->ReadIndex;
|
||||
|
||||
ASSERT(next < RingInfo->RingDataSize);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetNextReadLocationWithOffset()
|
||||
|
||||
Description:
|
||||
Get the next read location + offset for the specified ring buffer.
|
||||
This allows the caller to skip
|
||||
|
||||
--*/
|
||||
static inline UINT32
|
||||
GetNextReadLocationWithOffset(RING_BUFFER_INFO* RingInfo, UINT32 Offset)
|
||||
{
|
||||
UINT32 next = RingInfo->RingBuffer->ReadIndex;
|
||||
|
||||
ASSERT(next < RingInfo->RingDataSize);
|
||||
next += Offset;
|
||||
next %= RingInfo->RingDataSize;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
SetNextReadLocation()
|
||||
|
||||
Description:
|
||||
Set the next read location for the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline void
|
||||
SetNextReadLocation(RING_BUFFER_INFO* RingInfo, UINT32 NextReadLocation)
|
||||
{
|
||||
RingInfo->RingBuffer->ReadIndex = NextReadLocation;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetRingBuffer()
|
||||
|
||||
Description:
|
||||
Get the start of the ring buffer
|
||||
|
||||
--*/
|
||||
static inline PVOID
|
||||
GetRingBuffer(RING_BUFFER_INFO* RingInfo)
|
||||
{
|
||||
return (PVOID)RingInfo->RingBuffer->Buffer;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetRingBufferSize()
|
||||
|
||||
Description:
|
||||
Get the size of the ring buffer
|
||||
|
||||
--*/
|
||||
static inline UINT32
|
||||
GetRingBufferSize(RING_BUFFER_INFO* RingInfo)
|
||||
{
|
||||
return RingInfo->RingDataSize;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetRingBufferIndices()
|
||||
|
||||
Description:
|
||||
Get the read and write indices as UINT64 of the specified ring buffer
|
||||
|
||||
--*/
|
||||
static inline UINT64
|
||||
GetRingBufferIndices(RING_BUFFER_INFO* RingInfo)
|
||||
{
|
||||
return ((UINT64)RingInfo->RingBuffer->WriteIndex << 32) || RingInfo->RingBuffer->ReadIndex;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
DumpRingInfo()
|
||||
|
||||
Description:
|
||||
Dump out to console the ring buffer info
|
||||
|
||||
--*/
|
||||
void
|
||||
DumpRingInfo(RING_BUFFER_INFO* RingInfo, char *Prefix)
|
||||
{
|
||||
UINT32 bytesAvailToWrite;
|
||||
UINT32 bytesAvailToRead;
|
||||
|
||||
GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
|
||||
|
||||
DPRINT(VMBUS, DEBUG_RING_LVL, "%s <<ringinfo %p buffer %p avail write %u avail read %u read idx %u write idx %u>>",
|
||||
Prefix,
|
||||
RingInfo,
|
||||
RingInfo->RingBuffer->Buffer,
|
||||
bytesAvailToWrite,
|
||||
bytesAvailToRead,
|
||||
RingInfo->RingBuffer->ReadIndex,
|
||||
RingInfo->RingBuffer->WriteIndex);
|
||||
}
|
||||
|
||||
//
|
||||
// Internal routines
|
||||
//
|
||||
static UINT32
|
||||
CopyToRingBuffer(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
UINT32 StartWriteOffset,
|
||||
PVOID Src,
|
||||
UINT32 SrcLen);
|
||||
|
||||
static UINT32
|
||||
CopyFromRingBuffer(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
PVOID Dest,
|
||||
UINT32 DestLen,
|
||||
UINT32 StartReadOffset);
|
||||
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferGetDebugInfo()
|
||||
|
||||
Description:
|
||||
Get various debug metrics for the specified ring buffer
|
||||
|
||||
--*/
|
||||
void
|
||||
RingBufferGetDebugInfo(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
RING_BUFFER_DEBUG_INFO *DebugInfo
|
||||
)
|
||||
{
|
||||
UINT32 bytesAvailToWrite;
|
||||
UINT32 bytesAvailToRead;
|
||||
|
||||
if (RingInfo->RingBuffer)
|
||||
{
|
||||
GetRingBufferAvailBytes(RingInfo, &bytesAvailToRead, &bytesAvailToWrite);
|
||||
|
||||
DebugInfo->BytesAvailToRead = bytesAvailToRead;
|
||||
DebugInfo->BytesAvailToWrite = bytesAvailToWrite;
|
||||
DebugInfo->CurrentReadIndex = RingInfo->RingBuffer->ReadIndex;
|
||||
DebugInfo->CurrentWriteIndex = RingInfo->RingBuffer->WriteIndex;
|
||||
|
||||
DebugInfo->CurrentInterruptMask = RingInfo->RingBuffer->InterruptMask;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
GetRingBufferInterruptMask()
|
||||
|
||||
Description:
|
||||
Get the interrupt mask for the specified ring buffer
|
||||
|
||||
--*/
|
||||
UINT32
|
||||
GetRingBufferInterruptMask(
|
||||
RING_BUFFER_INFO *rbi
|
||||
)
|
||||
{
|
||||
return rbi->RingBuffer->InterruptMask;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferInit()
|
||||
|
||||
Description:
|
||||
Initialize the ring buffer
|
||||
|
||||
--*/
|
||||
int
|
||||
RingBufferInit(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
VOID *Buffer,
|
||||
UINT32 BufferLen
|
||||
)
|
||||
{
|
||||
ASSERT(sizeof(RING_BUFFER) == PAGE_SIZE);
|
||||
|
||||
memset(RingInfo, 0, sizeof(RING_BUFFER_INFO));
|
||||
|
||||
RingInfo->RingBuffer = (RING_BUFFER*)Buffer;
|
||||
RingInfo->RingBuffer->ReadIndex = RingInfo->RingBuffer->WriteIndex = 0;
|
||||
|
||||
RingInfo->RingSize = BufferLen;
|
||||
RingInfo->RingDataSize = BufferLen - sizeof(RING_BUFFER);
|
||||
|
||||
RingInfo->RingLock = SpinlockCreate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferCleanup()
|
||||
|
||||
Description:
|
||||
Cleanup the ring buffer
|
||||
|
||||
--*/
|
||||
void
|
||||
RingBufferCleanup(
|
||||
RING_BUFFER_INFO* RingInfo
|
||||
)
|
||||
{
|
||||
SpinlockClose(RingInfo->RingLock);
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferWrite()
|
||||
|
||||
Description:
|
||||
Write to the ring buffer
|
||||
|
||||
--*/
|
||||
int
|
||||
RingBufferWrite(
|
||||
RING_BUFFER_INFO* OutRingInfo,
|
||||
SG_BUFFER_LIST SgBuffers[],
|
||||
UINT32 SgBufferCount
|
||||
)
|
||||
{
|
||||
int i=0;
|
||||
UINT32 byteAvailToWrite;
|
||||
UINT32 byteAvailToRead;
|
||||
UINT32 totalBytesToWrite=0;
|
||||
|
||||
volatile UINT32 nextWriteLocation;
|
||||
UINT64 prevIndices=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
for (i=0; i < SgBufferCount; i++)
|
||||
{
|
||||
totalBytesToWrite += SgBuffers[i].Length;
|
||||
}
|
||||
|
||||
totalBytesToWrite += sizeof(UINT64);
|
||||
|
||||
SpinlockAcquire(OutRingInfo->RingLock);
|
||||
|
||||
GetRingBufferAvailBytes(OutRingInfo, &byteAvailToRead, &byteAvailToWrite);
|
||||
|
||||
DPRINT_DBG(VMBUS, "Writing %u bytes...", totalBytesToWrite);
|
||||
|
||||
//DumpRingInfo(OutRingInfo, "BEFORE ");
|
||||
|
||||
// If there is only room for the packet, assume it is full. Otherwise, the next time around, we think the ring buffer
|
||||
// is empty since the read index == write index
|
||||
if (byteAvailToWrite <= totalBytesToWrite)
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "No more space left on outbound ring buffer (needed %u, avail %u)", totalBytesToWrite, byteAvailToWrite);
|
||||
|
||||
SpinlockRelease(OutRingInfo->RingLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write to the ring buffer
|
||||
nextWriteLocation = GetNextWriteLocation(OutRingInfo);
|
||||
|
||||
for (i=0; i < SgBufferCount; i++)
|
||||
{
|
||||
nextWriteLocation = CopyToRingBuffer(OutRingInfo,
|
||||
nextWriteLocation,
|
||||
SgBuffers[i].Data,
|
||||
SgBuffers[i].Length);
|
||||
}
|
||||
|
||||
// Set previous packet start
|
||||
prevIndices = GetRingBufferIndices(OutRingInfo);
|
||||
|
||||
nextWriteLocation = CopyToRingBuffer(OutRingInfo,
|
||||
nextWriteLocation,
|
||||
&prevIndices,
|
||||
sizeof(UINT64));
|
||||
|
||||
// Make sure we flush all writes before updating the writeIndex
|
||||
MemoryFence();
|
||||
|
||||
// Now, update the write location
|
||||
SetNextWriteLocation(OutRingInfo, nextWriteLocation);
|
||||
|
||||
//DumpRingInfo(OutRingInfo, "AFTER ");
|
||||
|
||||
SpinlockRelease(OutRingInfo->RingLock);
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferPeek()
|
||||
|
||||
Description:
|
||||
Read without advancing the read index
|
||||
|
||||
--*/
|
||||
int
|
||||
RingBufferPeek(
|
||||
RING_BUFFER_INFO* InRingInfo,
|
||||
void* Buffer,
|
||||
UINT32 BufferLen
|
||||
)
|
||||
{
|
||||
UINT32 bytesAvailToWrite;
|
||||
UINT32 bytesAvailToRead;
|
||||
UINT32 nextReadLocation=0;
|
||||
|
||||
SpinlockAcquire(InRingInfo->RingLock);
|
||||
|
||||
GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
|
||||
|
||||
// Make sure there is something to read
|
||||
if (bytesAvailToRead < BufferLen )
|
||||
{
|
||||
//DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
|
||||
|
||||
SpinlockRelease(InRingInfo->RingLock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert to byte offset
|
||||
nextReadLocation = GetNextReadLocation(InRingInfo);
|
||||
|
||||
nextReadLocation = CopyFromRingBuffer(InRingInfo,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
nextReadLocation);
|
||||
|
||||
SpinlockRelease(InRingInfo->RingLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
RingBufferRead()
|
||||
|
||||
Description:
|
||||
Read and advance the read index
|
||||
|
||||
--*/
|
||||
int
|
||||
RingBufferRead(
|
||||
RING_BUFFER_INFO* InRingInfo,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32 Offset
|
||||
)
|
||||
{
|
||||
UINT32 bytesAvailToWrite;
|
||||
UINT32 bytesAvailToRead;
|
||||
UINT32 nextReadLocation=0;
|
||||
UINT64 prevIndices=0;
|
||||
|
||||
ASSERT(BufferLen > 0);
|
||||
|
||||
SpinlockAcquire(InRingInfo->RingLock);
|
||||
|
||||
GetRingBufferAvailBytes(InRingInfo, &bytesAvailToRead, &bytesAvailToWrite);
|
||||
|
||||
DPRINT_DBG(VMBUS, "Reading %u bytes...", BufferLen);
|
||||
|
||||
//DumpRingInfo(InRingInfo, "BEFORE ");
|
||||
|
||||
// Make sure there is something to read
|
||||
if (bytesAvailToRead < BufferLen )
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "got callback but not enough to read <avail to read %d read size %d>!!", bytesAvailToRead, BufferLen);
|
||||
|
||||
SpinlockRelease(InRingInfo->RingLock);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
nextReadLocation = GetNextReadLocationWithOffset(InRingInfo, Offset);
|
||||
|
||||
nextReadLocation = CopyFromRingBuffer(InRingInfo,
|
||||
Buffer,
|
||||
BufferLen,
|
||||
nextReadLocation);
|
||||
|
||||
nextReadLocation = CopyFromRingBuffer(InRingInfo,
|
||||
&prevIndices,
|
||||
sizeof(UINT64),
|
||||
nextReadLocation);
|
||||
|
||||
// Make sure all reads are done before we update the read index since
|
||||
// the writer may start writing to the read area once the read index is updated
|
||||
MemoryFence();
|
||||
|
||||
// Update the read index
|
||||
SetNextReadLocation(InRingInfo, nextReadLocation);
|
||||
|
||||
//DumpRingInfo(InRingInfo, "AFTER ");
|
||||
|
||||
SpinlockRelease(InRingInfo->RingLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
CopyToRingBuffer()
|
||||
|
||||
Description:
|
||||
Helper routine to copy from source to ring buffer.
|
||||
Assume there is enough room. Handles wrap-around in dest case only!!
|
||||
|
||||
--*/
|
||||
UINT32
|
||||
CopyToRingBuffer(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
UINT32 StartWriteOffset,
|
||||
PVOID Src,
|
||||
UINT32 SrcLen)
|
||||
{
|
||||
PVOID ringBuffer=GetRingBuffer(RingInfo);
|
||||
UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
|
||||
UINT32 fragLen;
|
||||
|
||||
if (SrcLen > ringBufferSize - StartWriteOffset) // wrap-around detected!
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "wrap-around detected!");
|
||||
|
||||
fragLen = ringBufferSize - StartWriteOffset;
|
||||
memcpy(ringBuffer + StartWriteOffset, Src, fragLen);
|
||||
memcpy(ringBuffer, Src + fragLen, SrcLen - fragLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(ringBuffer + StartWriteOffset, Src, SrcLen);
|
||||
}
|
||||
|
||||
StartWriteOffset += SrcLen;
|
||||
StartWriteOffset %= ringBufferSize;
|
||||
|
||||
return StartWriteOffset;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
CopyFromRingBuffer()
|
||||
|
||||
Description:
|
||||
Helper routine to copy to source from ring buffer.
|
||||
Assume there is enough room. Handles wrap-around in src case only!!
|
||||
|
||||
--*/
|
||||
UINT32
|
||||
CopyFromRingBuffer(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
PVOID Dest,
|
||||
UINT32 DestLen,
|
||||
UINT32 StartReadOffset)
|
||||
{
|
||||
PVOID ringBuffer=GetRingBuffer(RingInfo);
|
||||
UINT32 ringBufferSize=GetRingBufferSize(RingInfo);
|
||||
|
||||
UINT32 fragLen;
|
||||
|
||||
if (DestLen > ringBufferSize - StartReadOffset) // wrap-around detected at the src
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "src wrap-around detected!");
|
||||
|
||||
fragLen = ringBufferSize - StartReadOffset;
|
||||
|
||||
memcpy(Dest, ringBuffer + StartReadOffset, fragLen);
|
||||
memcpy(Dest + fragLen, ringBuffer, DestLen - fragLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(Dest, ringBuffer + StartReadOffset, DestLen);
|
||||
}
|
||||
|
||||
StartReadOffset += DestLen;
|
||||
StartReadOffset %= ringBufferSize;
|
||||
|
||||
return StartReadOffset;
|
||||
}
|
||||
|
||||
|
||||
// eof
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RING_BUFFER_H_
|
||||
#define _RING_BUFFER_H_
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
typedef struct _SG_BUFFER_LIST {
|
||||
PVOID Data;
|
||||
UINT32 Length;
|
||||
} SG_BUFFER_LIST;
|
||||
|
||||
typedef struct _RING_BUFFER {
|
||||
volatile UINT32 WriteIndex; // Offset in bytes from the start of ring data below
|
||||
volatile UINT32 ReadIndex; // Offset in bytes from the start of ring data below
|
||||
|
||||
volatile UINT32 InterruptMask;
|
||||
UINT8 Reserved[4084]; // Pad it to PAGE_SIZE so that data starts on page boundary
|
||||
// NOTE: The InterruptMask field is used only for channels but since our vmbus connection
|
||||
// also uses this data structure and its data starts here, we commented out this field.
|
||||
// volatile UINT32 InterruptMask;
|
||||
// Ring data starts here + RingDataStartOffset !!! DO NOT place any fields below this !!!
|
||||
UINT8 Buffer[0];
|
||||
} STRUCT_PACKED RING_BUFFER;
|
||||
|
||||
typedef struct _RING_BUFFER_INFO {
|
||||
RING_BUFFER* RingBuffer;
|
||||
UINT32 RingSize; // Include the shared header
|
||||
HANDLE RingLock;
|
||||
|
||||
UINT32 RingDataSize; // < ringSize
|
||||
UINT32 RingDataStartOffset;
|
||||
|
||||
} RING_BUFFER_INFO;
|
||||
|
||||
|
||||
typedef struct _RING_BUFFER_DEBUG_INFO {
|
||||
UINT32 CurrentInterruptMask;
|
||||
UINT32 CurrentReadIndex;
|
||||
UINT32 CurrentWriteIndex;
|
||||
UINT32 BytesAvailToRead;
|
||||
UINT32 BytesAvailToWrite;
|
||||
}RING_BUFFER_DEBUG_INFO;
|
||||
|
||||
|
||||
//
|
||||
// Interface
|
||||
//
|
||||
|
||||
INTERNAL int
|
||||
RingBufferInit(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
RingBufferCleanup(
|
||||
RING_BUFFER_INFO *RingInfo
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
RingBufferWrite(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
SG_BUFFER_LIST SgBuffers[],
|
||||
UINT32 SgBufferCount
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
RingBufferPeek(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
RingBufferRead(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
PVOID Buffer,
|
||||
UINT32 BufferLen,
|
||||
UINT32 Offset
|
||||
);
|
||||
|
||||
INTERNAL UINT32
|
||||
GetRingBufferInterruptMask(
|
||||
RING_BUFFER_INFO *RingInfo
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
DumpRingInfo(
|
||||
RING_BUFFER_INFO* RingInfo,
|
||||
char *Prefix
|
||||
);
|
||||
|
||||
INTERNAL void
|
||||
RingBufferGetDebugInfo(
|
||||
RING_BUFFER_INFO *RingInfo,
|
||||
RING_BUFFER_DEBUG_INFO *DebugInfo
|
||||
);
|
||||
|
||||
#endif // _RING_BUFFER_H_
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "Vmbus.c"
|
||||
#include "Hv.c"
|
||||
#include "Connection.c"
|
||||
#include "Channel.c"
|
||||
#include "ChannelMgmt.c"
|
||||
#include "ChannelInterface.c"
|
||||
#include "RingBuffer.c"
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
const char VersionDate[]=__DATE__;
|
||||
const char VersionTime[]=__TIME__;
|
||||
const char VersionDesc[]= "Version 2.0";
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "logging.h"
|
||||
#include "VersionInfo.h"
|
||||
#include "VmbusPrivate.h"
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
static const char* gDriverName="vmbus";
|
||||
|
||||
// Windows vmbus does not defined this. We defined this to be consistent with other devices
|
||||
//{c5295816-f63a-4d5f-8d1a-4daf999ca185}
|
||||
static const GUID gVmbusDeviceType={
|
||||
.Data = {0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85}
|
||||
};
|
||||
|
||||
//{ac3760fc-9adf-40aa-9427-a70ed6de95c5}
|
||||
static const GUID gVmbusDeviceId={
|
||||
.Data = {0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5}
|
||||
};
|
||||
|
||||
static DRIVER_OBJECT* gDriver; // vmbus driver object
|
||||
static DEVICE_OBJECT* gDevice; // vmbus root device
|
||||
|
||||
|
||||
//
|
||||
// Internal routines
|
||||
//
|
||||
|
||||
static void
|
||||
VmbusGetChannelInterface(
|
||||
VMBUS_CHANNEL_INTERFACE *Interface
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusGetChannelInfo(
|
||||
DEVICE_OBJECT *DeviceObject,
|
||||
DEVICE_INFO *DeviceInfo
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusGetChannelOffers(
|
||||
void
|
||||
);
|
||||
|
||||
static int
|
||||
VmbusOnDeviceAdd(
|
||||
DEVICE_OBJECT *Device,
|
||||
void *AdditionalInfo
|
||||
);
|
||||
|
||||
static int
|
||||
VmbusOnDeviceRemove(
|
||||
DEVICE_OBJECT* dev
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusOnCleanup(
|
||||
DRIVER_OBJECT* drv
|
||||
);
|
||||
|
||||
static int
|
||||
VmbusOnISR(
|
||||
DRIVER_OBJECT* drv
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusOnMsgDPC(
|
||||
DRIVER_OBJECT* drv
|
||||
);
|
||||
|
||||
static void
|
||||
VmbusOnEventDPC(
|
||||
DRIVER_OBJECT* drv
|
||||
);
|
||||
|
||||
/*++;
|
||||
|
||||
Name:
|
||||
VmbusInitialize()
|
||||
|
||||
Description:
|
||||
Main entry point
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusInitialize(
|
||||
DRIVER_OBJECT* drv
|
||||
)
|
||||
{
|
||||
VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
|
||||
int ret=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
DPRINT_INFO(VMBUS, "+++++++ Build Date=%s %s +++++++", VersionDate, VersionTime);
|
||||
DPRINT_INFO(VMBUS, "+++++++ Build Description=%s +++++++", VersionDesc);
|
||||
|
||||
DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", VMBUS_REVISION_NUMBER);
|
||||
DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", VMBUS_MESSAGE_SINT);
|
||||
|
||||
DPRINT_DBG(VMBUS, "sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER)=%d, sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%d",
|
||||
sizeof(VMBUS_CHANNEL_PACKET_PAGE_BUFFER), sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER));
|
||||
|
||||
drv->name = gDriverName;
|
||||
memcpy(&drv->deviceType, &gVmbusDeviceType, sizeof(GUID));
|
||||
|
||||
// Setup dispatch table
|
||||
driver->Base.OnDeviceAdd = VmbusOnDeviceAdd;
|
||||
driver->Base.OnDeviceRemove = VmbusOnDeviceRemove;
|
||||
driver->Base.OnCleanup = VmbusOnCleanup;
|
||||
driver->OnIsr = VmbusOnISR;
|
||||
driver->OnMsgDpc = VmbusOnMsgDPC;
|
||||
driver->OnEventDpc = VmbusOnEventDPC;
|
||||
driver->GetChannelOffers = VmbusGetChannelOffers;
|
||||
driver->GetChannelInterface = VmbusGetChannelInterface;
|
||||
driver->GetChannelInfo = VmbusGetChannelInfo;
|
||||
|
||||
// Hypervisor initialization...setup hypercall page..etc
|
||||
ret = HvInit();
|
||||
if (ret != 0)
|
||||
{
|
||||
DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", ret);
|
||||
}
|
||||
|
||||
gDriver = drv;
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++;
|
||||
|
||||
Name:
|
||||
VmbusGetChannelOffers()
|
||||
|
||||
Description:
|
||||
Retrieve the channel offers from the parent partition
|
||||
|
||||
--*/
|
||||
|
||||
static void
|
||||
VmbusGetChannelOffers(void)
|
||||
{
|
||||
DPRINT_ENTER(VMBUS);
|
||||
VmbusChannelRequestOffers();
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++;
|
||||
|
||||
Name:
|
||||
VmbusGetChannelInterface()
|
||||
|
||||
Description:
|
||||
Get the channel interface
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusGetChannelInterface(
|
||||
VMBUS_CHANNEL_INTERFACE *Interface
|
||||
)
|
||||
{
|
||||
GetChannelInterface(Interface);
|
||||
}
|
||||
|
||||
|
||||
/*++;
|
||||
|
||||
Name:
|
||||
VmbusGetChannelInterface()
|
||||
|
||||
Description:
|
||||
Get the device info for the specified device object
|
||||
|
||||
--*/
|
||||
static void
|
||||
VmbusGetChannelInfo(
|
||||
DEVICE_OBJECT *DeviceObject,
|
||||
DEVICE_INFO *DeviceInfo
|
||||
)
|
||||
{
|
||||
GetChannelInfo(DeviceObject, DeviceInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusCreateChildDevice()
|
||||
|
||||
Description:
|
||||
Creates the child device on the bus that represents the channel offer
|
||||
|
||||
--*/
|
||||
|
||||
DEVICE_OBJECT*
|
||||
VmbusChildDeviceCreate(
|
||||
GUID DeviceType,
|
||||
GUID DeviceInstance,
|
||||
void *Context)
|
||||
{
|
||||
VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
|
||||
|
||||
return vmbusDriver->OnChildDeviceCreate(
|
||||
DeviceType,
|
||||
DeviceInstance,
|
||||
Context);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChildDeviceAdd()
|
||||
|
||||
Description:
|
||||
Registers the child device with the vmbus
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusChildDeviceAdd(
|
||||
DEVICE_OBJECT* ChildDevice)
|
||||
{
|
||||
VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
|
||||
|
||||
return vmbusDriver->OnChildDeviceAdd(gDevice, ChildDevice);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChildDeviceRemove()
|
||||
|
||||
Description:
|
||||
Unregisters the child device from the vmbus
|
||||
|
||||
--*/
|
||||
void
|
||||
VmbusChildDeviceRemove(
|
||||
DEVICE_OBJECT* ChildDevice)
|
||||
{
|
||||
VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
|
||||
|
||||
vmbusDriver->OnChildDeviceRemove(ChildDevice);
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusChildDeviceDestroy()
|
||||
|
||||
Description:
|
||||
Release the child device from the vmbus
|
||||
|
||||
--*/
|
||||
//void
|
||||
//VmbusChildDeviceDestroy(
|
||||
// DEVICE_OBJECT* ChildDevice
|
||||
// )
|
||||
//{
|
||||
// VMBUS_DRIVER_OBJECT* vmbusDriver = (VMBUS_DRIVER_OBJECT*)gDriver;
|
||||
//
|
||||
// vmbusDriver->OnChildDeviceDestroy(ChildDevice);
|
||||
//}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnDeviceAdd()
|
||||
|
||||
Description:
|
||||
Callback when the root bus device is added
|
||||
|
||||
--*/
|
||||
static int
|
||||
VmbusOnDeviceAdd(
|
||||
DEVICE_OBJECT *dev,
|
||||
void *AdditionalInfo
|
||||
)
|
||||
{
|
||||
UINT32 *irqvector = (UINT32*) AdditionalInfo;
|
||||
int ret=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
gDevice = dev;
|
||||
|
||||
memcpy(&gDevice->deviceType, &gVmbusDeviceType, sizeof(GUID));
|
||||
memcpy(&gDevice->deviceInstance, &gVmbusDeviceId, sizeof(GUID));
|
||||
|
||||
//strcpy(dev->name, "vmbus");
|
||||
// SynIC setup...
|
||||
ret = HvSynicInit(*irqvector);
|
||||
|
||||
// Connect to VMBus in the root partition
|
||||
ret = VmbusConnect();
|
||||
|
||||
//VmbusSendEvent(device->localPortId+1);
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnDeviceRemove()
|
||||
|
||||
Description:
|
||||
Callback when the root bus device is removed
|
||||
|
||||
--*/
|
||||
int VmbusOnDeviceRemove(
|
||||
DEVICE_OBJECT* dev
|
||||
)
|
||||
{
|
||||
int ret=0;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
VmbusChannelReleaseUnattachedChannels();
|
||||
|
||||
VmbusDisconnect();
|
||||
|
||||
HvSynicCleanup();
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnCleanup()
|
||||
|
||||
Description:
|
||||
Perform any cleanup when the driver is removed
|
||||
|
||||
--*/
|
||||
void
|
||||
VmbusOnCleanup(
|
||||
DRIVER_OBJECT* drv
|
||||
)
|
||||
{
|
||||
//VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
HvCleanup();
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnMsgDPC()
|
||||
|
||||
Description:
|
||||
DPC routine to handle messages from the hypervisior
|
||||
|
||||
--*/
|
||||
void
|
||||
VmbusOnMsgDPC(
|
||||
DRIVER_OBJECT* drv
|
||||
)
|
||||
{
|
||||
void *page_addr = gHvContext.synICMessagePage[0];
|
||||
|
||||
HV_MESSAGE* msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
|
||||
HV_MESSAGE *copied;
|
||||
while (1)
|
||||
{
|
||||
if (msg->Header.MessageType == HvMessageTypeNone) // no msg
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
copied = MemAllocAtomic(sizeof(HV_MESSAGE));
|
||||
if (copied == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(copied, msg, sizeof(HV_MESSAGE));
|
||||
WorkQueueQueueWorkItem(gVmbusConnection.WorkQueue, VmbusOnChannelMessage, (void*)copied);
|
||||
}
|
||||
|
||||
msg->Header.MessageType = HvMessageTypeNone;
|
||||
|
||||
// Make sure the write to MessageType (ie set to HvMessageTypeNone) happens
|
||||
// before we read the MessagePending and EOMing. Otherwise, the EOMing will not deliver
|
||||
// any more messages since there is no empty slot
|
||||
MemoryFence();
|
||||
|
||||
if (msg->Header.MessageFlags.MessagePending)
|
||||
{
|
||||
// This will cause message queue rescan to possibly deliver another msg from the hypervisor
|
||||
WriteMsr(HV_X64_MSR_EOM, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnEventDPC()
|
||||
|
||||
Description:
|
||||
DPC routine to handle events from the hypervisior
|
||||
|
||||
--*/
|
||||
void
|
||||
VmbusOnEventDPC(
|
||||
DRIVER_OBJECT* drv
|
||||
)
|
||||
{
|
||||
// TODO: Process any events
|
||||
VmbusOnEvents();
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
|
||||
Name:
|
||||
VmbusOnISR()
|
||||
|
||||
Description:
|
||||
ISR routine
|
||||
|
||||
--*/
|
||||
int
|
||||
VmbusOnISR(
|
||||
DRIVER_OBJECT* drv
|
||||
)
|
||||
{
|
||||
//VMBUS_DRIVER_OBJECT* driver = (VMBUS_DRIVER_OBJECT*)drv;
|
||||
|
||||
int ret=0;
|
||||
//struct page* page;
|
||||
void *page_addr;
|
||||
HV_MESSAGE* msg;
|
||||
HV_SYNIC_EVENT_FLAGS* event;
|
||||
|
||||
//page = SynICMessagePage[0];
|
||||
//page_addr = page_address(page);
|
||||
page_addr = gHvContext.synICMessagePage[0];
|
||||
msg = (HV_MESSAGE*)page_addr + VMBUS_MESSAGE_SINT;
|
||||
|
||||
DPRINT_ENTER(VMBUS);
|
||||
|
||||
// Check if there are actual msgs to be process
|
||||
if (msg->Header.MessageType != HvMessageTypeNone)
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "received msg type %d size %d", msg->Header.MessageType, msg->Header.PayloadSize);
|
||||
ret |= 0x1;
|
||||
}
|
||||
|
||||
// TODO: Check if there are events to be process
|
||||
page_addr = gHvContext.synICEventPage[0];
|
||||
event = (HV_SYNIC_EVENT_FLAGS*)page_addr + VMBUS_MESSAGE_SINT;
|
||||
|
||||
// Since we are a child, we only need to check bit 0
|
||||
if (BitTestAndClear(&event->Flags32[0], 0))
|
||||
{
|
||||
DPRINT_DBG(VMBUS, "received event %d", event->Flags32[0]);
|
||||
ret |= 0x2;
|
||||
}
|
||||
|
||||
DPRINT_EXIT(VMBUS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// eof
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _VMBUS_PRIVATE_H_
|
||||
#define _VMBUS_PRIVATE_H_
|
||||
|
||||
#ifndef INTERNAL
|
||||
#define INTERNAL static
|
||||
#endif
|
||||
|
||||
#include "Hv.h"
|
||||
#include "VmbusApi.h"
|
||||
#include "Channel.h"
|
||||
#include "ChannelMgmt.h"
|
||||
#include "ChannelInterface.h"
|
||||
//#include "ChannelMessages.h"
|
||||
#include "RingBuffer.h"
|
||||
//#include "Packet.h"
|
||||
#include "List.h"
|
||||
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
|
||||
// Maximum channels is determined by the size of the interrupt page which is PAGE_SIZE. 1/2 of PAGE_SIZE is for
|
||||
// send endpoint interrupt and the other is receive endpoint interrupt
|
||||
#define MAX_NUM_CHANNELS (PAGE_SIZE >> 1) << 3 // 16348 channels
|
||||
|
||||
// The value here must be in multiple of 32
|
||||
// TODO: Need to make this configurable
|
||||
#define MAX_NUM_CHANNELS_SUPPORTED 256
|
||||
|
||||
//
|
||||
// Data types
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
Disconnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
Disconnecting
|
||||
} VMBUS_CONNECT_STATE;
|
||||
|
||||
#define MAX_SIZE_CHANNEL_MESSAGE HV_MESSAGE_PAYLOAD_BYTE_COUNT
|
||||
|
||||
typedef struct _VMBUS_CONNECTION {
|
||||
|
||||
VMBUS_CONNECT_STATE ConnectState;
|
||||
|
||||
UINT32 NextGpadlHandle;
|
||||
|
||||
// Represents channel interrupts. Each bit position
|
||||
// represents a channel.
|
||||
// When a channel sends an interrupt via VMBUS, it
|
||||
// finds its bit in the sendInterruptPage, set it and
|
||||
// calls Hv to generate a port event. The other end
|
||||
// receives the port event and parse the recvInterruptPage
|
||||
// to see which bit is set
|
||||
VOID* InterruptPage;
|
||||
VOID* SendInterruptPage;
|
||||
VOID* RecvInterruptPage;
|
||||
|
||||
// 2 pages - 1st page for parent->child notification and 2nd is child->parent notification
|
||||
VOID* MonitorPages;
|
||||
LIST_ENTRY ChannelMsgList;
|
||||
HANDLE ChannelMsgLock;
|
||||
|
||||
// List of channels
|
||||
LIST_ENTRY ChannelList;
|
||||
HANDLE ChannelLock;
|
||||
|
||||
HANDLE WorkQueue;
|
||||
} VMBUS_CONNECTION;
|
||||
|
||||
|
||||
typedef struct _VMBUS_MSGINFO {
|
||||
// Bookkeeping stuff
|
||||
LIST_ENTRY MsgListEntry;
|
||||
|
||||
// Synchronize the request/response if needed
|
||||
HANDLE WaitEvent;
|
||||
|
||||
// The message itself
|
||||
unsigned char Msg[0];
|
||||
} VMBUS_MSGINFO;
|
||||
|
||||
|
||||
//
|
||||
// Externs
|
||||
//
|
||||
extern VMBUS_CONNECTION gVmbusConnection;
|
||||
|
||||
//
|
||||
// General vmbus interface
|
||||
//
|
||||
INTERNAL DEVICE_OBJECT*
|
||||
VmbusChildDeviceCreate(
|
||||
GUID deviceType,
|
||||
GUID deviceInstance,
|
||||
void *context);
|
||||
|
||||
INTERNAL int
|
||||
VmbusChildDeviceAdd(
|
||||
DEVICE_OBJECT* Device);
|
||||
|
||||
INTERNAL void
|
||||
VmbusChildDeviceRemove(
|
||||
DEVICE_OBJECT* Device);
|
||||
|
||||
//INTERNAL void
|
||||
//VmbusChildDeviceDestroy(
|
||||
// DEVICE_OBJECT*);
|
||||
|
||||
INTERNAL VMBUS_CHANNEL*
|
||||
GetChannelFromRelId(
|
||||
UINT32 relId
|
||||
);
|
||||
|
||||
//
|
||||
// Connection interface
|
||||
//
|
||||
INTERNAL int
|
||||
VmbusConnect(
|
||||
VOID
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusDisconnect(
|
||||
VOID
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusPostMessage(
|
||||
PVOID buffer,
|
||||
SIZE_T bufSize
|
||||
);
|
||||
|
||||
INTERNAL int
|
||||
VmbusSetEvent(
|
||||
UINT32 childRelId
|
||||
);
|
||||
|
||||
INTERNAL VOID
|
||||
VmbusOnEvents(
|
||||
VOID
|
||||
);
|
||||
|
||||
|
||||
#endif // _VMBUS_PRIVATE_H_
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2009, Microsoft Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*
|
||||
* Authors:
|
||||
* Haiyang Zhang <haiyangz@microsoft.com>
|
||||
* Hank Janssen <hjanssen@microsoft.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/vmalloc.h>
|
||||
//#include <linux/config.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <asm/kmap_types.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
//
|
||||
// Data types
|
||||
//
|
||||
typedef struct _TIMER {
|
||||
struct timer_list timer;
|
||||
PFN_TIMER_CALLBACK callback;
|
||||
void* context;
|
||||
}TIMER;
|
||||
|
||||
|
||||
typedef struct _WAITEVENT {
|
||||
int condition;
|
||||
wait_queue_head_t event;
|
||||
} WAITEVENT;
|
||||
|
||||
typedef struct _SPINLOCK {
|
||||
spinlock_t lock;
|
||||
unsigned long flags;
|
||||
} SPINLOCK;
|
||||
|
||||
typedef struct _WORKQUEUE {
|
||||
struct workqueue_struct *queue;
|
||||
} WORKQUEUE;
|
||||
|
||||
typedef struct _WORKITEM {
|
||||
struct work_struct work;
|
||||
PFN_WORKITEM_CALLBACK callback;
|
||||
void* context;
|
||||
} WORKITEM;
|
||||
|
||||
|
||||
//
|
||||
// Global
|
||||
//
|
||||
|
||||
void LogMsg(const char *fmt, ...)
|
||||
{
|
||||
#ifdef KERNEL_2_6_5
|
||||
char buf[1024];
|
||||
#endif
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
#ifdef KERNEL_2_6_5
|
||||
vsnprintf(buf, 1024, fmt, args);
|
||||
va_end(args);
|
||||
printk(buf);
|
||||
#else
|
||||
vprintk(fmt, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BitSet(unsigned int* addr, int bit)
|
||||
{
|
||||
set_bit(bit, (unsigned long*)addr);
|
||||
}
|
||||
|
||||
int BitTest(unsigned int* addr, int bit)
|
||||
{
|
||||
return test_bit(bit, (unsigned long*)addr);
|
||||
}
|
||||
|
||||
void BitClear(unsigned int* addr, int bit)
|
||||
{
|
||||
clear_bit(bit, (unsigned long*)addr);
|
||||
}
|
||||
|
||||
int BitTestAndClear(unsigned int* addr, int bit)
|
||||
{
|
||||
return test_and_clear_bit(bit, (unsigned long*)addr);
|
||||
}
|
||||
|
||||
int BitTestAndSet(unsigned int* addr, int bit)
|
||||
{
|
||||
return test_and_set_bit(bit, (unsigned long*)addr);
|
||||
}
|
||||
|
||||
|
||||
int InterlockedIncrement(int *val)
|
||||
{
|
||||
#ifdef KERNEL_2_6_5
|
||||
int i;
|
||||
local_irq_disable();
|
||||
i = atomic_read((atomic_t*)val);
|
||||
atomic_set((atomic_t*)val, i+1);
|
||||
local_irq_enable();
|
||||
return i+1;
|
||||
#else
|
||||
return atomic_inc_return((atomic_t*)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
int InterlockedDecrement(int *val)
|
||||
{
|
||||
#ifdef KERNEL_2_6_5
|
||||
int i;
|
||||
local_irq_disable();
|
||||
i = atomic_read((atomic_t*)val);
|
||||
atomic_set((atomic_t*)val, i-1);
|
||||
local_irq_enable();
|
||||
return i-1;
|
||||
#else
|
||||
return atomic_dec_return((atomic_t*)val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef atomic_cmpxchg
|
||||
#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
|
||||
#endif
|
||||
int InterlockedCompareExchange(int *val, int new, int curr)
|
||||
{
|
||||
//return ((int)cmpxchg(((atomic_t*)val), curr, new));
|
||||
return atomic_cmpxchg((atomic_t*)val, curr, new);
|
||||
|
||||
}
|
||||
|
||||
void Sleep(unsigned long usecs)
|
||||
{
|
||||
udelay(usecs);
|
||||
}
|
||||
|
||||
void* VirtualAllocExec(unsigned int size)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL_EXEC);
|
||||
#else
|
||||
return __vmalloc(size, GFP_KERNEL, __pgprot(__PAGE_KERNEL & (~_PAGE_NX)));
|
||||
#endif
|
||||
}
|
||||
|
||||
void VirtualFree(void* VirtAddr)
|
||||
{
|
||||
return vfree(VirtAddr);
|
||||
}
|
||||
|
||||
void* PageAlloc(unsigned int count)
|
||||
{
|
||||
void *p;
|
||||
p = (void *)__get_free_pages(GFP_KERNEL, get_order(count * PAGE_SIZE));
|
||||
if (p) memset(p, 0, count * PAGE_SIZE);
|
||||
return p;
|
||||
|
||||
//struct page* page = alloc_page(GFP_KERNEL|__GFP_ZERO);
|
||||
//void *p;
|
||||
|
||||
////BUGBUG: We need to use kmap in case we are in HIMEM region
|
||||
//p = page_address(page);
|
||||
//if (p) memset(p, 0, PAGE_SIZE);
|
||||
//return p;
|
||||
}
|
||||
|
||||
void PageFree(void* page, unsigned int count)
|
||||
{
|
||||
free_pages((unsigned long)page, get_order(count * PAGE_SIZE));
|
||||
/*struct page* p = virt_to_page(page);
|
||||
__free_page(p);*/
|
||||
}
|
||||
|
||||
|
||||
void* PageMapVirtualAddress(unsigned long Pfn)
|
||||
{
|
||||
return kmap_atomic(pfn_to_page(Pfn), KM_IRQ0);
|
||||
}
|
||||
|
||||
void PageUnmapVirtualAddress(void* VirtAddr)
|
||||
{
|
||||
kunmap_atomic(VirtAddr, KM_IRQ0);
|
||||
}
|
||||
|
||||
void* MemAlloc(unsigned int size)
|
||||
{
|
||||
return kmalloc(size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void* MemAllocZeroed(unsigned int size)
|
||||
{
|
||||
void *p = kmalloc(size, GFP_KERNEL);
|
||||
if (p) memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* MemAllocAtomic(unsigned int size)
|
||||
{
|
||||
return kmalloc(size, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
void MemFree(void* buf)
|
||||
{
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
void *MemMapIO(unsigned long phys, unsigned long size)
|
||||
{
|
||||
#if X2V_LINUX
|
||||
#ifdef __x86_64__
|
||||
return (void*)(phys + 0xFFFF83000C000000);
|
||||
#else // i386
|
||||
return (void*)(phys + 0xfb000000);
|
||||
#endif
|
||||
#else
|
||||
return (void*)GetVirtualAddress(phys); //return ioremap_nocache(phys, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemUnmapIO(void *virt)
|
||||
{
|
||||
//iounmap(virt);
|
||||
}
|
||||
|
||||
void MemoryFence()
|
||||
{
|
||||
mb();
|
||||
}
|
||||
|
||||
void TimerCallback(unsigned long data)
|
||||
{
|
||||
TIMER* t = (TIMER*)data;
|
||||
|
||||
t->callback(t->context);
|
||||
}
|
||||
|
||||
HANDLE TimerCreate(PFN_TIMER_CALLBACK pfnTimerCB, void* context)
|
||||
{
|
||||
TIMER* t = kmalloc(sizeof(TIMER), GFP_KERNEL);
|
||||
if (!t)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t->callback = pfnTimerCB;
|
||||
t->context = context;
|
||||
|
||||
init_timer(&t->timer);
|
||||
t->timer.data = (unsigned long)t;
|
||||
t->timer.function = TimerCallback;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void TimerStart(HANDLE hTimer, UINT32 expirationInUs)
|
||||
{
|
||||
TIMER* t = (TIMER* )hTimer;
|
||||
|
||||
t->timer.expires = jiffies + usecs_to_jiffies(expirationInUs);
|
||||
add_timer(&t->timer);
|
||||
}
|
||||
|
||||
int TimerStop(HANDLE hTimer)
|
||||
{
|
||||
TIMER* t = (TIMER* )hTimer;
|
||||
|
||||
return del_timer(&t->timer);
|
||||
}
|
||||
|
||||
void TimerClose(HANDLE hTimer)
|
||||
{
|
||||
TIMER* t = (TIMER* )hTimer;
|
||||
|
||||
del_timer(&t->timer);
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
SIZE_T GetTickCount(void)
|
||||
{
|
||||
return jiffies;
|
||||
}
|
||||
|
||||
signed long long GetTimestamp(void)
|
||||
{
|
||||
struct timeval t;
|
||||
|
||||
do_gettimeofday(&t);
|
||||
|
||||
return timeval_to_ns(&t);
|
||||
}
|
||||
|
||||
HANDLE WaitEventCreate(void)
|
||||
{
|
||||
WAITEVENT* wait = kmalloc(sizeof(WAITEVENT), GFP_KERNEL);
|
||||
if (!wait)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wait->condition = 0;
|
||||
init_waitqueue_head(&wait->event);
|
||||
return wait;
|
||||
}
|
||||
|
||||
void WaitEventClose(HANDLE hWait)
|
||||
{
|
||||
WAITEVENT* waitEvent = (WAITEVENT* )hWait;
|
||||
kfree(waitEvent);
|
||||
}
|
||||
|
||||
void WaitEventSet(HANDLE hWait)
|
||||
{
|
||||
WAITEVENT* waitEvent = (WAITEVENT* )hWait;
|
||||
waitEvent->condition = 1;
|
||||
wake_up_interruptible(&waitEvent->event);
|
||||
}
|
||||
|
||||
int WaitEventWait(HANDLE hWait)
|
||||
{
|
||||
int ret=0;
|
||||
WAITEVENT* waitEvent = (WAITEVENT* )hWait;
|
||||
|
||||
ret= wait_event_interruptible(waitEvent->event,
|
||||
waitEvent->condition);
|
||||
waitEvent->condition = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WaitEventWaitEx(HANDLE hWait, UINT32 TimeoutInMs)
|
||||
{
|
||||
int ret=0;
|
||||
WAITEVENT* waitEvent = (WAITEVENT* )hWait;
|
||||
|
||||
ret= wait_event_interruptible_timeout(waitEvent->event,
|
||||
waitEvent->condition,
|
||||
msecs_to_jiffies(TimeoutInMs));
|
||||
waitEvent->condition = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
HANDLE SpinlockCreate(VOID)
|
||||
{
|
||||
SPINLOCK* spin = kmalloc(sizeof(SPINLOCK), GFP_KERNEL);
|
||||
if (!spin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
spin_lock_init(&spin->lock);
|
||||
|
||||
return spin;
|
||||
}
|
||||
|
||||
VOID SpinlockAcquire(HANDLE hSpin)
|
||||
{
|
||||
SPINLOCK* spin = (SPINLOCK* )hSpin;
|
||||
|
||||
spin_lock_irqsave(&spin->lock, spin->flags);
|
||||
}
|
||||
|
||||
VOID SpinlockRelease(HANDLE hSpin)
|
||||
{
|
||||
SPINLOCK* spin = (SPINLOCK* )hSpin;
|
||||
|
||||
spin_unlock_irqrestore(&spin->lock, spin->flags);
|
||||
}
|
||||
|
||||
VOID SpinlockClose(HANDLE hSpin)
|
||||
{
|
||||
SPINLOCK* spin = (SPINLOCK* )hSpin;
|
||||
kfree(spin);
|
||||
}
|
||||
|
||||
void* Physical2LogicalAddr(ULONG_PTR PhysAddr)
|
||||
{
|
||||
void* logicalAddr = phys_to_virt(PhysAddr);
|
||||
BUG_ON(!virt_addr_valid(logicalAddr));
|
||||
return logicalAddr;
|
||||
}
|
||||
|
||||
ULONG_PTR Logical2PhysicalAddr(PVOID LogicalAddr)
|
||||
{
|
||||
BUG_ON(!virt_addr_valid(LogicalAddr));
|
||||
return virt_to_phys(LogicalAddr);
|
||||
}
|
||||
|
||||
|
||||
ULONG_PTR Virtual2Physical(PVOID VirtAddr)
|
||||
{
|
||||
ULONG_PTR pfn = vmalloc_to_pfn(VirtAddr);
|
||||
|
||||
return pfn << PAGE_SHIFT;
|
||||
}
|
||||
|
||||
#ifdef KERNEL_2_6_27
|
||||
void WorkItemCallback(struct work_struct *work)
|
||||
#else
|
||||
void WorkItemCallback(void* work)
|
||||
#endif
|
||||
{
|
||||
WORKITEM* w = (WORKITEM*)work;
|
||||
|
||||
w->callback(w->context);
|
||||
|
||||
kfree(w);
|
||||
}
|
||||
|
||||
HANDLE WorkQueueCreate(char* name)
|
||||
{
|
||||
WORKQUEUE *wq = kmalloc(sizeof(WORKQUEUE), GFP_KERNEL);
|
||||
if (!wq)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
wq->queue = create_workqueue(name);
|
||||
|
||||
return wq;
|
||||
}
|
||||
|
||||
void WorkQueueClose(HANDLE hWorkQueue)
|
||||
{
|
||||
WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
|
||||
|
||||
destroy_workqueue(wq->queue);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int WorkQueueQueueWorkItem(HANDLE hWorkQueue, PFN_WORKITEM_CALLBACK workItem, void* context)
|
||||
{
|
||||
WORKQUEUE *wq = (WORKQUEUE *)hWorkQueue;
|
||||
|
||||
WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
|
||||
if (!w)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
w->callback = workItem,
|
||||
w->context = context;
|
||||
#ifdef KERNEL_2_6_27
|
||||
INIT_WORK(&w->work, WorkItemCallback);
|
||||
#else
|
||||
INIT_WORK(&w->work, WorkItemCallback, w);
|
||||
#endif
|
||||
return queue_work(wq->queue, &w->work);
|
||||
}
|
||||
|
||||
void QueueWorkItem(PFN_WORKITEM_CALLBACK workItem, void* context)
|
||||
{
|
||||
WORKITEM* w = kmalloc(sizeof(WORKITEM), GFP_ATOMIC);
|
||||
if (!w)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
w->callback = workItem,
|
||||
w->context = context;
|
||||
#ifdef KERNEL_2_6_27
|
||||
INIT_WORK(&w->work, WorkItemCallback);
|
||||
#else
|
||||
INIT_WORK(&w->work, WorkItemCallback, w);
|
||||
#endif
|
||||
schedule_work(&w->work);
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче