Commit 3e7ee490 authored by Hank Janssen's avatar Hank Janssen Committed by Greg Kroah-Hartman

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: default avatarHank Janssen <hjanssen@microsoft.com>
Signed-off-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ab057781
This diff is collapsed.
/*
*
* 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_
/*
*
* 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;
}
}
/*
*
* 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_
This diff is collapsed.
/*
*
* 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_
/*
*
* 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
This diff is collapsed.
/*
*
* 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__
This diff is collapsed.
/*
*
* 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_
/*
*
* 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"
/*
*
* 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";
This diff is collapsed.
/*
*
* 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_
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment