Patch AppleUSBXHCI để dùng với mọi USB 3.0 Controller – Phần 2

Phần 2 – Các patch cần áp dụng đối với AppleUSBXHCI

PatchAppleUSBXHCI1

Phần trước: Mục đích và các bước chuẩn bị

Lưu ý: Các patch dưới đây được áp dụng đối với phiên bản mới nhất tại thời điểm viết bài là AppleUSBXHCI version 705.4.14 (có trên Mac OS X 10.10 và 10.10.1). Với các phiên bản cũ hơn, bạn có thể tham khảo ở link nguồn bài viết trong phần 1.

A. Nguyên lí patch

Trong file AppleUSBXHCI.dsm.txt được chia làm nhiều section có dạng __ZN32[Tên module]. Mỗi module chứa nhiều dòng lệnh assembly, và bên trái mỗi dòng lệnh là một số nguyên 64-bit cho biết đoạn mã máy tương ứng với dòng lệnh sẽ nằm ở vị trí (offset) nào trong binary.

Trong từng patch một, ta sẽ phải tìm ra vị trí mà các byte sẽ được thay đổi. Để làm được điều này, ta sẽ dựa vào file AppleUSBXHCI.dsm.txt để tìm ra dòng lệnh assembly sẽ được thay đổi nhờ patch. Sau đó dựa vào con số bên trái dòng lệnh mà ta có được offset tương đối của các byte cần thay đổi. Bằng công cụ 0xED, ta sẽ nhảy đến offset đó và sửa các byte một cách phù hợp.

Để nhảy tới offset cần đến, ta chỉ cần nhập offset vào ô Go To Offset và bấm Enter. Byte tại offset đó sẽ được chọn.

PatchAppleUSBXHCI3

Khi ta chọn một byte, offset của byte đó sẽ hiển thị ở góc dưới bên phải.

PatchAppleUSBXHCI6

Để thay đổi một byte, đầu tiên ta phải bật chế độ overwrite bằng cách mở menu Edit -> Write mode, chọn Overwrite. Sau khi bật overwrite mode, ta chỉ cần chọn byte đó và nhập giá trị mới của byte.

B. Danh sách các patch cần áp dụng

Patch 1 – Tắt kiểm tra nhà cung cấp (vendor) của USB 3.0 controller

Patch này sẽ giúp cho AppleUSBXHCI chấp nhận USB 3.0 controller của mọi hãng, không chỉ riêng Intel.

Sự thay đổi trên assembly

Dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

jne	0x120bc

nằm ở offset 0x12086, trong section:

__ZN12AppleUSBXHCI13UIMInitializeEP9IOService

Với các phiên bản khác, con số 0x120bc có thể sẽ thay đổi, sẽ rất khó để ta xác định ra dòng lệnh này. Tuy vậy, dòng lệnh phía trên nó:

testb	$-0x80, 0xd4(%rax)

thì không đổi qua các phiên bản, do đó ta sẽ dùng nó làm từ khóa để tìm kiếm.

Patch này sẽ khiến cho chỉ lệnh jne được sửa thành jmp (unconditional jump), tức là dòng lệnh sau khi thay đổi sẽ thành:

jmp	0x120bc

Patch trên binary

Bước 1: Trong cửa sổ TextEdit của AppleUSBXHCI.dsm.txt, bấm Cmd + F để hiện Find Toolbar. Tìm kiếm với từ khóa:

testb	$-0x80, 0xd4(%rax)

sẽ cho ra 1 kết quả. Dòng lệnh ngay dưới kết quả tìm kiếm chính là dòng lệnh cần sửa.

PatchAppleUSBXHCI5

Bước 2: Nhìn vào con số bên trái, ta suy ra offset cần nhảy đến là 0x12086. Trong 0xED, ta nhảy tới offset 0x12086. Dòng lệnh bị thay đổi sẽ tương ứng với 2 byte:

... 00 80 75 34 41 F6 ...

Ta sửa byte ở offset 0x12086 từ 75 thành EB, tương ứng với việc thay đổi chỉ lệnh jne thành jmp:

... 00 80 EB 34 41 F6 ...

Patch 2 – Tắt kiểm tra phiên bản XHCI của USB 3.0 controller

Với các USB 3.0 controller đời trước, phiên bản XHCI của chúng thường dưới 1.0 (chẳng hạn như 0.96 đối với Renesas uDP72020). Patch này sẽ cho phép AppleUSBXHCI hoạt động với mọi phiên bản XHCI của các controller.

Sự thay đổi trên assembly

Dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

cmpl	$0x100, %eax

nằm ở offset 0x12160, trong section:

__ZN12AppleUSBXHCI13UIMInitializeEP9IOService

