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);
|
||||||
|
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче