diff --git a/headers/private/hyperv/hyperv.h b/headers/private/hyperv/hyperv.h index 04738ed686..60c27b3ace 100644 --- a/headers/private/hyperv/hyperv.h +++ b/headers/private/hyperv/hyperv.h @@ -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; diff --git a/headers/private/hyperv/hyperv_spec.h b/headers/private/hyperv/hyperv_spec.h index 8a6a1fca91..ea0ebe2fc2 100644 --- a/headers/private/hyperv/hyperv_spec.h +++ b/headers/private/hyperv/hyperv_spec.h @@ -9,11 +9,14 @@ #include -#define HV_PAGE_SIZE 4096 -#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_MS_TO_US(x) ((x) * 1000ULL) +#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_ diff --git a/src/add-ons/kernel/bus_managers/hyperv/VMBus.cpp b/src/add-ons/kernel/bus_managers/hyperv/VMBus.cpp index 56d56f5017..e8e7cd79dd 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/VMBus.cpp +++ b/src/add-ons/kernel/bus_managers/hyperv/VMBus.cpp @@ -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 } }; diff --git a/src/add-ons/kernel/bus_managers/hyperv/VMBusDevice.cpp b/src/add-ons/kernel/bus_managers/hyperv/VMBusDevice.cpp index 901c37851d..78935118f3 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/VMBusDevice.cpp +++ b/src/add-ons/kernel/bus_managers/hyperv/VMBusDevice.cpp @@ -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(headerLength >> VMBUS_PKT_SIZE_SHIFT); + gpa.header.total_length = static_cast(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) { diff --git a/src/add-ons/kernel/bus_managers/hyperv/VMBusDeviceModule.cpp b/src/add-ons/kernel/bus_managers/hyperv/VMBusDeviceModule.cpp index b644bcf4cb..090dae0d4e 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/VMBusDeviceModule.cpp +++ b/src/add-ons/kernel/bus_managers/hyperv/VMBusDeviceModule.cpp @@ -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(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(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(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(cookie); + return device->AllocateGPADL(length, _buffer, _gpadl); +} + + +static status_t +vmbus_device_free_gpadl(hyperv_device cookie, uint32 gpadl) +{ + VMBusDevice* device = reinterpret_cast(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 }; diff --git a/src/add-ons/kernel/bus_managers/hyperv/VMBusDevicePrivate.h b/src/add-ons/kernel/bus_managers/hyperv/VMBusDevicePrivate.h index 96e8c3ad0c..a15835a56e 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/VMBusDevicePrivate.h +++ b/src/add-ons/kernel/bus_managers/hyperv/VMBusDevicePrivate.h @@ -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); diff --git a/src/add-ons/kernel/bus_managers/hyperv/VMBusPrivate.h b/src/add-ons/kernel/bus_managers/hyperv/VMBusPrivate.h index c511a6b221..b87197b0a9 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/VMBusPrivate.h +++ b/src/add-ons/kernel/bus_managers/hyperv/VMBusPrivate.h @@ -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); diff --git a/src/add-ons/kernel/bus_managers/hyperv/hyperv_spec_private.h b/src/add-ons/kernel/bus_managers/hyperv/hyperv_spec_private.h index 72cddbdfb6..70e7b9c2ef 100644 --- a/src/add-ons/kernel/bus_managers/hyperv/hyperv_spec_private.h +++ b/src/add-ons/kernel/bus_managers/hyperv/hyperv_spec_private.h @@ -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; @@ -321,11 +313,11 @@ typedef struct { typedef struct { vmbus_msg_header header; - uint32 channel_id; - uint32 gpadl_id; - uint16 total_range_length; - uint16 range_count; - vmbus_gpadl_range ranges[1]; // Only 1 range is supported by this driver + uint32 channel_id; + uint32 gpadl_id; + uint16 total_range_length; + uint16 range_count; + 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))