Skip to content

Commit 6d9f5f3

Browse files
committed
Shutdown: Fix hvshutdownd daemon
1 parent 9ab26c3 commit 6d9f5f3

File tree

4 files changed

+93
-43
lines changed

4 files changed

+93
-43
lines changed

MacHyperVSupport/IntegrationComponents/Shutdown/HyperVShutdownUserClient.cpp

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,54 @@
1010
OSDefineMetaClassAndStructors(HyperVShutdownUserClient, super);
1111

1212
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_5
13-
const IOExternalMethodDispatch HyperVShutdownUserClient::sShutdownMethods[kHyperVShutdownUserClientMethodNumberOfMethods] = {
14-
{ // kHyperVShutdownUserClientMethodReportShutdownAbility
15-
reinterpret_cast<IOExternalMethodAction>(&HyperVShutdownUserClient::methodReportShutdownAbility), // Method pointer
16-
1, // Num of scalar input values
17-
0, // Size of struct input
18-
0, // Num of scalar output values
19-
0 // Size of struct output
13+
IOReturn HyperVShutdownUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments *arguments, IOExternalMethodDispatch *dispatch,
14+
OSObject *target, void *reference) {
15+
static const IOExternalMethodDispatch methods[kHyperVShutdownUserClientMethodNumberOfMethods] = {
16+
{ // kHyperVShutdownUserClientMethodReportShutdownAbility
17+
reinterpret_cast<IOExternalMethodAction>(&HyperVShutdownUserClient::sMethodReportShutdownAbility), // Method pointer
18+
1, // Num of scalar input values
19+
0, // Size of struct input
20+
0, // Num of scalar output values
21+
0 // Size of struct output
22+
}
23+
};
24+
25+
if (selector >= kHyperVShutdownUserClientMethodNumberOfMethods) {
26+
return kIOReturnUnsupported;
2027
}
21-
};
28+
dispatch = const_cast<IOExternalMethodDispatch*>(&methods[selector]);
2229

23-
/*IOExternalMethod* HyperVShutdownUserClient::getTargetAndMethodForIndex(IOService **targetP, UInt32 index) {
24-
static IOExternalMethod sMethods[kHyperVShutdownUserClientMethodNumberOfMethods] = {
25-
{ // kHyperVShutdownUserClientMethodReportShutdownAbility, 0
26-
0, (IOMethod)&HyperVShutdownUserClient::reportShutdownAbility, kIOUCScalarIScalarO, 1, 0
27-
},
30+
target = this;
31+
reference = nullptr;
32+
33+
return super::externalMethod(selector, arguments, dispatch, target, reference);
34+
}
35+
36+
#else
37+
IOExternalMethod* HyperVShutdownUserClient::getTargetAndMethodForIndex(IOService **target, UInt32 index) {
38+
static const IOExternalMethod methods[kHyperVShutdownUserClientMethodNumberOfMethods] = {
39+
{ // kHyperVShutdownUserClientMethodReportShutdownAbility
40+
NULL,
41+
#if (defined(__i386__) && defined(__clang__))
42+
// Required to match GCC behavior on 32-bit when building with clang
43+
kIOExternalMethodACID32Padding,
44+
(IOMethodACID32) &HyperVShutdownUserClient::reportShutdownAbility,
45+
#else
46+
(IOMethod) &HyperVShutdownUserClient::reportShutdownAbility,
47+
#endif
48+
kIOUCScalarIScalarO,
49+
1,
50+
0
51+
}
2852
};
2953

3054
if (index >= kHyperVShutdownUserClientMethodNumberOfMethods) {
3155
return nullptr;
32-
} else {
33-
*targetP = this;
34-
return &sMethods[index];
3556
}
36-
}*/
3757

58+
*target = this;
59+
return (IOExternalMethod *) &methods[index];
60+
}
3861
#endif
3962

