hyperv: Implement additional driver functions
* Switch instance ID from string to raw attribute * Implement device allocate/free GPADL functions * Add definitions and functions for additional VMBus packet types Change-Id: I01e9a30f567358fad520df95b1c14b7ea9671915 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10402 Reviewed-by: Jérôme Duval <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
|
||||
// Device attributes for the VMBus device
|
||||
#define HYPERV_CHANNEL_ID_ITEM "hyperv/channel"
|
||||
#define HYPERV_DEVICE_TYPE_ITEM "hyperv/type"
|
||||
#define HYPERV_DEVICE_TYPE_ITEM "hyperv/type_string"
|
||||
#define HYPERV_INSTANCE_ID_ITEM "hyperv/instance"
|
||||
|
||||
#define HYPERV_PRETTYNAME_VMBUS "Hyper-V Virtual Machine Bus"
|
||||
@@ -53,10 +53,16 @@ typedef struct hyperv_device_interface {
|
||||
status_t (*open)(hyperv_device cookie, uint32 txLength, uint32 rxLength,
|
||||
hyperv_device_callback callback, void* callbackData);
|
||||
void (*close)(hyperv_device cookie);
|
||||
status_t (*write_packet)(hyperv_device cookie, uint16 type, void* buffer,
|
||||
uint32 length, bool responseRequired, uint64 transactionID);
|
||||
status_t (*read_packet)(hyperv_device cookie, vmbus_pkt_header* _header,
|
||||
uint32* _headerLength, void* _buffer, uint32* _length);
|
||||
status_t (*write_packet)(hyperv_device cookie, uint16 type, const void* buffer,
|
||||
uint32 length, bool responseRequired, uint64 transactionID);
|
||||
status_t (*write_gpa_packet)(hyperv_device cookie, uint32 rangeCount,
|
||||
const vmbus_gpa_range* rangesList, uint32 rangesLength, const void* buffer,
|
||||
uint32 length, bool responseRequired, uint64 transactionID);
|
||||
status_t (*allocate_gpadl)(hyperv_device cookie, uint32 length, void** _buffer,
|
||||
uint32* _gpadl);
|
||||
status_t (*free_gpadl)(hyperv_device cookie, uint32 gpadl);
|
||||
} hyperv_device_interface;
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
|
||||
|
||||
#define HV_PAGE_SIZE 4096
|
||||
#define HV_PAGE_MASK (HV_PAGE_SIZE - 1)
|
||||
#define HV_PAGE_SHIFT 12
|
||||
#define HV_PAGE_ALIGN(x) (((x) + (HV_PAGE_SIZE - 1)) & ~(HV_PAGE_SIZE - 1))
|
||||
#define HV_BYTES_TO_PAGES(x) (HV_PAGE_ALIGN(x) >> HV_PAGE_SHIFT)
|
||||
#define HV_BYTES_TO_SPAN_PAGES(a, l) ((((l) - 1) >> HV_PAGE_SHIFT) \
|
||||
+ (((((l) - 1) & HV_PAGE_MASK) + ((a) & HV_PAGE_MASK)) >> HV_PAGE_SHIFT) + 1);
|
||||
#define HV_MS_TO_US(x) ((x) * 1000ULL)
|
||||
|
||||
#define HV_STATIC_ASSERT(cond, msg) static_assert(cond, msg)
|
||||
@@ -56,6 +59,14 @@
|
||||
#define VMBUS_TYPE_VSS "35fa2e29-ea23-4236-96ae-3a6ebacba440"
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32 data1;
|
||||
uint16 data2;
|
||||
uint16 data3;
|
||||
uint8 data4[8];
|
||||
} _PACKED vmbus_guid_t;
|
||||
|
||||
|
||||
// VMBus packet types
|
||||
enum {
|
||||
VMBUS_PKTTYPE_INVALID = 0,
|
||||
@@ -89,7 +100,47 @@ typedef struct {
|
||||
uint16 total_length;
|
||||
uint16 flags;
|
||||
uint64 transaction_id;
|
||||
} vmbus_pkt_header;
|
||||
} _PACKED vmbus_pkt_header;
|
||||
|
||||
|
||||
// VMBus transfer range
|
||||
// Describes a buffer within an existing defined buffer
|
||||
typedef struct {
|
||||
uint32 length;
|
||||
uint32 offset;
|
||||
} _PACKED vmbus_transfer_range;
|
||||
|
||||
|
||||
// VMBus transfer ranges packet header
|
||||
typedef struct {
|
||||
vmbus_pkt_header header;
|
||||
|
||||
uint16 transfer_pageset_id;
|
||||
uint8 sender_owns_sets;
|
||||
uint8 reserved;
|
||||
|
||||
uint32 range_count;
|
||||
vmbus_transfer_range ranges[];
|
||||
} _PACKED vmbus_pkt_transfer_header;
|
||||
|
||||
|
||||
// VMBus GPA (Guest Physical Address) range
|
||||
// Describes a buffer made up of one or more physical pages in the guest
|
||||
typedef struct {
|
||||
uint32 length;
|
||||
uint32 offset;
|
||||
uint64 page_nums[];
|
||||
} _PACKED vmbus_gpa_range;
|
||||
|
||||
|
||||
// VMBus GPA packet header
|
||||
typedef struct {
|
||||
vmbus_pkt_header header;
|
||||
|
||||
uint32 reserved;
|
||||
uint32 range_count;
|
||||
vmbus_gpa_range ranges[];
|
||||
} _PACKED vmbus_pkt_gpa_header;
|
||||
|
||||
|
||||
#endif // _HYPERV_SPEC_H_
|
||||
|
||||
@@ -1070,13 +1070,14 @@ status_t
|
||||
VMBus::_RegisterChannel(VMBusChannel* channel)
|
||||
{
|
||||
char typeStr[37];
|
||||
char instanceStr[37];
|
||||
|
||||
snprintf(typeStr, sizeof(typeStr), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
channel->type_id.data1, channel->type_id.data2, channel->type_id.data3,
|
||||
channel->type_id.data4[0], channel->type_id.data4[1], channel->type_id.data4[2],
|
||||
channel->type_id.data4[3], channel->type_id.data4[4], channel->type_id.data4[5],
|
||||
channel->type_id.data4[6], channel->type_id.data4[7]);
|
||||
|
||||
#ifdef TRACE_VMBUS
|
||||
char instanceStr[37];
|
||||
snprintf(instanceStr, sizeof(instanceStr),
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
channel->instance_id.data1, channel->instance_id.data2, channel->instance_id.data3,
|
||||
@@ -1086,6 +1087,7 @@ VMBus::_RegisterChannel(VMBusChannel* channel)
|
||||
channel->instance_id.data4[6], channel->instance_id.data4[7]);
|
||||
TRACE("Registering VMBus channel %u type %s inst %s\n", channel->channel_id, typeStr,
|
||||
instanceStr);
|
||||
#endif
|
||||
|
||||
char prettyName[sizeof(HYPERV_PRETTYNAME_VMBUS_DEVICE_FMT) + 8];
|
||||
snprintf(prettyName, sizeof(prettyName), HYPERV_PRETTYNAME_VMBUS_DEVICE_FMT,
|
||||
@@ -1100,8 +1102,8 @@ VMBus::_RegisterChannel(VMBusChannel* channel)
|
||||
{ .ui32 = channel->channel_id }},
|
||||
{ HYPERV_DEVICE_TYPE_ITEM, B_STRING_TYPE,
|
||||
{ .string = typeStr }},
|
||||
{ HYPERV_INSTANCE_ID_ITEM, B_STRING_TYPE,
|
||||
{ .string = instanceStr }},
|
||||
{ HYPERV_INSTANCE_ID_ITEM, B_RAW_TYPE,
|
||||
{ .raw = { .data = &channel->instance_id, .length = sizeof(channel->instance_id) }}},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -81,8 +81,7 @@ VMBusDevice::Open(uint32 txLength, uint32 rxLength, hyperv_device_callback callb
|
||||
TRACE("Open channel %u tx length 0x%X rx length 0x%X\n", fChannelID, txLength, rxLength);
|
||||
|
||||
// Create the GPADL used for the ring buffers
|
||||
status_t status = fVMBus->allocate_gpadl(fVMBusCookie, fChannelID, fRingBufferLength,
|
||||
&fRingBuffer, &fRingGPADL);
|
||||
status_t status = AllocateGPADL(fRingBufferLength, &fRingBuffer, &fRingGPADL);
|
||||
if (status != B_OK) {
|
||||
ERROR("Failed to allocate GPADL while opening channel %u (%s)\n", fChannelID,
|
||||
strerror(status));
|
||||
@@ -133,7 +132,7 @@ VMBusDevice::Close()
|
||||
if (status != B_OK)
|
||||
ERROR("Failed to close channel %u (%s)\n", fChannelID, strerror(status));
|
||||
|
||||
status = fVMBus->free_gpadl(fVMBusCookie, fChannelID, fRingGPADL);
|
||||
status = FreeGPADL(fRingGPADL);
|
||||
if (status != B_OK)
|
||||
ERROR("Failed to free ring GPADL for channel %u (%s)\n", fChannelID, strerror(status));
|
||||
|
||||
@@ -148,8 +147,8 @@ status_t
|
||||
VMBusDevice::WritePacket(uint16 type, const void* buffer, uint32 length, bool responseRequired,
|
||||
uint64 transactionID)
|
||||
{
|
||||
TRACE_TX("Channel %u TX pkt %u len 0x%X resp %u tran %lu\n", fChannelID, type, length,
|
||||
responseRequired, transactionID);
|
||||
TRACE_TX("Channel %u TX pkt %u len 0x%X resp %u tran %" B_PRIu64 "\n", fChannelID, type,
|
||||
length, responseRequired, transactionID);
|
||||
|
||||
vmbus_pkt_header header;
|
||||
uint32 totalLength = sizeof(header) + length;
|
||||
@@ -161,16 +160,53 @@ VMBusDevice::WritePacket(uint16 type, const void* buffer, uint32 length, bool re
|
||||
header.flags = responseRequired ? VMBUS_PKT_FLAGS_RESPONSE_REQUIRED : 0;
|
||||
header.transaction_id = transactionID;
|
||||
|
||||
iovec pkt[3];
|
||||
iovec data[3];
|
||||
uint64 padding = 0;
|
||||
pkt[0].iov_base = &header;
|
||||
pkt[0].iov_len = sizeof(header);
|
||||
pkt[1].iov_base = (void*)buffer;
|
||||
pkt[1].iov_len = length;
|
||||
pkt[2].iov_base = &padding;
|
||||
pkt[2].iov_len = totalLengthAligned - totalLength;
|
||||
data[0].iov_base = &header;
|
||||
data[0].iov_len = sizeof(header);
|
||||
data[1].iov_base = (void*)buffer;
|
||||
data[1].iov_len = length;
|
||||
data[2].iov_base = &padding;
|
||||
data[2].iov_len = totalLengthAligned - totalLength;
|
||||
|
||||
return _WriteTXData(pkt, 3);
|
||||
return _WriteTXData(data, 3);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMBusDevice::WriteGPAPacket(uint32 rangeCount, const vmbus_gpa_range* rangesList,
|
||||
uint32 rangesLength, const void* buffer, uint32 length, bool responseRequired,
|
||||
uint64 transactionID)
|
||||
{
|
||||
TRACE_TX("Channel %u TX gpa pkt cnt %u gpa len 0x%X len 0x%X resp %u tran %" B_PRIu64 "\n",
|
||||
fChannelID, rangeCount, rangesLength, length, responseRequired, transactionID);
|
||||
|
||||
vmbus_pkt_gpa_header gpa;
|
||||
uint32 headerLength = sizeof(gpa) + rangesLength;
|
||||
uint32 totalLength = headerLength + length;
|
||||
uint32 totalLengthAligned = VMBUS_PKT_ALIGN(totalLength);
|
||||
|
||||
gpa.header.type = VMBUS_PKTTYPE_DATA_USING_GPA_DIRECT;
|
||||
gpa.header.header_length = static_cast<uint16>(headerLength >> VMBUS_PKT_SIZE_SHIFT);
|
||||
gpa.header.total_length = static_cast<uint16>(totalLengthAligned >> VMBUS_PKT_SIZE_SHIFT);
|
||||
gpa.header.flags = responseRequired ? VMBUS_PKT_FLAGS_RESPONSE_REQUIRED : 0;
|
||||
gpa.header.transaction_id = transactionID;
|
||||
|
||||
gpa.reserved = 0;
|
||||
gpa.range_count = rangeCount;
|
||||
|
||||
iovec data[4];
|
||||
uint64 padding = 0;
|
||||
data[0].iov_base = &gpa;
|
||||
data[0].iov_len = sizeof(gpa);
|
||||
data[1].iov_base = (void*)rangesList;
|
||||
data[1].iov_len = rangesLength;
|
||||
data[2].iov_base = (void*)buffer;
|
||||
data[2].iov_len = length;
|
||||
data[3].iov_base = &padding;
|
||||
data[3].iov_len = totalLengthAligned - totalLength;
|
||||
|
||||
return _WriteTXData(data, 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +299,20 @@ VMBusDevice::ReadPacket(vmbus_pkt_header* _header, uint32* _headerLength, void*
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMBusDevice::AllocateGPADL(uint32 length, void** _buffer, uint32* _gpadl)
|
||||
{
|
||||
return fVMBus->allocate_gpadl(fVMBusCookie, fChannelID, length, _buffer, _gpadl);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMBusDevice::FreeGPADL(uint32 gpadl)
|
||||
{
|
||||
return fVMBus->free_gpadl(fVMBusCookie, fChannelID, gpadl);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
VMBusDevice::_CallbackHandler(void* arg)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,16 @@ vmbus_device_close(hyperv_device cookie)
|
||||
|
||||
|
||||
static status_t
|
||||
vmbus_device_write_packet(hyperv_device cookie, uint16 type, void* buffer, uint32 length,
|
||||
vmbus_device_read_packet(hyperv_device cookie, vmbus_pkt_header* _header, uint32* _headerLength,
|
||||
void* _buffer, uint32* _length)
|
||||
{
|
||||
VMBusDevice* device = reinterpret_cast<VMBusDevice*>(cookie);
|
||||
return device->ReadPacket(_header, _headerLength, _buffer, _length);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
vmbus_device_write_packet(hyperv_device cookie, uint16 type, const void* buffer, uint32 length,
|
||||
bool responseRequired, uint64 transactionID)
|
||||
{
|
||||
VMBusDevice* device = reinterpret_cast<VMBusDevice*>(cookie);
|
||||
@@ -85,11 +94,29 @@ vmbus_device_write_packet(hyperv_device cookie, uint16 type, void* buffer, uint3
|
||||
|
||||
|
||||
static status_t
|
||||
vmbus_device_read_packet(hyperv_device cookie, vmbus_pkt_header* _header, uint32* _headerLength,
|
||||
void* _buffer, uint32* _length)
|
||||
vmbus_device_write_gpa_packet(hyperv_device cookie, uint32 rangeCount,
|
||||
const vmbus_gpa_range* rangesList, uint32 rangesLength, const void* buffer, uint32 length,
|
||||
bool responseRequired, uint64 transactionID)
|
||||
{
|
||||
VMBusDevice* device = reinterpret_cast<VMBusDevice*>(cookie);
|
||||
return device->ReadPacket(_header, _headerLength, _buffer, _length);
|
||||
return device->WriteGPAPacket(rangeCount, rangesList, rangesLength, buffer, length,
|
||||
responseRequired, transactionID);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
vmbus_device_allocate_gpadl(hyperv_device cookie, uint32 length, void** _buffer, uint32* _gpadl)
|
||||
{
|
||||
VMBusDevice* device = reinterpret_cast<VMBusDevice*>(cookie);
|
||||
return device->AllocateGPADL(length, _buffer, _gpadl);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
vmbus_device_free_gpadl(hyperv_device cookie, uint32 gpadl)
|
||||
{
|
||||
VMBusDevice* device = reinterpret_cast<VMBusDevice*>(cookie);
|
||||
return device->FreeGPADL(gpadl);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +155,9 @@ hyperv_device_interface gVMBusDeviceModule = {
|
||||
vmbus_device_get_bus_version,
|
||||
vmbus_device_open,
|
||||
vmbus_device_close,
|
||||
vmbus_device_read_packet,
|
||||
vmbus_device_write_packet,
|
||||
vmbus_device_read_packet
|
||||
vmbus_device_write_gpa_packet,
|
||||
vmbus_device_allocate_gpadl,
|
||||
vmbus_device_free_gpadl
|
||||
};
|
||||
|
||||
@@ -50,12 +50,20 @@ public:
|
||||
status_t Open(uint32 txLength, uint32 rxLength,
|
||||
hyperv_device_callback callback, void* callbackData);
|
||||
void Close();
|
||||
|
||||
status_t WritePacket(uint16 type, const void* buffer, uint32 length,
|
||||
bool responseRequired, uint64 transactionID);
|
||||
status_t WriteGPAPacket(uint32 rangeCount,
|
||||
const vmbus_gpa_range* rangesList, uint32 rangesLength,
|
||||
const void* buffer, uint32 length, bool responseRequired,
|
||||
uint64 transactionID);
|
||||
status_t PeekPacket(void* _buffer, uint32 length);
|
||||
status_t ReadPacket(vmbus_pkt_header* _header, uint32* _headerLength,
|
||||
void* _buffer, uint32* _length);
|
||||
|
||||
status_t AllocateGPADL(uint32 length, void** _buffer, uint32* _gpadl);
|
||||
status_t FreeGPADL(uint32 gpadl);
|
||||
|
||||
private:
|
||||
static void _CallbackHandler(void* arg);
|
||||
static void _DPCHandler(void* arg);
|
||||
|
||||
@@ -116,6 +116,7 @@ public:
|
||||
|
||||
uint32 GetVersion() const { return fVersion; }
|
||||
status_t RequestChannels();
|
||||
|
||||
status_t OpenChannel(uint32 channelID, uint32 gpadlID, uint32 rxOffset,
|
||||
hyperv_bus_callback callback, void* callbackData);
|
||||
status_t CloseChannel(uint32 channelID);
|
||||
|
||||
@@ -167,14 +167,6 @@ static const uint32 vmbus_versions[] = {
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32 data1;
|
||||
uint16 data2;
|
||||
uint16 data3;
|
||||
uint8 data4[8];
|
||||
} _PACKED vmbus_guid_t;
|
||||
|
||||
|
||||
// VMBus GPADL range descriptor
|
||||
typedef struct {
|
||||
uint32 length;
|
||||
@@ -325,7 +317,7 @@ typedef struct {
|
||||
uint32 gpadl_id;
|
||||
uint16 total_range_length;
|
||||
uint16 range_count;
|
||||
vmbus_gpadl_range ranges[1]; // Only 1 range is supported by this driver
|
||||
vmbus_gpa_range ranges[1]; // Only 1 range is supported by this driver
|
||||
} _PACKED vmbus_msg_create_gpadl;
|
||||
#define VMBUS_MSG_CREATE_GPADL_MAX_PAGES \
|
||||
((HYPERCALL_MAX_DATA_SIZE - sizeof(vmbus_msg_create_gpadl)) / sizeof(uint64))
|
||||
|
||||
Reference in New Issue
Block a user