Skip to content

Commit 8b51dbd

Browse files
committed
IntelBTPatcher: Add patcher workaround to support new Intel bluetooth firmwares including new BT 5.1, BT 5.2 and BT 5.3.
1 parent eb7e3e1 commit 8b51dbd

File tree

3 files changed

+317
-9
lines changed

3 files changed

+317
-9
lines changed

IntelBTPatcher/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
<dict>
4141
<key>as.vit9696.Lilu</key>
4242
<string>1.2.0</string>
43+
<key>com.apple.iokit.IOUSBHostFamily</key>
44+
<string>1.2</string>
4345
<key>com.apple.kpi.bsd</key>
4446
<string>12.0.0</string>
4547
<key>com.apple.kpi.dsep</key>

IntelBTPatcher/IntelBTPatcher.cpp

Lines changed: 239 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// IntelBTPatcher.cpp
33
// IntelBTPatcher
44
//
5-
// Created by qcwap on 2021/2/8.
5+
// Created by zxystd <[email protected]> on 2021/2/8.
66
//
77

88
#include <Headers/kern_api.hpp>
@@ -37,7 +37,7 @@ PluginConfiguration ADDPR(config) {
3737
bootargBeta,
3838
arrsize(bootargBeta),
3939
KernelVersion::MountainLion,
40-
KernelVersion::Monterey,
40+
KernelVersion::Ventura,
4141
[]() {
4242
ibtPatcher.init();
4343
}
@@ -54,14 +54,37 @@ static KernelPatcher::KextInfo IntelBTPatcher_IOBluetoothInfo {
5454
KernelPatcher::KextInfo::Unloaded
5555
};
5656

57+
static const char *IntelBTPatcher_IOUSBHostFamily[] {
58+
"/System/Library/Extensions/IOUSBHostFamily.kext/Contents/MacOS/IOUSBHostFamily" };
59+
60+
static KernelPatcher::KextInfo IntelBTPatcher_IOUsbHostInfo {
61+
"com.apple.iokit.IOUSBHostFamily",
62+
IntelBTPatcher_IOUSBHostFamily,
63+
1,
64+
{true, true},
65+
{},
66+
KernelPatcher::KextInfo::Unloaded
67+
};
68+
69+
void *CIntelBTPatcher::_hookPipeInstance = nullptr;
70+
AsyncOwnerData *CIntelBTPatcher::_interruptPipeAsyncOwner = nullptr;
71+
bool CIntelBTPatcher::_randomAddressInit = false;
72+
5773
bool CIntelBTPatcher::init()
5874
{
5975
DBGLOG(DRV_NAME, "%s", __PRETTY_FUNCTION__);
6076
callbackIBTPatcher = this;
61-
lilu.onKextLoadForce(&IntelBTPatcher_IOBluetoothInfo, 1,
62-
[](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
63-
callbackIBTPatcher->processKext(patcher, index, address, size);
64-
}, this);
77+
if (getKernelVersion() < KernelVersion::Monterey) {
78+
lilu.onKextLoadForce(&IntelBTPatcher_IOBluetoothInfo, 1,
79+
[](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
80+
callbackIBTPatcher->processKext(patcher, index, address, size);
81+
}, this);
82+
} else {
83+
lilu.onKextLoadForce(&IntelBTPatcher_IOUsbHostInfo, 1,
84+
[](void *user, KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size) {
85+
callbackIBTPatcher->processKext(patcher, index, address, size);
86+
}, this);
87+
}
6588
return true;
6689
}
6790

@@ -91,15 +114,224 @@ void CIntelBTPatcher::processKext(KernelPatcher &patcher, size_t index, mach_vm_
91114
}
92115

93116
}
117+
} else {
118+
if (IntelBTPatcher_IOUsbHostInfo.loadIndex == index) {
119+
SYSLOG(DRV_NAME, "%s", IntelBTPatcher_IOUsbHostInfo.id);
120+
121+
KernelPatcher::RouteRequest hostDeviceRequest {
122+
"__ZN15IOUSBHostDevice13deviceRequestEP9IOServiceRN11StandardUSB13DeviceRequestEPvP18IOMemoryDescriptorRjP19IOUSBHostCompletionj",
123+
newHostDeviceRequest,
124+
oldHostDeviceRequest
125+
};
126+
patcher.routeMultiple(index, &hostDeviceRequest, 1, address, size);
127+
if (patcher.getError() == KernelPatcher::Error::NoError) {
128+
SYSLOG(DRV_NAME, "routed %s", hostDeviceRequest.symbol);
129+
} else {
130+
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", hostDeviceRequest.symbol, patcher.getError());
131+
patcher.clearError();
132+
}
133+
134+
KernelPatcher::RouteRequest asyncIORequest {
135+
"__ZN13IOUSBHostPipe2ioEP18IOMemoryDescriptorjP19IOUSBHostCompletionj",
136+
newAsyncIO,
137+
oldAsyncIO
138+
};
139+
patcher.routeMultiple(index, &asyncIORequest, 1, address, size);
140+
if (patcher.getError() == KernelPatcher::Error::NoError) {
141+
SYSLOG(DRV_NAME, "routed %s", asyncIORequest.symbol);
142+
} else {
143+
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", asyncIORequest.symbol, patcher.getError());
144+
patcher.clearError();
145+
}
146+
147+
KernelPatcher::RouteRequest initPipeRequest {
148+
"__ZN13IOUSBHostPipe28initWithDescriptorsAndOwnersEPKN11StandardUSB18EndpointDescriptorEPKNS0_37SuperSpeedEndpointCompanionDescriptorEP22AppleUSBHostControllerP15IOUSBHostDeviceP18IOUSBHostInterfaceht",
149+
newInitPipe,
150+
oldInitPipe
151+
};
152+
patcher.routeMultiple(index, &initPipeRequest, 1, address, size);
153+
if (patcher.getError() == KernelPatcher::Error::NoError) {
154+
SYSLOG(DRV_NAME, "routed %s", initPipeRequest.symbol);
155+
} else {
156+
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", initPipeRequest.symbol, patcher.getError());
157+
patcher.clearError();
158+
}
159+
160+
KernelPatcher::RouteRequest syncIORequest {
161+
"__ZN13IOUSBHostPipe2ioEP18IOMemoryDescriptorjRjj",
162+
newSyncIO,
163+
oldSyncIO
164+
};
165+
patcher.routeMultiple(index, &syncIORequest, 1, address, size);
166+
if (patcher.getError() == KernelPatcher::Error::NoError) {
167+
SYSLOG(DRV_NAME, "routed %s", syncIORequest.symbol);
168+
} else {
169+
SYSLOG(DRV_NAME, "failed to resolve %s, error = %d", syncIORequest.symbol, patcher.getError());
170+
patcher.clearError();
171+
}
172+
}
94173
}
95174
}
96175