Với các phiên bản thấp hơn, dòng lệnh sẽ là:

cmpw	$0x100, %ax

Dòng lệnh phía trên nó luôn chứa:

movl	$0xe00002c7

do đó ta sẽ dùng nó làm dấu hiệu để nhận ra dòng lệnh bị thay đổi.

Patch này sẽ khiến cho giá trị 0x100 được sửa thành 0x0, tức là dòng lệnh sau khi thay đổi sẽ thành:

cmpl	$0x0, %eax

Patch trên binary

Bước 1: Tìm kiếm với từ khóa:

cmpl	$0x100, %eax

sẽ cho ra 3 kết quả trong cả file. Dòng lệnh bị thay đổi sẽ nằm ở kết quả thứ 2, bấm nút > để nhảy sang kết quả đó:

PatchAppleUSBXHCI7

Bước 2: Nhìn vào con số bên trái, ta suy ra offset cần nhảy đến là 0x12160. Trong 0xED, ta nhảy tới offset 0x12160. Dòng lệnh bị thay đổi sẽ tương ứng với 5 byte:

... 00 E0 3D 00 01 00 00 0F 82 ...

Ta sửa byte ở offset 0x12162 từ 01 thành 00, tương ứng với việc thay đổi giá trị từ 0x100 thành 0x0:

... 00 E0 3D 00 00 00 00 0F 82 ...

Patch 3 – Patch MSI / pin interrupt

Patch này sẽ disable việc dùng MSI interrupt (multiple vectors), mà thay vào đó chỉ dùng pin interrupt (single vector). Trong patch này sẽ gồm 2 patch nhỏ:

Patch 3.1

Sự thay đổi trên assembly

Dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

orl	$0x400000, 0x8(%rcx)

nằm ở offset 0x144a3, trong section:

__ZN12AppleUSBXHCI13AddressDeviceEjtbhii

Patch này sẽ khiến cho giá trị 0x400000 được sửa thành 0x0, tức là dòng lệnh sau khi thay đổi sẽ thành:

orl	$0x0, 0x8(%rcx)

Patch trên binary

Bước 1: Tìm kiếm với từ khóa:

orl	$0x400000, 0x8(%rcx)

sẽ cho ra đúng 1 kết quả chính là dòng lệnh bị thay đổi.

PatchAppleUSBXHCI7

Bước 2: Nhìn vào con số bên trái, ta suy ra offset cần nhảy đến là 0x144a3. Trong 0xED, ta nhảy tới offset 0x144a3. Dòng lệnh bị thay đổi sẽ tương ứng với 7 byte:

... 89 01 81 49 08 00 00 40 00 41 81 ...

Ta sửa byte ở offset 0x144a8 từ 40 thành 00, tương ứng với việc thay đổi giá trị từ 0x400000 thành 0x0:

... 89 01 81 49 08 00 00 00 00 41 81 ...

Patch 3.2

Sự thay đổi trên assembly

2 dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

movl	$0x400000, 0x8(%r15)

nằm ở offset 0x1574c và 0x159bc, trong section:

__ZN12AppleUSBXHCI15_createTransferEPvbyjybbPjS1_bPs

Patch này sẽ khiến cho giá trị 0x400000 được sửa thành 0x0, tức là dòng lệnh sau khi thay đổi sẽ thành:

movl	$0x0, 0x8(%r15)

Patch trên binary

Bước 1: Tìm kiếm với từ khóa:

movl	$0x400000, 0x8(%r15)

sẽ cho ra 2 kết quả, ứng với 2 dòng lệnh bị thay đổi.

PatchAppleUSBXHCI8PatchAppleUSBXHCI9

Bước 2: Nhìn vào con số bên trái, ta suy ra hai offset cần nhảy đến là 0x1574c và 0x159bc.

Trong 0xED, ta nhảy tới offset 0x1574c. Dòng lệnh đầu tiên bị thay đổi sẽ tương ứng với 8 byte:

... 45 E6 41 C7 47 08 00 00 40 00 48 8B ...

Ta sửa byte ở offset 0x15752 từ 40 thành 00, tương ứng với việc thay đổi giá trị từ 0x400000 thành 0x0:

... 45 E6 41 C7 47 08 00 00 00 00 48 8B ...

Sau đó ta nhảy tới offset 0x159bc. Dòng lệnh thứ 2 bị thay đổi sẽ tương ứng với 8 byte:

... E9 04 41 C7 47 08 00 00 40 00 41 8B ...

Ta sửa byte ở offset 0x159c2 từ 40 thành 00, tương ứng với việc thay đổi giá trị từ 0x400000 thành 0x0:

... E9 04 41 C7 47 08 00 00 00 00 41 8B ...

