Các bản AppleACPIPlatform mới không thể nào truy cập chính xác vào trường EC (Embedded Controller) nên nó sẽ gây ra 1 số lỗi khi sử dụng các kext hiển thị phần trăm pin, bạn phải tiến hành sửa đổi DSDT để nó nhận chính xác mặc dù bạn có thể dùng các bản AppleACPIPlatform cũ hơn (Snow Leopard) nhưng vì các CPU đời Ivy Birdge + có hỗ trợ tính năng quản lý năng lượng nên mình khuyên các bạn nên dùng bản mới nhất. Để làm điều đó, chúng ta cần thay đổi các trường trong EC thành 8 bit để có thể truy cập cùng 1 lúc.
Tiến hành
Dùng kext ECEnabler
Khi dùng cách này thì khả năng 90% là nhận pin
B1: Tải kext ECEnabler từ nguồn sau và bỏ vào thư mục EFI ⇒ OC hoặc EFI ==> CLOVER ==> KEXT ==> OTHER
B2 Snapshot config nếu dùng OpenCore.
B3: Tải SMCBattery.kext bỏ vô mục kext và snapshot lại
Lưu ý : Khi làm theo cách này thì lúc các bạn update firmware sẽ phải làm lại, nếu không muốn làm lại thì các bạn có thể trích DSDT theo hướng dẫn tại đây.
B2: Biên dịch DSDT thành .dsl theo hướng dẫn tại đây.
B3: Mở DSDT lên và search Embedded để xác định các trường EC.
Ở đây ta có 4 trường EC
ECOR
SMBX
SMB2
NSBS
B4: Ta tiến hành search các trường EC đã xác định ở trên
Ở đây ta có:
Biến NSBS xuất hiện ở 1 field
Biến SMB2 xuất hiện ở 2 field
Biến SMBX xuất hiện ở 3 field
Và biến ECOR xuất hiện ở 1 field
B5: Các bạn tiến hành nhìn vào các biến ở các field đã xác định ở trên.
Biến nào trên 8 bit thì ghi lại.
Lưu ý:
Đối với những trường 16 bit và 32 bit các bạn tiết hành search các trường đó nếu chỉ trả về 1 giá trị có nghĩa là trường đó không được sử dụng và có thể bỏ qua.
Ở đây ta có trường B0TM có 16 bit
Tuy nhiên khi search lại trường này tả chỉ thấy có 1 kết quả trả về. Tức trường này không được sử dụng và có thể bỏ qua.
Để fix các trường 16 bit bạn sẽ tiến hành chia nhỏ các trường 16 bit thành 2 trường 8 bit
B1: Đặt tên cho 2 trường vừa tách. Tên mới không được trùng với các tên đã có trong DSDT
mẹo ở đây là bạn sẽ lấy tên của trường chính bỏ đi ký tự đầu tiên và thêm sau là các sô thứ tự. Cần tránh các tên bắt đầu bằn chữ số
// sau khi làm xong ta được
variableOrig. variable1 variable2
DT2B, 16, ==> T2B1, T2B2
TAH0, 16, ==> AH01, AH02
TAH1, 16, ==> AH11, AH12
B0C3, 16, ==> B0CX, B0CK
B0SN, 16, ==> B0SX, B0SK
B1SN, 16, ==> B1SX, B1SK
B2: Tiến hành viết patch để tách các trường thành các trường nhỏ 8 bit.
# cấu trúc chung:
into device label EC code_regex variableOrig,\s+16, replace_matched begin variable1,8,variable2,8, end;
# Note thay variable bằng tên trường các bạn đã xác định ở trên
# ví dụ
into device label EC code_regex DT2B,\s+16 replace_matched begin T2B1,8,T2B2,8, end;
# giái thích cú pháp:
# into device label EC code_regex DT2B,\s+16: tức là tìm trong device EC đoạn code DT2B, 16
# replace_matched begin T2B1,8,T2B2,8,: tức là thay thế đoạn code trên và thay thế chúng bằng T2B1,8,T2B2,8,
# sau khi làm xong ta được
into device label EC code_regex DT2B,\s+16 replace_matched begin T2B1,8,T2B2,8, end;
into device label EC code_regex TAH0,\s+16, replace_matched begin AH01,8,AH02,8, end;
into device label EC code_regex TAH1,\s+16, replace_matched begin AH11,8,AH12,8, end;
into device label EC code_regex B0C3,\s+16, replace_matched begin B0CX,8,B0CK,8, end;
into device label EC code_regex B0SN,\s+16, replace_matched begin B0SX,8,B0SK,8, end;
into device label EC code_regex B1SN,\s+16 replace_matched begin B1SX,8,B1SK,8, end;
B3: Tiến hành apply patch vừa viết theo hướng dẫn tại đây. Sau khi apply sẽ được như hình:
hình ảnh chỉ mang tính chất minh họa
B4: Ta sẽ tiến hành fix các lỗi. Do ở bước trên bạn đã tiên hành tách các trường 16 bit nên những method call qua trường này sẽ bị lỗi. Để fix lỗi đó các bạn sẽ tiến hành add method b1b2 vào:
into method label B1B2 remove_entry;
into definitionblock code_regex . insert
begin
Method (B1B2, 2, NotSerialized) { Return(Or(Arg0, ShiftLeft(Arg1, 8))) }\n
end;
B5: Nhấn compiler để tiến hành check lỗi.
B6: Các bạn sẽ ân vào vùng lỗi và tìm xem nó ở method nào.
B7: Ta sẽ tiến hành phân tích lỗi và viết patch.
Ở đây ta thấy nó báo lỗi trường B1SN khi nhấn vào thì sẽ hiện dòng code bị lỗi là Store (B1SN, Local0) ở method BIFA thì ta sẽ có cách dạng lỗi thường gặp:
Store (variableOrig, )
Đối với dạng này ta sẽ có cấu trúc fix chung là:
into method label <method> code_regex \(<variableOrig>, replaceall_matched begin (B1B2(<variable1>,<variable2>), end;
Ví dụ:
into method label BIFA code_regex \(B1SN, replaceall_matched begin (B1B2(B1SX,B1SK), end;
Store ( ,variableOrig)
Đối với dạn này ta sẽ có câu trúc fix chung là:
into method label <method> code_regex \<variableOrig>) replaceall_matched begin B1B2(<variable1>,<variable2>)) end;
Ví dụ:
into method label SMBW code_regex \DT2B) replaceall_matched begin B1B2(T2B1,T2B2)) end;
Ở trên là 2 dạng khá phổ biến mà bạn có thể gặp phải. Ngoài ra còn 1 dạng lỗi đặc biệt nữa như sau:
Ta có thể thấy biến bị lỗi được gắn với 1 đường dẫn. Vì vậy để fix lỗi này ta sẽ tiến hành thay toàn bộ đường dẫn bằng b1b2. Tuy nhiên bạn phải tiến hành gắn các biến trong b1b2 với đường dẫn đã thay thế
// before
Store (^^LPCB.EC.B0C3, Index (BIXT, 0x0A))
// after
Store (B1B2(^^LPCB.EC.B0CX, ^^LPCB.EC.B0CK), Index (BIXT, 0x0A))
Cấu trúc chung:
into method label<method> code_regex \<path variableOrig>, replaceall_matched begin B1B2(<path variable1>, <path variable2>), end;
Xem các xác định path variable ở mục lưu ý
Ví dụ:
into method label _BIX code_regex \^\^LPCB.EC.B0C3, replaceall_matched begin B1B2(^\^LPCB.EC.B0CX, ^\^LPCB.EC.B0CK), end;
Chú ý:
Có nghĩa là method chứa dòng code lỗi như ở trên sẽ là _BIX
Vậy để xác định được method của dòng code lỗi ta sẽ ấn nút compiler để check lỗi và ấn vào lỗi cần fix nhìn vào gốc dưới bên trái để xác định được method cần dùng.
Ở đây do DSDT patch ở trên không có trường 32 bit nên ta sẽ dùng tạm DSDT khác để tiến hành patch trường 32 bit. Làm tương tự như P1 ta có các trường 32 bit sau:
BTY0, 32,
BTY1, 32,
B1: Ta sẽ tiến hành tách các trường 32 bit thành 4 trường 8 bit và đặt tên cho 4 trường đó:
B2: Ta tiến hành viết patch trương tự như ở trường 16 bit. Nhưng thay vì thay bằng 2 trường 8 bit ta sẽ tiến hành thay bằng 4 trường 8 bit. Sau khi làm xong ta được:
into device label EC code_regex BTY0,\s+32 replace_matched begin TY01,8,TY02,8,TY03,8,TY04,8 end;
into device label EC code_regex BTY1,\s+32 replace_matched begin TY11,8,TY12,8,TY13,8,TY14,8 end;
Tương tự như trường 16 bit ta vẫn sẽ gặp error.
B3: Để khắc phục điều này ta sẽ tiến hành tương tự như trường 16 bit nhưng thay vì add method B1B2 ta sẽ add method B1B4:
B4: Ta sẽ tiến hành add các patch fix lỗi tương tự như trường 16 bit nhưng thay B1B2 thành B1B4. Sau khi làm xong ta sẽ được:
into method label GBTI code_regex \(BTY0, replaceall_matched begin (B1B4(TY01,TY02,TY03,TY04), end;
into method label GBTI code_regex \(BTY1, replaceall_matched begin (B1B4(TY11,TY12,TY13,TY14), end;
B5: Tiến hành apply các patch.
P3: Patch các trường lớn hơn 32 bit
Như đã xác định ở P1 ta có các trường lớn hơn 32 bit là:
B5: Vì ta đã rename ở bước 2 nên khi compiler sẽ có error. Để khắc phục ta sẽ tiến hành add method RECB (Read EC Buffer) và WECB (Write EC Buffer)
Khi bạn check lỗi mà nhận được lỗi có dạng Store(<variableOrig>, )
thì nó sẽ thuộc method RECB
Ví dụ:
Store (BDAT, )
Khi check lỗi mà có dạng là Store( ,<variableOrig>)
thì nó sẽ thuộc method WECB
Ví dụ:
Store ( ,BDAT)
# RECB
# utility methods to read/write buffers from/to EC
into method label RE1B parent_label EC remove_entry;
into method label RECB parent_label EC remove_entry;
into device label EC insert
begin
Method (RE1B, 1, NotSerialized)\n
{\n
OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
Return(BYTE)\n
}\n
Method (RECB, 2, Serialized)\n
// Arg0 - offset in bytes from zero-based EC\n
// Arg1 - size of buffer in bits\n
{\n
ShiftRight(Add(Arg1,7), 3, Arg1)\n
Name(TEMP, Buffer(Arg1) { })\n
Add(Arg0, Arg1, Arg1)\n
Store(0, Local0)\n
While (LLess(Arg0, Arg1))\n
{\n
Store(RE1B(Arg0), Index(TEMP, Local0))\n
Increment(Arg0)\n
Increment(Local0)\n
}\n
Return(TEMP)\n
}\n
end;
#WECB
into method label WE1B parent_label EC remove_entry;
into method label WECB parent_label EC remove_entry;
into device label EC insert
begin
Method (WE1B, 2, NotSerialized)\n
{\n
OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
Store(Arg1, BYTE)\n
}\n
Method (WECB, 3, Serialized)\n
// Arg0 - offset in bytes from zero-based EC\n
// Arg1 - size of buffer in bits\n
// Arg2 - value to write\n
{\n
ShiftRight(Add(Arg1,7), 3, Arg1)\n
Name(TEMP, Buffer(Arg1) { })\n
Store(Arg2, TEMP)\n
Add(Arg0, Arg1, Arg1)\n
Store(0, Local0)\n
While (LLess(Arg0, Arg1))\n
{\n
WE1B(Arg0, DerefOf(Index(TEMP, Local0)))\n
Increment(Arg0)\n
Increment(Local0)\n
}\n
}\n
end;
B6: Ta tiến hành viết patch. Tương tự như trường 16 bit và 32 bit việc đầu tiên ta cần làm là xác định đoạn code lỗi nằm ở method nào.
Như ảnh thì ta có thể thấy đoạn code lỗi nằm ở method SMBR. Tiến hành viết patch:
WECB
Cú pháp chung:
into method label <method> code_regex Store\s+((.*),\s+<variableOrig>) replaceall_matched begin WECB(<offset>,<size>,%1) end;
Ví dụ:
into method label SMBR code_regex Store\s+((.*),\s+BDAT) replaceall_matched begin WECB(0x1c,256,%1) end;
Giải thích cú pháp:
into method label SMBR code_regex Store\s+((.*),\s+BDAT): tức là sẽ tìm trong method SMBR đoạn code Store (zero, BDAT) (kí hiệu .* tức là đoạn code sẽ lấy giá trị ở trước trường BDAT trong đoạn code ở DSDT)
replaceall_matched begin WECB(0x1c,256,%1) end;: tức là tất cả đoạn code được tìm thấy ở trên sẽ được thay thế bằng (0x1c,256,zero) (kí hiệu %1 có nghĩa là lấy phần tử T1 trong đoạn code được tìm thấy)
RECB
Cú pháp chung:
into method label <method> code_regex (variableOrig, replaceall_matched begin (RECB(<offset>,<size>), end;
Ví dụ:
into method label SMBR code_regex (BDAT, replaceall_matched begin (RECB(0x1c,256), end;
Giải thích cú pháp:
into method label SMBR code_regex (BDAT,: tức là sẽ tìm trong method SMBR đoạn code (BDAT,
replaceall_matched begin (RECB(0x1c,256), end;: tức là sẽ thay thế tất cả các đoạn code được tìm thấy trong method SMBR bằng (RECB(0x1c,256),
// Patch tay
# RECB
// before
Store (BDAT, Index (Local0, 0x02))
// after
Store (RECB(0x1c,256), Index (Local0, 0x02))
# WECB
// before
Store (Zero, BDAT)
// after
WECB(0x1c,256,Zero)
// Trong đó 0x1c là offset 256 là dung lượng tính bằng bit của trường BDAT
Chú ý:
<offset> là offset mà bạn đã xác định ở B4
<method> là method mà bạn đã xác định ở B6
Sau khi làm xong ta sẽ có:
into method label SMBR code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label SMBR code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
into method label SMBW code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
into method label ECSB code_regex Store\s+\((.*),\s+BDA2\) replaceall_matched begin WECB(0x44,256,%1) end;
into method label ECSB code_regex \(BDA2, replaceall_matched begin (RECB(0x44,256), end;
B7: Apply patch vào DSDT.
B8: Đối với 1 số dòng Asus thì bạn cần thêm patch Logic bug with charging/discharging status
Vì 1 số laptop ASUS có thể gặp tình trạng khi sạc đầy nhưng hệ thống vẫn báo chưa đầy hoặc khi hết pin nhưng hệ thống vẫn báo chưa hết pin dẫn đến các lỗi như sập nguồn bất chợt ( lỗi nãy vẫn có thể xảy ra ở 1 só máy model khác ) cách fix là các bạn add đoạn sau vào
into method label FBST code_regex If\s\(CHGS\s\(Zero\)\)[\s]+\{[\s]+Store\s\(0x02,\sLocal0\)[\s]+\}[\s]+Else[\s]+\{[\s]+Store\s\(One,\sLocal0\)[\s]+\} replaceall_matched begin
If (CHGS (Zero))\n
{\n
Store (0x02, Local0)\n
}\n
Else\n
{\n
Store (Zero, Local0)\n
}
end;
Sau khi làm xong tất cả các phần trên ta sẽ có đoạn patch sau:
#Rename field EC
DT2B, 16 ==> T2B1,T2B2
TAH0, 16, ==> AH01,AH02
TAH1, 16, ==> AH11,AH12
B0C3, 16, ==> B0CX, B0CK
B0SN, 16, ==> B0SX,B0SK
B1SN, 16 ==> B1SX,B1SK
BDAT, 256, ==> DATX
BDA2, 256, ==> DA2X
#16 bit convert 8 bit
into device label EC code_regex DT2B,\s+16 replace_matched begin T2B1,8,T2B2,8, end;
into device label EC code_regex TAH0,\s+16, replace_matched begin AH01,8,AH02,8, end;
into device label EC code_regex TAH1,\s+16, replace_matched begin AH11,8,AH12,8, end;
into device label EC code_regex B0C3,\s+16, replace_matched begin B0CX,8,B0CK,8, end;
into device label EC code_regex B0SN,\s+16, replace_matched begin B0SX,8,B0SK,8, end;
into device label EC code_regex B1SN,\s+16 replace_matched begin B1SX,8,B1SK,8, end;
#into b1b2 method
into method label B1B2 remove_entry;
into definitionblock code_regex . insert
begin
Method (B1B2, 2, NotSerialized) { Return(Or(Arg0, ShiftLeft(Arg1, 8))) }\n
end;
#fix 16 bit error
into method label _BIX code_regex \^\^LPCB\.EC\.B0C3, replaceall_matched begin B1B2(^\^LPCB\.EC\.B0CX, ^\^LPCB\.EC\.B0CK), end;
into method label BIFA code_regex \(B1SN, replaceall_matched begin (B1B2(B1SX,B1SK), end;
into method label BIFA code_regex \(B0SN, replaceall_matched begin (B1B2(B0SX,B0SK), end;
into method label SMBR code_regex \(DT2B, replaceall_matched begin (B1B2(T2B1,T2B2), end;
into method label SMBW code_regex \DT2B\) replaceall_matched begin B1B2(T2B1,T2B2)) end;
into method label TACH code_regex \(TAH0, replaceall_matched begin (B1B2(AH01,AH02), end;
into method label TACH code_regex \(TAH1, replaceall_matched begin (B1B2(AH11,AH12), end;
#Patch 32 bit
into device label EC code_regex (BDAT,)\s+(256) replace_matched begin DATX,%2,//%1%2 end;
into device label EC code_regex (BDA2,)\s+(256) replace_matched begin DA2X,%2,//%1%2 end;
#xác định offset
BDAT: 24 + (8/8) + (5/8) + (1/8) + (1/8) + (1/8) + (8/8) + (8/8) = 28 = 0x1c
BDA2: 64 + (8/8) + (5/8) + (1/8) + (1/8) + (1/8) + (8/8) + (8/8) = 68 = 0x44
#fix 32 bit error
into method label SMBR code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label SMBR code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
into method label SMBW code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
into method label ECSB code_regex Store\s+\((.*),\s+BDA2\) replaceall_matched begin WECB(0x44,256,%1) end;
into method label ECSB code_regex \(BDA2, replaceall_matched begin (RECB(0x44,256), end;
#32 bit field
BTY0, 32, ==> TY01,TY02,TY03,TY04
BTY1, 32, ==> TY11,TY12,TY13,TY14
#32 bit convert to 8 bit
into device label EC code_regex BTY0,\s+32 replace_matched begin TY01,8,TY02,8,TY03,8,TY04,8 end;
into device label EC code_regex BTY1,\s+32 replace_matched begin TY11,8,TY12,8,TY13,8,TY14,8 end;
Lưu ý: Bạn nên trích DSDT ra SSDT theo hướng dẫn tại đây. Vì nếu dùng DSDT thì khi update bios các patch sẽ bị mất tác dụng. Hoặc bạn có thể save file patched.txt lại để apply lại vào DSDT khi update BIOS.
Lưu ý 2: Khi các bạn không thể nào tìm thấy EmbeddedControl trong DSDT tức là pin của bạn không thuộc sự quản lý của EC Controler. Để khắc phục tình trạng này các bạn sẽ tiến hành update bios để cập nhật lại DSDT