176+
#pragma mark - For Bigsur-, patch unhandled 0x2019 opcode
177+
178+
#define HCI_OP_LE_START_ENCRYPTION 0x2019
179+
97180
IOReturn CIntelBTPatcher::newFindQueueRequest(void *that, unsigned short arg1, void *addr, unsigned short arg2, bool arg3, void **hciRequestPtr)
98181
{
99182
IOReturn ret = FunctionCast(newFindQueueRequest, callbackIBTPatcher->oldFindQueueRequest)(that, arg1, addr, arg2, arg3, hciRequestPtr);
100-
if (ret != 0 && arg1 == 0x2019) {
183+
if (ret != 0 && arg1 == HCI_OP_LE_START_ENCRYPTION) {
101184
ret = FunctionCast(newFindQueueRequest, callbackIBTPatcher->oldFindQueueRequest)(that, arg1, addr, 0xffff, arg3, hciRequestPtr);
102185
DBGLOG(DRV_NAME, "%s ret: %d arg1: 0x%04x arg2: 0x%04x arg3: %d ptr: %p", __FUNCTION__, ret, arg1, arg2, arg3, *hciRequestPtr);
103186
}
104187
return ret;
105188
}
189+
190+
#pragma mark - For Monterey+ patch for intercept HCI REQ and RESP
191+
192+
StandardUSB::DeviceRequest randomAddressRequest;
193+
// Hardcoded Random Address HCI Command
194+
const uint8_t randomAddressHci[9] = {0x05, 0x20, 0x06, 0x94, 0x50, 0x64, 0xD0, 0x78, 0x6B};
195+
IOBufferMemoryDescriptor *writeHCIDescriptor = nullptr;
196+
197+
#define MAX_HCI_BUF_LEN 255
198+
#define HCI_OP_RESET 0x0c03
199+
#define HCI_OP_LE_SET_SCAN_PARAM 0x200B
200+
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200C
201+
202+
IOReturn CIntelBTPatcher::newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length, IOUSBHostCompletion *completion, unsigned int timeout)
203+
{
204+
HciCommandHdr *hdr = nullptr;
205+
uint32_t hdrLen = 0;
206+
char hciBuf[MAX_HCI_BUF_LEN] = {0};
207+
208+
if (data == nullptr) {
209+
if (descriptor != nullptr && descriptor->getLength() > 0) {
210+
descriptor->readBytes(0, hciBuf, min(descriptor->getLength(), MAX_HCI_BUF_LEN));
211+
hdrLen = (uint32_t)min(descriptor->getLength(), MAX_HCI_BUF_LEN);
212+
}
213+
hdr = (HciCommandHdr *)hciBuf;
214+
if (hdr->opcode == HCI_OP_LE_SET_SCAN_PARAM) {
215+
if (!_randomAddressInit) {
216+
randomAddressRequest.bmRequestType = makeDeviceRequestbmRequestType(kRequestDirectionOut, kRequestTypeClass, kRequestRecipientInterface);
217+
randomAddressRequest.bRequest = 0xE0;
218+
randomAddressRequest.wIndex = 0;
219+
randomAddressRequest.wValue = 0;
220+
randomAddressRequest.wLength = 9;
221+
length = 9;
222+
if (writeHCIDescriptor == nullptr)
223+
writeHCIDescriptor = IOBufferMemoryDescriptor::withBytes(randomAddressHci, 9, kIODirectionOut);
224+
writeHCIDescriptor->prepare(kIODirectionOut);
225+
IOReturn ret = FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, randomAddressRequest, nullptr, writeHCIDescriptor, length, nullptr, timeout);
226+
writeHCIDescriptor->complete();
227+
const char *randAddressDump = _hexDumpHCIData((uint8_t *)randomAddressHci, 9);
228+
if (randAddressDump) {
229+
SYSLOG(DRV_NAME, "[PATCH] Sending Random Address HCI %lld %s", ret, randAddressDump);
230+
IOFree((void *)randAddressDump, 9 * 3 + 1);
231+
}
232+
_randomAddressInit = true;
233+
SYSLOG(DRV_NAME, "[PATCH] Resend LE SCAN PARAM HCI %lld", ret);
234+
}
235+
}
236+
#if 0 // We don't need to fake Random address request to Public address, and it is not really fix the issue with Intel fatal firmware error after HCI_OP_LE_SET_SCAN_ENABLE.
237+
else if (hdr->opcode == HCI_OP_LE_SET_SCAN_ENABLE) {
238+
hdr->data[5] = 0x00;
239+
SYSLOG(DRV_NAME, "[FAKE REQ]: RANDOM->PUBLIC done\n");
240+
}
241+
#endif
242+
} else {
243+
hdr = (HciCommandHdr *)data;
244+
hdrLen = request.wLength - 3;
245+
}
246+
if (hdr) {
247+
// HCI reset, we need to send Random address again
248+
if (hdr->opcode == HCI_OP_RESET)
249+
_randomAddressInit = false;
250+
#if DEBUG
251+
DBGLOG(DRV_NAME, "[%s] bRequest: 0x%x direction: %s type: %s recipient: %s wValue: 0x%02x wIndex: 0x%02x opcode: 0x%04x len: %d length: %d async: %d", provider->getName(), request.bRequest, requestDirectionNames[(request.bmRequestType & kDeviceRequestDirectionMask) >> kDeviceRequestDirectionPhase], requestRecipientNames[(request.bmRequestType & kDeviceRequestRecipientMask) >> kDeviceRequestRecipientPhase], requestTypeNames[(request.bmRequestType & kDeviceRequestTypeMask) >> kDeviceRequestTypePhase], request.wValue, request.wIndex, hdr->opcode, hdr->len, request.wLength, completion != nullptr);
252+
if (hdrLen) {
253+
const char *dump = _hexDumpHCIData((uint8_t *)hdr, hdrLen);
254+
if (dump) {
255+
DBGLOG(DRV_NAME, "[Request]: %s", dump);
256+
IOFree((void *)dump, hdrLen * 3 + 1);
257+
}
258+
}
259+
#endif
260+
}
261+
return FunctionCast(newHostDeviceRequest, callbackIBTPatcher->oldHostDeviceRequest)(that, provider, request, data, descriptor, length, completion, timeout);
262+
}
263+
264+
// Succeeded HCI command result of HCI_OP_LE_SET_SCAN_ENABLE, on Monterey+ this will return status 0x12 if we don't set the Random address before
265+
const uint8_t fakeLEScanEnableResp[6] = {0x0E, 0x04, 0x02, 0x0C, 0x20, 0x00};
266+
267+
static void asyncIOCompletion(void* owner, void* parameter, IOReturn status, uint32_t bytesTransferred)
268+
{
269+
AsyncOwnerData *asyncOwner = (AsyncOwnerData *)owner;
270+
IOMemoryDescriptor* dataBuffer = asyncOwner->dataBuffer;
271+
DBGLOG(DRV_NAME, "[COMPLETE] status: %d bytesTransferred: %d", status, bytesTransferred);
272+
if (dataBuffer && bytesTransferred) {
273+
void *buffer = IOMalloc(bytesTransferred);
274+
dataBuffer->readBytes(0, buffer, bytesTransferred);
275+
const char *dump = _hexDumpHCIData((uint8_t *)buffer, bytesTransferred);
276+
if (dump) {
277+
DBGLOG(DRV_NAME, "[Response]: %s", dump);
278+
IOFree((void *)dump, bytesTransferred * 3 + 1);
279+
}
280+
HciResponse *resp = (HciResponse *)buffer;
281+
if (resp->opcode == 0x200C && resp->data[0]) {
282+
SYSLOG(DRV_NAME, "[FAKE RESP]: done");
283+
dataBuffer->writeBytes(0, fakeLEScanEnableResp, 6);
284+
}
285+
IOFree(buffer, bytesTransferred);
286+
}
287+
if (asyncOwner->action)
288+
asyncOwner->action(asyncOwner->owner, parameter, status, bytesTransferred);
289+
}
290+
291+
IOReturn CIntelBTPatcher::
292+
newAsyncIO(void *that, IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs)
293+
{
294+
IOReturn ret = kIOReturnSuccess;
295+
if (that == _hookPipeInstance && completion) {
296+
_interruptPipeAsyncOwner->action = completion->action;
297+
_interruptPipeAsyncOwner->owner = completion->owner;
298+
_interruptPipeAsyncOwner->dataBuffer = dataBuffer;
299+
completion->action = asyncIOCompletion;
300+
completion->owner = _interruptPipeAsyncOwner;
301+
ret = FunctionCast(newAsyncIO, callbackIBTPatcher->oldAsyncIO)(that, dataBuffer, dataBufferLength, completion, completionTimeoutMs);
302+
if (ret != kIOReturnSuccess)
303+
SYSLOG(DRV_NAME, "%s failed ret: %lld", __FUNCTION__, ret);
304+
return ret;
305+
}
306+
return FunctionCast(newAsyncIO, callbackIBTPatcher->oldAsyncIO)(that, dataBuffer, dataBufferLength, completion, completionTimeoutMs);
307+
}
308+
309+
IOReturn CIntelBTPatcher::
310+
newSyncIO(void *that, IOMemoryDescriptor *dataBuffer, uint32_t dataBufferLength, uint32_t &bytesTransferred, uint32_t completionTimeoutMs)
311+
{
312+
return FunctionCast(newSyncIO, callbackIBTPatcher->oldSyncIO)(that, dataBuffer, dataBufferLength, bytesTransferred, completionTimeoutMs);
313+
}
314+
315+
#define VENDOR_USB_INTEL 0x8087
316+
317+
int CIntelBTPatcher::
318+
newInitPipe(void *that, StandardUSB::EndpointDescriptor const *descriptor, StandardUSB::SuperSpeedEndpointCompanionDescriptor const *superDescriptor, AppleUSBHostController *controller, IOUSBHostDevice *device, IOUSBHostInterface *interface, unsigned char a7, unsigned short a8)
319+
{
320+
int ret = FunctionCast(newInitPipe, callbackIBTPatcher->oldInitPipe)(that, descriptor, superDescriptor, controller, device, interface, a7, a8);
321+
if (device) {
322+
const StandardUSB::DeviceDescriptor *deviceDescriptor = device->getDeviceDescriptor();
323+
if (deviceDescriptor &&
324+
deviceDescriptor->idVendor == VENDOR_USB_INTEL) {
325+
uint8_t epType = StandardUSB::getEndpointType(descriptor);
326+
DBGLOG(DRV_NAME, "GOT YOU Intel bluetooth pid: %d ep type: %d", deviceDescriptor->iProduct, epType);
327+
if (epType == kIOUSBEndpointTypeInterrupt) {
328+
SYSLOG(DRV_NAME, "GOT YOU Interrupt PIPE");
329+
CIntelBTPatcher::_hookPipeInstance = that;
330+
if (!CIntelBTPatcher::_interruptPipeAsyncOwner)
331+
CIntelBTPatcher::_interruptPipeAsyncOwner = new AsyncOwnerData;
332+
CIntelBTPatcher::_randomAddressInit = false;
333+
}
334+
}
335+
}
336+
return ret;
337+
}