4063
bool HyperVShutdownUserClient::start(IOService *provider) {
@@ -55,22 +78,6 @@ void HyperVShutdownUserClient::stop(IOService *provider) {
5578
super::stop(provider);
5679
}
5780

58-
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_5
59-
IOReturn HyperVShutdownUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments *arguments, IOExternalMethodDispatch *dispatch,
60-
OSObject *target, void *reference) {
61-
if (selector >= kHyperVShutdownUserClientMethodNumberOfMethods) {
62-
return kIOReturnUnsupported;
63-
}
64-
dispatch = const_cast<IOExternalMethodDispatch*>(&sShutdownMethods[selector]);
65-
66-
target = this;
67-
reference = nullptr;
68-
69-
return super::externalMethod(selector, arguments, dispatch, target, reference);
70-
}
71-
#else
72-
#endif
73-
7481
IOReturn HyperVShutdownUserClient::notifyClientApplication(HyperVShutdownUserClientNotificationType type) {
7582
HyperVShutdownUserClientNotificationMessage notificationMsg = { };
7683

@@ -80,27 +87,39 @@ IOReturn HyperVShutdownUserClient::notifyClientApplication(HyperVShutdownUserCli
8087
}
8188

8289
HVDBGLOG("Sending shutdown notification type %u", type);
83-
8490
notificationMsg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
8591
notificationMsg.header.msgh_size = sizeof (notificationMsg);
8692
notificationMsg.header.msgh_remote_port = _notificationPort;
8793
notificationMsg.header.msgh_local_port = MACH_PORT_NULL;
8894
notificationMsg.header.msgh_reserved = 0;
8995
notificationMsg.header.msgh_id = 0;
90-
91-
notificationMsg.type = type;
96+
notificationMsg.type = type;
9297

9398
return mach_msg_send_from_kernel(&notificationMsg.header, notificationMsg.header.msgh_size);
9499
}
95100