Patch 4 – Tắt sleep code trong AppleUSBXHCI

Do sleep code trong AppleUSBXHCI chỉ hoạt động với các USB 3.0 controller hỗ trợ PME, nên các controller đời trước khi dùng với sleep code sẽ không thể bật lại sau khi wake, dẫn đến các cổng USB 3.0 không hoạt động. Patch này sẽ tắt sleep code và sử dụng phương thức cổ điển, tức là tắt hẳn USB 3.0 controller khi sleep và khởi động lại nó khi wake.

Trước hết bạn nên thử xem nếu không patch thì các cổng USB 3.0 sau khi wake có hoạt động không, nếu không hoạt động thì mới phải áp dụng patch.

Sự thay đổi trên assembly

Dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

movb	$0x1, 0xc8(%rax)

nằm ở offset 0x643e, trong section:

__ZN12AppleUSBXHCI20CheckSleepCapabilityEv

Patch này sẽ khiến cho giá trị 0x1 được sửa thành 0x0, tức là dòng lệnh sau khi thay đổi sẽ thành:

movb	$0x0, 0xc8(%rax)

Patch trên binary

Bước 1: Tìm kiếm với từ khóa:

movb	$0x1, 0xc8(%rax)

sẽ cho ra đúng 1 kết quả chính là dòng lệnh bị thay đổi.

PatchAppleUSBXHCI11

Bước 2: Nhìn vào con số bên trái, ta suy ra offset cần nhảy đến là 0x643e. Trong 0xED, ta nhảy tới offset 0x643e. Dòng lệnh bị thay đổi sẽ tương ứng với 7 byte:

... 00 00 C6 80 C8 00 00 00 01 48 8B ...

Ta sửa byte ở offset 0x6444 từ 01 thành 00, tương ứng với việc thay đổi giá trị từ 0x1 thành 0x0:

... 00 00 C6 80 C8 00 00 00 00 48 8B ...

Patch 5 – Bật PME kể cả khi USB 3.0 controller không được liệt kê trong DSDT

Với DSDT của một số máy, Device tương ứng với USB 3.0 controller có thể không được liệt kê, dẫn đến AppleUSBXHCI không bật PME kể cả khi controller có hỗ trợ. Patch này sẽ bỏ qua kiểm tra đó, giúp cho PME được bật với controller có hỗ trợ.

Sự thay đổi trên assembly

Dòng lệnh bị thay đổi đối với phiên bản 705.4.14 sẽ là:

jne	0x64f5

nằm ở offset 0x64a6, trong section:

__ZN12AppleUSBXHCI20CheckSleepCapabilityEv

Với các phiên bản khác, con số 0x64f5 có thể sẽ thay đổi, sẽ rất khó để ta xác định ra dòng lệnh này. Tuy vậy, dòng lệnh phía trên nó:

testq	%rax, %rax

thì không đổi qua các phiên bản, do đó ta sẽ dùng nó làm từ khóa để tìm kiếm.

Patch này sẽ khiến cho chỉ lệnh jne được sửa thành jmp (unconditional jump), tức là dòng lệnh sau khi thay đổi sẽ thành:

jmp	0x64f5

Patch trên binary

Bước 1: Giữ nguyên dấu nháy văn bản tại dòng lệnh bị thay đổi ở patch 4, khi đó việc tìm kiếm sẽ bắt đầu từ dấu nháy văn bản. Tìm kiếm với từ khóa:

testq	%rax, %rax

sẽ cho ra rất nhiều kết quả. Bấm nút > để duyệt qua từng kết quả, để ý dòng lệnh ngay dưới kết quả có bắt đầu bằng chỉ lệnh jne hay không. Nếu có thì ta dừng lại và đó là dòng lệnh bị thay đổi (thường sẽ nằm ở kết quả thứ 2)

PatchAppleUSBXHCI10

Bước 2: Nhìn vào con số bên trái, ta suy ra offset cần nhảy đến là 0x64a6. Trong 0xED, ta nhảy tới offset 0x64a6. Dòng lệnh bị thay đổi sẽ tương ứng với 2 byte:

... 85 C0 75 4D 48 8B ...

Ta sửa byte ở offset 0x64a6 từ 75 thành EB, tương ứng với việc thay đổi chỉ lệnh jne thành jmp:

... 85 C0 EB 4D 48 8B ...

Dưới đây là file tóm tắt toàn bộ patch AppleUSBXHCI do mình soạn (tiếng Anh). Các bạn có thể tải bằng cách click vào link dưới.

Patch AppleUSBXHCI.docx

Phần tiếp theo: Áp dụng patch và tận hưởng thành quả

Bình luận về bài viết này