IntelBTPatcher/IntelBTPatcher.hpp

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,77 @@
22
// IntelBTPatcher.h
33
// IntelBTPatcher
44
//
5-
// Created by qcwap on 2021/2/8.
5+
// Created by zxystd <[email protected]> on 2021/2/8.
66
//
77

88
#ifndef IntelBTPatcher_h
99
#define IntelBTPatcher_h
1010

1111
#include <Headers/kern_patcher.hpp>
1212

13-
#define DRV_NAME "IntelBTPatcher"
13+
#include <IOKit/usb/IOUSBHostDevice.h>
14+
15+
#define DRV_NAME "ibtp"
1416

1517
class BluetoothDeviceAddress;
1618

19+
typedef struct {
20+
void *owner;
21+
IOMemoryDescriptor *dataBuffer;
22+
IOUSBHostCompletionAction action;
23+
} AsyncOwnerData;
24+
25+
typedef struct __attribute__((packed))
26+
{
27+
uint16_t opcode; /* OCF & OGF */
28+
uint8_t len;
29+
uint8_t data[];
30+
} HciCommandHdr;
31+
32+
typedef struct __attribute__((packed))
33+
{
34+
uint8_t evt;
35+
uint8_t len;
36+
} HciEventHdr;
37+
38+
typedef struct __attribute__((packed))
39+
{
40+
HciEventHdr evt;
41+
uint8_t numCommands;
42+
uint16_t opcode;
43+
uint8_t data[];
44+
} HciResponse;
45+
46+
const char *requestDirectionNames[] = {
47+
"OUT",
48+
"IN"
49+
};
50+
51+
const char *requestTypeNames[] = {
52+
"Standard",
53+
"Class",
54+
"Vendor"
55+
};
56+
57+
const char *requestRecipientNames[] = {
58+
"Device",
59+
"Interface",
60+
"Endpoint",
61+
"Other"
62+
};
63+
64+
const char* _hexDumpHCIData(uint8_t *buf, size_t len)
65+
{
66+
ssize_t str_len = len * 3 + 1;
67+
char *str = (char*)IOMalloc(str_len);
68+
if (!str)
69+
return nullptr;
70+
for (size_t i = 0; i < len; i++)
71+
snprintf(str + 3 * i, (len - i) * 3, "%02x ", buf[i]);
72+
str[MAX(str_len - 2, 0)] = 0;
73+
return str;
74+
}
75+
1776
class CIntelBTPatcher {
1877
public:
1978
bool init();
@@ -22,7 +81,22 @@ class CIntelBTPatcher {
2281
void processKext(KernelPatcher &patcher, size_t index, mach_vm_address_t address, size_t size);
2382
static IOReturn newFindQueueRequest(void *that, unsigned short arg1, void *addr, unsigned short arg2, bool arg3, void **hciRequestPtr);
2483

84+
static IOReturn newHostDeviceRequest(void *that, IOService *provider, StandardUSB::DeviceRequest &request, void *data, IOMemoryDescriptor *descriptor, unsigned int &length,IOUSBHostCompletion *completion, unsigned int timeout);
85+
static IOReturn newAsyncIO(void *that, IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, IOUSBHostCompletion* completion, uint32_t completionTimeoutMs);
86+
static IOReturn newSyncIO(void *that, IOMemoryDescriptor* dataBuffer, uint32_t dataBufferLength, uint32_t& bytesTransferred, uint32_t completionTimeoutMs);
87+
static int newInitPipe(void *that, StandardUSB::EndpointDescriptor const *descriptor, StandardUSB::SuperSpeedEndpointCompanionDescriptor const *superDescriptor,AppleUSBHostController *controller, IOUSBHostDevice *device, IOUSBHostInterface *interface, unsigned char, unsigned short);
88+
89+
2590
mach_vm_address_t oldFindQueueRequest {};
91+
mach_vm_address_t oldHostDeviceRequest {};
92+
mach_vm_address_t oldAsyncIO {};
93+
mach_vm_address_t oldSyncIO {};
94+
mach_vm_address_t oldInitPipe {};
95+
96+
private:
97+
static void *_hookPipeInstance;
98+
static AsyncOwnerData *_interruptPipeAsyncOwner;
99+
static bool _randomAddressInit;
26100
};
27101

28102
#endif /* IntelBTPatcher_h */

0 commit comments

Comments
 (0)