96-
IOReturn HyperVShutdownUserClient::methodReportShutdownAbility(HyperVShutdownUserClient *target, void *ref, IOExternalMethodArguments *args) {
97-
target->wakeThread(static_cast<bool>(args->scalarInput[0]) ? kIOReturnSuccess : kIOReturnUnsupported);
101+
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_5
102+
IOReturn HyperVShutdownUserClient::sMethodReportShutdownAbility(HyperVShutdownUserClient *target, void *ref, IOExternalMethodArguments *args) {
103+
return target->reportShutdownAbility((UInt32)args->scalarInput[0]);
104+
}
105+
#endif
106+
107+
#if (defined(__i386__) && defined(__clang__))
108+
IOReturn HyperVShutdownUserClient::reportShutdownAbility(HyperVShutdownUserClient* that, UInt32 arg) {
109+
that->wakeThread((arg == kHyperVShutdownMagic) ? kIOReturnSuccess : kIOReturnUnsupported);
110+
#else
111+
IOReturn HyperVShutdownUserClient::reportShutdownAbility(UInt32 arg) {
112+
wakeThread((arg == kHyperVShutdownMagic) ? kIOReturnSuccess : kIOReturnUnsupported);
113+
#endif
98114
return kIOReturnSuccess;
99115
}
100116

101117
bool HyperVShutdownUserClient::canShutdown() {
102118
IOReturn status;
103119

120+
//
121+
// Check if userspace daemon is running and responsive.
122+
//
104123
_isSleeping = true;
105124
status = notifyClientApplication(kHyperVShutdownUserClientNotificationTypeCheck);
106125
if (status != kIOReturnSuccess) {

MacHyperVSupport/IntegrationComponents/Shutdown/HyperVShutdownUserClient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <libkern/OSTypes.h>
1212
#include <mach/message.h>
1313

14+
#define kHyperVShutdownMagic 0x66697368
15+
1416
typedef enum : UInt32 {
1517
kHyperVShutdownUserClientMethodReportShutdownAbility,
1618

MacHyperVSupport/IntegrationComponents/Shutdown/HyperVShutdownUserClientInternal.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ class HyperVShutdownUserClient : public HyperVICUserClient {
2727
//
2828
// Userspace external methods.
2929
//
30-
static IOReturn methodReportShutdownAbility(HyperVShutdownUserClient *target, void *ref, IOExternalMethodArguments *args);
30+
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_5
31+
static IOReturn sMethodReportShutdownAbility(HyperVShutdownUserClient *target, void *ref, IOExternalMethodArguments *args);
32+
#endif
33+
#if (defined(__i386__) && defined(__clang__))
34+
static IOReturn reportShutdownAbility(HyperVShutdownUserClient* that, UInt32 arg);
35+
#else
36+
IOReturn reportShutdownAbility(UInt32 arg);
37+
#endif
3138

3239
public:
3340
//
@@ -43,6 +50,8 @@ class HyperVShutdownUserClient : public HyperVICUserClient {
4350
IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments *arguments,
4451
IOExternalMethodDispatch *dispatch, OSObject *target,
4552
void *reference) APPLE_KEXT_OVERRIDE;
53+
#else
54+
IOExternalMethod *getTargetAndMethodForIndex(IOService **target, UInt32 index) APPLE_KEXT_OVERRIDE;
4655
#endif
4756

4857
bool canShutdown();

Tools/hvshutdownd/hvshutdownd.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,26 @@
1414

1515
HVDeclareLogFunctionsUser("hvshutdownd");
1616

17-
static void hvShutdownDoShutdown(bool restart) {
17+
void hvShutdownDoShutdownCheck(io_connect_t connection) {
18+
#if !defined(__x86_64__)
19+
if (IOConnectCallScalarMethod != NULL) {
20+
#endif
21+
//
22+
// Call into user client with standard API.
23+
//
24+
UInt64 input64 = kHyperVShutdownMagic;
25+
IOConnectCallScalarMethod(connection, kHyperVShutdownUserClientMethodReportShutdownAbility, &input64, 1, NULL, NULL);
26+
#if !defined(__x86_64__)
27+
} else {
28+
//
29+
// Call into user client with legacy API.
30+
//
31+
IOConnectMethodScalarIScalarO(connection, kHyperVShutdownUserClientMethodReportShutdownAbility, 1, 0, kHyperVShutdownMagic);
32+
}
33+
#endif
34+
}
35+
36+
void hvShutdownDoShutdown(bool restart) {
1837
HVSYSLOG(stdout, "Shutdown request received, performing shutdown (restart %u)", restart);
1938

2039
//
@@ -39,7 +58,6 @@ static void hvShutdownDoShutdown(bool restart) {
3958

4059
void hvIOKitNotificationHandler(io_connect_t connection, CFMachPortRef port, void *msg, CFIndex size, void *info) {
4160
HyperVShutdownUserClientNotificationMessage *shutdownMsg = (HyperVShutdownUserClientNotificationMessage *) msg;
42-
UInt64 input[1];
4361

4462
if (size < __offsetof(HyperVShutdownUserClientNotificationMessage, type)) {
4563
HVSYSLOG(stderr, "Invalid message size %u received, should be at least %u",
@@ -49,9 +67,11 @@ void hvIOKitNotificationHandler(io_connect_t connection, CFMachPortRef port, voi
4967

5068
HVDBGLOG(stdout, "Received notification of type 0x%X", shutdownMsg->type);
5169
switch (shutdownMsg->type) {
70+
//
71+
// Always returns magic value, means daemon is alive and can handle a shutdown request.
72+
//
5273
case kHyperVShutdownUserClientNotificationTypeCheck:
53-
input[0] = true;
54-
IOConnectCallScalarMethod(connection, kHyperVShutdownUserClientMethodReportShutdownAbility, input, 1, NULL, NULL);
74+
hvShutdownDoShutdownCheck(connection);
5575
break;
5676

5777
case kHyperVShutdownUserClientNotificationTypePerformShutdown:

0 commit comments

Comments
 (0)