Skip to content

Commit 61e2bbf

Browse files
Added support for sending hda-verbs from user-space (#614)
1 parent 09a0177 commit 61e2bbf

13 files changed

+974
-39
lines changed

AppleALC.xcodeproj/project.pbxproj

+207-2
Large diffs are not rendered by default.
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// ALCUserClient.cpp
3+
// AppleALC
4+
//
5+
// Created by Nick on 10/14/20.
6+
// Copyright © 2020 vit9696. All rights reserved.
7+
//
8+
9+
#include <IOKit/IOLib.h>
10+
11+
#include "ALCUserClient.hpp"
12+
13+
OSDefineMetaClassAndStructors(ALCUserClient, IOUserClient);
14+
15+
const IOExternalMethodDispatch ALCUserClient::sMethods[kNumberOfMethods] = {
16+
{ //kMethodExecuteVerb
17+
reinterpret_cast<IOExternalMethodAction>(&ALCUserClient::methodExecuteVerb), // Method pointer
18+
3, // Num of scalar input values
19+
0, // Num of struct input values
20+
1, // Num of scalar output values
21+
0 // Num of struct output values
22+
}
23+
};
24+
25+
IOReturn ALCUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments* arguments, IOExternalMethodDispatch* dispatch, OSObject* target, void* reference) {
26+
if (selector >= kNumberOfMethods)
27+
return kIOReturnUnsupported;
28+
29+
dispatch = const_cast<IOExternalMethodDispatch*>(&sMethods[selector]);
30+
31+
target = mProvider;
32+
reference = NULL;
33+
34+
return super::externalMethod(selector, arguments, dispatch, target, reference);
35+
}
36+
37+
bool ALCUserClient::initWithTask(task_t owningTask, void* securityToken, UInt32 type, OSDictionary* properties) {
38+
if (!owningTask)
39+
return false;
40+
41+
if (!super::initWithTask(owningTask, securityToken, type))
42+
return false;
43+
44+
mTask = owningTask;
45+
mProvider = NULL;
46+
47+
return true;
48+
}
49+
50+
bool ALCUserClient::start(IOService* provider) {
51+
bool success;
52+
53+
mProvider = OSDynamicCast(ALCUserClientProvider, provider);
54+
success = (mProvider != NULL);
55+
56+
if (success)
57+
success = super::start(provider);
58+
59+
return success;
60+
}
61+
62+
IOReturn ALCUserClient::clientClose() {
63+
if (!isInactive())
64+
terminate();
65+
66+
return kIOReturnSuccess;
67+
}
68+
69+
IOReturn ALCUserClient::methodExecuteVerb(ALCUserClientProvider* target, void* ref, IOExternalMethodArguments* args) {
70+
uint16_t nid, verb, params;
71+
72+
nid = static_cast<uint16_t>(args->scalarInput[0]);
73+
verb = static_cast<uint16_t>(args->scalarInput[1]);
74+
params = static_cast<uint16_t>(args->scalarInput[2]);
75+
76+
args->scalarOutput[0] = target->sendHdaCommand(nid, verb, params);
77+
return kIOReturnSuccess;
78+
}
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// ALCUserClient.hpp
3+
// AppleALC
4+
//
5+
// Created by Nick on 10/14/20.
6+
// Copyright © 2020 vit9696. All rights reserved.
7+
//
8+
9+
#ifndef ALCUserClient_hpp
10+
#define ALCUserClient_hpp
11+
12+
#include <IOKit/IOService.h>
13+
#include <IOKit/IOUserClient.h>
14+
15+
#include "../UserKernelShared.h"
16+
#include "../ALCUserClientProvider/ALCUserClientProvider.hpp"
17+
18+
class ALCUserClient : public IOUserClient {
19+
typedef IOUserClient super;
20+
OSDeclareDefaultStructors(ALCUserClient);
21+
22+
private:
23+
ALCUserClientProvider* mProvider { nullptr };
24+
task_t mTask;
25+
static const IOExternalMethodDispatch sMethods[kNumberOfMethods];
26+
27+
public:
28+
virtual bool start(IOService* provider) override;
29+
30+
virtual bool initWithTask(task_t owningTask, void* securityToken,
31+
UInt32 type, OSDictionary* properties) override;
32+
33+
virtual IOReturn clientClose() override;
34+
virtual IOReturn externalMethod(uint32_t selector, IOExternalMethodArguments* arguments,
35+
IOExternalMethodDispatch* dispatch, OSObject* target,
36+
void* reference) override;
37+
38+
protected:
39+
static IOReturn methodExecuteVerb(ALCUserClientProvider* target, void* ref,
40+
IOExternalMethodArguments* args);
41+
};
42+
43+
#endif /* ALCUserClient_hpp */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//
2+
// ALCUserClientProvider.cpp
3+
// AppleALC
4+
//
5+
// Created by Nick on 10/14/20.
6+
// Copyright © 2020 vit9696. All rights reserved.
7+
//
8+
9+
#include "ALCUserClientProvider.hpp"
10+
11+
OSDefineMetaClassAndStructors(ALCUserClientProvider, IOService);
12+
13+
bool ALCUserClientProvider::start(IOService* provider) {
14+
if (!super::start(provider))
15+
return false;
16+
17+
auto matchingDict = IOService::nameMatching(kIOHDACodecDevice);
18+
if (!matchingDict) {
19+
DBGLOG("client", "Failed to allocate matching dictionary");
20+
return false;
21+
}
22+
23+
mHDACodecDevice = IOService::waitForMatchingService(matchingDict, 100000000); // Wait for 0.1s
24+
matchingDict->release();
25+
26+
if (!mHDACodecDevice)
27+
{
28+
DBGLOG("client", "Timeout in waiting for IOHDACodecDevice, will retry");
29+
return false;
30+
}
31+
32+
// We are ready for verbs
33+
DBGLOG("client", "ALCUserClient is ready for hda-verbs");
34+
setProperty("ReadyForALCVerbs", kOSBooleanTrue);
35+
readyForVerbs = true;
36+
37+
// Publish the service
38+
registerService();
39+
40+
return true;
41+
}
42+
43+
void ALCUserClientProvider::stop(IOService* provider) {
44+
super::stop(provider);
45+
46+
OSSafeReleaseNULL(mHDACodecDevice);
47+
}
48+
49+
uint64_t ALCUserClientProvider::sendHdaCommand(uint16_t nid, uint16_t verb, uint16_t param) {
50+
if (!readyForVerbs)
51+
{
52+
DBGLOG("client", "Provider not ready to accept hda-verb commands");
53+
return kIOReturnError;
54+
}
55+
56+
auto sharedAlc = AlcEnabler::getShared();
57+
58+
if (!sharedAlc) {
59+
DBGLOG("client", "Unable to get shared AlcEnabler instance");
60+
return kIOReturnError;
61+
}
62+
63+
UInt ret = 0;
64+
sharedAlc->IOHDACodecDevice_executeVerb(reinterpret_cast<void*>(mHDACodecDevice), nid, verb, param, &ret, true);
65+
DBGLOG("client", "Send HDA command nid=0x%X, verb=0x%X, param=0x%X, result=0x%08x", nid, verb, param, ret);
66+
67+
return ret;
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// ALCUserClientProvider.hpp
3+
// AppleALC
4+
//
5+
// Created by Nick on 10/14/20.
6+
// Copyright © 2020 vit9696. All rights reserved.
7+
//
8+
9+
#ifndef ALCUserClientProvider_hpp
10+
#define ALCUserClientProvider_hpp
11+
12+
#define kIOHDACodecDevice "IOHDACodecDevice"
13+
14+
#include<IOKit/IOService.h>
15+
#include <IOKit/IOUserClient.h>
16+
17+
#include "../kern_alc.hpp"
18+
19+
class ALCUserClientProvider : public IOService {
20+
typedef IOService super;
21+
OSDeclareDefaultStructors(ALCUserClientProvider);
22+
23+
private:
24+
IOService* mHDACodecDevice { nullptr };
25+
bool readyForVerbs { false };
26+
27+
public:
28+
virtual bool start(IOService* provider) override;
29+
virtual void stop(IOService* provider) override;
30+
31+
/**
32+
* Called by user-client to set the codec verbs
33+
*
34+
* @param nid Node ID
35+
* @param verb The hda-verb command to send (as defined in hdaverb.h)
36+
* @param param The parameters for the verb
37+
*
38+
* @return kIOReturnSuccess on successful execution
39+
*/
40+
virtual uint64_t sendHdaCommand(uint16_t nid, uint16_t verb, uint16_t param);
41+
};
42+
43+
#endif /* ALCUserClientProvider_hpp */

AppleALC/Info.plist

+25-10
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,25 @@
2020
<string>????</string>
2121
<key>CFBundleVersion</key>
2222
<string>$(MODULE_VERSION)</string>
23-
<key>OSBundleCompatibleVersion</key>
24-
<string>1.0</string>
2523
<key>IOKitPersonalities</key>
2624
<dict>
25+
<key>ALCUserClientProvider</key>
26+
<dict>
27+
<key>CFBundleIdentifier</key>
28+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
29+
<key>IOClass</key>
30+
<string>ALCUserClientProvider</string>
31+
<key>IOMatchCategory</key>
32+
<string>ALCUserClientProvider</string>
33+
<key>IOProbeScore</key>
34+
<integer>1000</integer>
35+
<key>IOProviderClass</key>
36+
<string>IOResources</string>
37+
<key>IOResourceMatch</key>
38+
<string>IOKit</string>
39+
<key>IOUserClientClass</key>
40+
<string>ALCUserClient</string>
41+
</dict>
2742
<key>as.vit9696.AppleALC</key>
2843
<dict>
2944
<key>CFBundleIdentifier</key>
@@ -40,26 +55,26 @@
4055
</dict>
4156
<key>NSHumanReadableCopyright</key>
4257
<string>Copyright © 2017 vit9696. All rights reserved.</string>
58+
<key>OSBundleCompatibleVersion</key>
59+
<string>1.0</string>
4360
<key>OSBundleLibraries</key>
4461
<dict>
62+
<key>as.vit9696.Lilu</key>
63+
<string>1.2.0</string>
64+
<key>com.apple.iokit.IOPCIFamily</key>
65+
<string>1.0.0b1</string>
4566
<key>com.apple.kpi.bsd</key>
4667
<string>12.0.0</string>
68+
<key>com.apple.kpi.dsep</key>
69+
<string>12.0.0</string>
4770
<key>com.apple.kpi.iokit</key>
4871
<string>12.0.0</string>
4972
<key>com.apple.kpi.libkern</key>
5073
<string>12.0.0</string>
5174
<key>com.apple.kpi.mach</key>
5275
<string>12.0.0</string>
53-
<key>com.apple.kpi.dsep</key>
54-
<string>12.0.0</string>
5576
<key>com.apple.kpi.unsupported</key>
5677
<string>12.0.0</string>
57-
<key>com.apple.iokit.IOPCIFamily</key>
58-
<string>1.0.0b1</string>
59-
<key>as.vit9696.Lilu</key>
60-
<string>1.2.0</string>
61-
<key>as.vit9696.PinConfigs</key>
62-
<string>1.0.0</string>
6378
</dict>
6479
<key>OSBundleRequired</key>
6580
<string>Root</string>

AppleALC/UserKernelShared.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// UserKernelShared.h
3+
// AppleALC
4+
//
5+
// Created by Nick on 10/14/20.
6+
// Copyright © 2020 vit9696. All rights reserved.
7+
//
8+
9+
#ifndef UserKernelShared_h
10+
#define UserKernelShared_h
11+
12+
enum {
13+
kMethodExecuteVerb,
14+
15+
kNumberOfMethods // Must be last
16+
};
17+
18+
#endif /* UserKernelShared_h */

AppleALC/kern_alc.cpp

+17-12
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,22 @@
1515
#include "kern_alc.hpp"
1616
#include "kern_resources.hpp"
1717

18+
static AlcEnabler alcEnabler;
19+
1820
// Only used in apple-driven callbacks
19-
static AlcEnabler *callbackAlc;
21+
AlcEnabler* AlcEnabler::callbackAlc = nullptr;
22+
23+
void AlcEnabler::createShared() {
24+
if (callbackAlc)
25+
PANIC("alc", "Attempted to assign alc callback again");
26+
27+
callbackAlc = &alcEnabler;
28+
29+
if (!callbackAlc)
30+
PANIC("alc", "Failed to assign alc callback");
31+
}
2032

2133
void AlcEnabler::init() {
22-
callbackAlc = this;
2334

2435
lilu.onPatcherLoadForce(
2536
[](void *user, KernelPatcher &pathcer) {
@@ -317,15 +328,11 @@ bool AlcEnabler::AppleHDAController_start(IOService* service, IOService* provide
317328
return FunctionCast(AppleHDAController_start, callbackAlc->orgAppleHDAController_start)(service, provider);
318329
}
319330

320-
#ifdef DEBUG
321-
IOReturn AlcEnabler::IOHDACodecDevice_executeVerb(void *that, uint16_t a1, uint16_t a2, uint16_t a3, unsigned int *a4, bool a5)
331+
IOReturn AlcEnabler::IOHDACodecDevice_executeVerb(void *hdaCodecDevice, uint16_t nid, uint16_t verb, uint16_t param, unsigned int *output, bool waitForSuccess)
322332
{
323-
IOReturn result = FunctionCast(IOHDACodecDevice_executeVerb, callbackAlc->orgIOHDACodecDevice_executeVerb)(that, a1, a2, a3, a4, a5);
324-
if (result != KERN_SUCCESS)
325-
DBGLOG("alc", "IOHDACodecDevice::executeVerb with parameters a1 = %u, a2 = %u, a3 = %u failed with result = %x", a1, a2, a3, result);
326-
return result;
333+
DBGLOG("alc", "IOHDACodecDevice::executeVerb with parameters nid = %u, verb = %u, param = %u", nid, verb, param);
334+
return FunctionCast(IOHDACodecDevice_executeVerb, callbackAlc->orgIOHDACodecDevice_executeVerb)(hdaCodecDevice, nid, verb, param, output, waitForSuccess);
327335
}
328-
#endif
329336

330337
uint32_t AlcEnabler::getAudioLayout(IOService *hdaDriver) {
331338
auto parent = hdaDriver->getParentEntry(gIOServicePlane);
@@ -623,13 +630,11 @@ void AlcEnabler::processKext(KernelPatcher &patcher, size_t index, mach_vm_addre
623630
eraseRedundantLogs(patcher, kextIndex);
624631
}
625632

626-
#ifdef DEBUG
627-
if (ADDPR(debugEnabled) && !(progressState & ProcessingState::PatchHDAFamily) && kextIndex == KextIdIOHDAFamily) {
633+
if (!(progressState & ProcessingState::PatchHDAFamily) && kextIndex == KextIdIOHDAFamily) {
628634
progressState |= ProcessingState::PatchHDAFamily;
629635
KernelPatcher::RouteRequest request("__ZN16IOHDACodecDevice11executeVerbEtttPjb", IOHDACodecDevice_executeVerb, orgIOHDACodecDevice_executeVerb);
630636
patcher.routeMultiple(index, &request, 1, address, size);
631637
}
632-
#endif
633638

634639
if (!(progressState & ProcessingState::PatchHDAController) && kextIndex == KextIdAppleHDAController) {
635640
progressState |= ProcessingState::PatchHDAController;

0 commit comments

Comments
 (0)