"Du hast ja Alles" - hmmm vielleicht, wenn ich einen Laptop habe.

  • Das ist ja spannender als ein Krimi. Freue mich schon auf die nächste Folge. Technische Hintergründe werden wunderbar erklärt. Deshalb bin ich für die Einführung des Rangs Professor Brumbear.

  • @ebs
    Das wird nix. Nicht weil wir nicht wollen sondern wegen anderer Gründe

  • Besten Dank, läuft auch bei mir. Meine BCM94352ZAE_3 / DW1560 hat die vendor-id 0xa5c (2652) und die product-id 0x216f (8559). Chipsatz: 20702A3.

  • @Brumbaer Du hast ja gar keine Zeit mehr zu arbeiten oder bist schon Rentner ODER hast du deswegen, wegen der Sache hier, gekündigt ? :-)

  • ...oh, das ist gut.


    Ich habe ja schon meinen eigenen USB-Kext für den Coffee-Lake (nach-)gebaut, aber gerade eben ist mir nach Teil 4 nochmal klar geworden, dass ja meine Abhängigkeit von anderen Kexten, wie z.B. den BrcmPatch... und BrcmFirmware... (vielleicht) gar nicht mehr so da ist. Ich kann ja meinen USB-Kext um den notwendigen Treiber ergänzen, da ich nun weiß wo, ich zu suchen habe. Und auf die Idee kommen, falls mein Modell zu neu ist, Vorgänger(treiber)modelle mit auszuprobieren. Dann kann also der USB-Kext entsprechend angepasst auch noch WiFi und BT abdecken. Ein weiterer Schritt in die Unabhängigkeit. ;)


    Und aus Deinem sehr analytischen Herangehen an das Log und die Rücksprungadressen und das Finden von PNP... und _LID nehme ich mit, dass sich für uns das tiefe Buddeln lohnt und man sich dann auch einfach trauen sollte, z.B. so eine Methode auch mal (probeweise) lahmzulegen. Das geht ja dann wieder mit Clover-ACPI-Patch sehr gut.


    Und keine Angst vor langen Hex-Zahlen, die können alle z.B.in den Apple-Taschenrechner (im Programmierer-Modus) einfach reinkopiert werden und dann kann man ganz einfach damit arbeiten (0xffffff7f8450f158 - 0xffffff7f84500000 = 0x0f158 und von dieser Adresse aus führte der Weg ins Licht).


    Na ja, … wenn man nun noch weiß, dass es sowas wie „otool“ gibt und die Syntax kennt, oder „Hopper“ und …


    … oder man fragt doch besser jemanden wie Brumbaer.

    Liebe Grüße aus Berlin

  • WiFi läuft auf dem Lenovo aber (noch) mit FakePCIID und FakePCIID_Broadcom_WIFI, oder?

  • Ja, der Treiber fragt wohl die Register ab und braucht deshalb FakePCIID.

  • Komischerweise wird der Brcm4360-Treiber bei mir mit neueren Clover-Versionen nicht mehr geladen, das Device taucht dann auch nicht mehr im IOReg auf. Mit einer älteren Clover-Version (39irgendwas) funktioniert das mit FakePCIID und FakePCIID_Broadcom_WIFI hingegen prima. Alles unter 10.12.6.

  • Das Leben geht weiter
    Dumdidum war gestern. Das Oberwasser ist zurückgegangen.
    Jetzt, da ich eine Netzwerkverbindung habe, kann ich die Bildschirmfreigabe verwenden.
    Ich mache das gerne, denn ich arbeite am liebsten an meinem großen Rechner.
    Der Bildschirm ist da wo ich ihn gut sehen kann, die Tastatur ist do, wo ich gut tippen kann und das Trackpad ist da, verd. .. wo ist mein Trackpad ?
    Wiedergefunden, in einem ordentlichen Haushalt kommt halt nichts weg.
    Außerdem lassen sich mit der Bildschirmfreigabe mal schnell Dateien kopieren. In diesem speziellen Falle hat die Bildschirmfreigabe den zusätzlichen Vorteil, dass Tastatur und Maus beim ferngesteuerten Rechner nicht per USB angebunden sind. Nach einem Wake funktionieren Tastatur und Maus nicht mehr, obwohl die Geräte noch in der IORegistry stehen. Das externe USB Laufwerk geht interessanterweise noch, BT scheint auch nicht zu gehen. Also mal schnell die Kennung der USB Ports auf extern gestellt und die Gleichstellung von internen und externen USB Anschlüssen belegt.
    Das böse Erwachen lässt sich auch nicht durch das Dunkle Erwachen beeinflussen.
    Hibernatemode, sollte nichts ändern, aber man kann's ja mal versuchen. Man versucht's und es ändert nichts.
    Der Unterschied zwischen in- und externen Gerät ist, dass das externe Gerät ein eigenes Netzteil hat und nicht am internen Akku hängt. Ich will jetzt nicht hängen bleiben, weder am Akku, noch einem Sleep/Wake Problem, also zur Seite geschoben.


    Problemkind
    Ich habe auf mehr als zehn Motherboards macos installiert und noch nie solch eine Anhäufung von Problemen erlebt, sollte irgendetwas bei der Installation auf dem Miix einfach nur so funktionieren, mache ich ein dickes Kreuz in den Kalender.


    (Duracell)Hase oder Meister Lampe ?
    Batterie oder Hintergrundbeleuchtung ? Hintergrundbeleuchtung sollte einfacher sein und ich bin für jedes Erfolgserlebnis dankbar. Aber man bekommt so selten, was man sich wünscht, also Batterieverwaltung.


    Nichts einfacher als das
    "Da legst du das Kext vom Rehabman in den Other Ordner und fertig", habe ich verstanden, ist ja ganz einfach. Nach dem Kext geggoogelt, gedownloaded und in den Other Ordner gepackt, Neustart, Energie sparen öffnen. Ladezustand 0% und ein clicken auf Batteriestatus in der Menüleiste anzeigen setzt den Haken nicht. Sieht nach Brandschutzklasse B1 aus, selbstlöschend.
    Ich merke schon, das wird heute kein Spass.


    Wer lesen kann, ist klar im Vorteil
    Rehabmans Artikel gelesen und da steht irgendwo, dass man die DSDT patchen muss, wenn Felder in der Operationregion des Embedded Controllers länger als 8 Bit sind.
    Also einen Blick in die DSDT werfen.


    Darin Steht Dieser Text


    Treiber greifen auf die Register von Schaltkreisen (Hardware-Register) zu. Die Register sehen nach außen hin aus wie normale Speicherzellen. Aber tatsächlich spiegeln die Bits und Bytes Schaltzustände des Schaltkreises wieder und/oder lösen Vorgänge und Abläufe aus statt sich nur Werte zu merken. Diese Register stehen für gewöhnlich an festen Adressen. So hat jede PCIe Karte einen für ihre Zwecke reservierten Speicherbereich. In diesem gibt es einen festen Bereich für die PCIe Konfigurationsregister. in diesem sind die ersten Register für die VendorId und ProductId vorgesehen.
    Auch einige BIOS-Variablen stehen an festen Speicherstellen.
    Der Befehl OperationRegion erzählt dem BIOS von solchen Speicherbereichen und ermöglicht dadurch den Zugriff auf Systemvariable und Hardware-Register. Wir suchen den OperationRegion Befehl, der den Zugriff auf den Speicherbereich EmbeddedControl ermöglicht, weil Rehabman schreibt, dass es um die geht. EmbeddedControl ist einer von 9 in der ACPI Spezifikation definierten Standardspeicherbereichen. Ein weiterer dieser Bereiche ist PCI_Config, der Zugriff auf die erwähnten Konfigurationsregister erlaubt.
    Ich kann die Lektüre der ACPI Spezifikation nur jedem empfehlen. 1036 Seiten purer Poesie, vollgepackt mit spannender Action und herzzerreißenden Dramen, ein Muß für jeden, jeden .... pfffffff, ich komme später darauf zurück.
    Denen, deren Herz der Spezifikation nicht standhalten würde, sei gesagt, dass der Befehl am Anfang eine Operationregion mit dem Namen ECF2 definiert, die die 255 Bytes ab Adresse 0 im Speicherbereich des EmbeddedControllers belegt.


    Ordnung ist das halbe Leben
    ECF2 ist einfach nur ein Speicherbereich von 255 Bytes. Das macht den Zugriff auf Register, Funktionen und Schaltzustände zwar möglich, aber nicht einfach.
    Mit dem Field-Befehl, kommen Ordnung und Übersichtlichkeit in die Sache. Mit dem Befehl weisst man einzelnen Speicherzellen bzw. Bitbereichen Namen zu, bevorzugt solche, die die Funktion beschreiben.
    Ein Eintrag im Field-Befehl besteht aus dem Register Namen und der Länge des Registers in Bits. Das nächste Register beginnt and dem Bit, das auf das letzte des vorhergehenden Registers folgt. Statt eines Namens kann dort auch ein Offset-Befehl stehen. In diesem Fall beginnt das nächste Register bei Bit 0 des Bytes, das so viele Bytes vom Anfang des Speicherbereichs entfernt ist, wie der Wert in Klammern angibt.


    Die erwähnten Konfigurationsregister, die jeweils 16 Bit lang sind, würden wie folgt definiert und abgefragt.



    Lange Kerls
    Uns interessieren, die Register in der Miix DSDT, die länger als 8 Bit sind. Das sind in der DSDT des Miix 9 Stück. Von denen interessieren uns nur die, die auch benutzt werden. Im Suchfeld von MaciAsl, kann man sehen, wie oft das Suchwort gefunden wurde. Wenn da eine 1 steht, kann man das Register ignorieren. Jedes der 9 Register einmal suchen und es bleiben 6 übrig.
    AML kennt nur wenige "Schreib-Befehle". Store ist einer, wie der Name schon sagt. Store (denWert, nachHier) - speichert den Wert des ersten Parameters im zweiten. Mathematische Operationen können mit zwei oder drei Parametern - Add (das, zudem, speichereHier) - aufgerufen werden. Werden sie mit drei Parametern aufgerufen, so wird das Ergebnis der Operation im letzten Parameter gespeichert. Schauen wir uns die Stellen an, an denen die Register verwendet werden, stellen wir fest, dass die Register in der DSDT immer nur gelesen werden. Alle langen Kerls haben 16 Bit Länge und werden immer nur gelesen. Das macht das Leben einfacher, denn wir müssen uns nur mit Lesebefehlen von jeweils 2 Byte Länge beschäftigen.


    Divide et impera
    Nun kann Apples ACPIInterpreter, wohl an dieser Stelle nicht mit Bitlängen über 8 arbeiten. Also muss man jeden 16 Bit Zugriff in zwei 8 Bit Zugriffe aufteilen und das Ergebnis zu einem 16 Bit-Wert zusammenfügen. Rehabman zeigt eine Möglichkeit, die mir aber nicht liegt. Ich will nicht so viel tippen und jedes Register in zwei zu zerlegen ist umständlich und dann beim Lesen jedesmal beide Teilvariablen anzugeben auch. Details findet man in Rehabman's Hilfethread zum Thema Batterieanzeige.


    Vitamin C
    Ich verwende eine bei C gebräuchliche Methode. Ich lege ein Byte Array über den Speicherbereich und greife darüber auf einzelne Bytes zu. Beim Lesen einer Variable muss ich nur den ersten Offset angeben und ich muss die Original Felddefinition nicht ändern bzw. eine neue anlegen.


    Die Methode, um ein 16 Bit Wort zu lesen, soll RDWD heißen, und hat einen Parameter. den Offset des ersten Bytes vom Beginn der Operationregion:


    Die RDWD-Methode schreibt man in der DSDT, direkt hinter den Field Befehl für die Operationregion ECF2.


    Abstand halten
    Jetzt braucht's nur noch die Offsets der Register. Das ist einfach: Der Offset-Befehl direkt vor ECWR sagt uns, dass ECWR bei Byte 0x80 steht. XX10 ist 8 Bit, ein Byte, weiter also bei 0x81. XX11 wieder 8 Bit weiter, also bei 0x82. XX11 ist 16 Bit lang, somit ist B1DC 2 Byte weiter, bei 0x84.
    Die Liste der Felder mit ihren Abständen (Offsets)



    Nun verwenden wir Suchen und Ersetzen um jeden Aufruf von B1DC, außer dem im Field Befehl, durch RDWD(0x84). Entsprechend geht man bei den anderen Registern vor.


    Bei der Gelegenheit sehen wir, dass die Aufrufe im Gerät BAT0 erfolgen.


    Das ist dann wohl unsere Batterie. BAT0 könnte natürlich auch für Fledermaus 0 stehen, aber wenn mein Leben davon abhängen würde, würde ich eher auf Batterie tippen.
    Warum die Felder B1XX heißen, wenn die Batterie Nummer 0 ist, ist eines der vielen Lenovo Geheimnisse. Es gibt noch mehr BAT Geräte, aber offensichtlich sind sie nur Platzhalter.


    Beim Durchsuchen der SSDTs findet man in der SSDT-8 Zugriffe auf einige der Register. Also muss man auch in der SSDT-8 die Zugriffe durch RDWDs ersetzen. Das passiert ebenfalls mit suchen und Ersetzen. Allerdings muss man die Methode noch zu den Externals Deklarationen hinzufügen, damit MaciASL weiß, dass es sie gibt..

    Code
    1. Schnipp
    2. External (_SB_.PCI0.I2C1.TPL1, DeviceObj) // (from opcode)
    3. External (_SB_.PCI0.LPCB.H_EC, DeviceObj) // (from opcode)
    4. External (_SB_.PCI0.LPCB.H_EC.RDWD, MethodObj)
    5. External (_SB_.PCI0.LPCB.H_EC.B1CI, UnknownObj) // (from opcode)
    6. External (_SB_.PCI0.LPCB.H_EC.B1DC, UnknownObj) // (from opcode)
    7. External (_SB_.PCI0.LPCB.H_EC.B1DI, UnknownObj) // (from opcode)
    8. Schnapp


    Die DSDT im patched Ordner speichern und Neustarten.


    Close, but no cigar
    Die gute Nachricht ist, dass sich das Batteriesymbol in der Menüleiste anzeigen lässt, die schlechte ist, dass der Ladezustand immer 0% ist. Netzteil abgeklemmt, Ladezustand immer noch 0%, hätte ja auch negativ werden können.


    Also gut IORegistry geöffnet.


    Wir sehen Rehabmans AppleSmatBatteryManager wird geladen. Das Gerät ist vom Typ PNP0C0A. Ein kurzer Blick in die ACPI Spezifikation zeigt, dass es sich um eine Control-Method-Battery handelt und keine Smart-Battery wie der Treibername vermuten lässt. Da der Treiber allerdings für Geräte des Types PNP0C0A gedacht ist (siehe Info.plist des Batterie-Kextes), scheint der Batterietyp der gewünschte zu sein.
    Die Spezifikation sagt uns, dass ein Control-Method-Battery Gerät die Methoden _BST und _BIF oder _BIX zum Auslesen der Batteriewerte verwendet.


    Ver_BIXT und zugenäht
    Also ein Kext programmiert, das die Werte eines ACPI Gerätes abfragen kann. Das Teil heißt ACPIRuntime, weil ich schon ein EFIRuntime geschrieben habe, das unter anderem EFI Variablen ausliest.
    ACPIRuntime schreibt die gelesenen Werte als Property in die IORegistry und man kann diese mit dem IORegistryEditor anzuschauen.


    Offensichtlich funktionieren _BST und _BIF, _BIX hingegen gibt's nicht.


    Ich könnte der DSDT eine _BIX Routine hinzufügen, oder erst einmal einen Blick in die Quellen des AppleSmatBatteryManager werfen.
    Sucht man in den Quellen nach _BIX findet man eine ganze Menge, darunter folgendes:



    Das ist offensichtlich die Methode, die die _BIX Methode der Batterie liest. Suchen wir nach getBatteryBIX finden wir nur einen Aufruf der Methode, der Rest gehört zu deren Definition.



    Man sieht, dass getBatteryBIX nur aufgerufen wird, wenn fUseBatteryExtendedInformation wahr ist. Ansonsten wird _BIF verwendet. Also nach fUseBatteryExtendedInformation suchen und wir finden:


    Code
    1. Schnipp
    2. fUseBatteryExtendedInformation = useExtendedInformation->isTrue();
    3. if (fUseBatteryExtendedInformation && kIOReturnSuccess != fProvider->validateBatteryBIX())
    4. fUseBatteryExtendedInformation = false;
    5. Schnapp


    Der Wert hängt von einer anderen Variablen ab und von validateBatteryBIX. Nur anhand des Namens, kann man vermuten, dass in der Methode überprüft wird ob _BIX vernünftige Werte liefert. In unserem Falle wird _BIX das nicht tun, es existiert ja nicht. Der Batterietreiber wird in unserem Falle _BIF verwenden, da validateBatteryBIX false liefern wird und deshalb fUseBatteryExtendedInformation ebenfalls false ist. Das fehlende _BIX is somit nicht unser Problem.


    Spannung
    IORegistry in der linken und die ACPI Spec in der rechten, überprüfe ich ob die Werte in _BST und _BIF Sinn machen. Tun sie. Die Design Voltage ist zwar als unbekannt markiert, aber das ist laut Spezifikation erlaubt.
    Dem aufmerksamen Betrachter mag oben der Eintrag Configuration im AppleSmatBatteryManager aufgefallen sein. Ich bin versucht "ein bisschen spät" zu sagen, aber mir ist er auch nicht früher aufgefallen.


    UseDesignVoltageFor... springt sogleich ins Auge. Also noch mal in den Programmcode geschaut und festgestellt, dass das Kext für die Laufzeitberechnung auf die Design Voltage zurückgreift. Es merkt aber nicht, dass der Design Voltage Wert auf unbekannt steht und schon wird mit -1 multipliziert statt mit 7 irgendwas Volt, es sei denn man lässt das Kext die DesignVoltage ignorieren und stattdessen die aktuelle Batterie Spannung verwenden..
    Also gut in der Info.plist unter Configuration die beiden Uses... auf NO gesetzt.
    Neustart und siehe da: 100%. Dabei fühle ich mich inzwischen als sei meine fast Batterie leer.


    Dann kommt die Hintergrundbeleuchtung eben morgen dran.


    PS.
    Man könnte statt die beiden Uses... zu ändern, natürlich auch in der _BIF Methode einen Wert für die Design Spannung vorgeben. 0x1E00, würde sich anbieten, denn das ist die in _BST angegebene momentane Batteriespannung.
    Man könnte auch AppleSmatBatteryManager so ändern, dass es eine validateDesignVoltageMethode gäbe, mit deren Hilfe dieUses... automatisch auf false gesetzt werden würden, falls die DesignVoltage nicht definiert ist.

  • Da scheint das Lenovo ja in gewisser Hinsicht echt eine Zicke zu sein, dennoch schön zu sehen wie du das Ding “einfach” dazu zwingst. :klatschen:

  • @griven und @al6042 sagt noch mal das mein HP Klingonen Laptop ne zicke ist !!!!


    @Brumbaer Nice Job und immer wieder ein spaß zu lesen

    Mit freundlichen grüssen KayKun

  • Ich bin immer wieder faziniert über die extrem leicht zu lesende Schreibweise trotz der echt kompliziert anmutenden Thematik.
    Bei dem Foto auf der Startseite fiel mir auf, dein Schreibtisch könnte meiner sein ...

  • Du hast echt einen tollen Schreibstil! Macht beim Lesen echt Spaß, auch wenn ich bei vielen Bereichen (mangels Fachkenntnis) kurz aussteigen muss.


    Bin in sehr gespannt was am Ende deiner Odysee dann alles funktionieren wird und drücke die Daumen!

    iMac 15,1 - Gigabyte GA-Z77-DS3H Rev. 1.0
    i5 3750K :: PowerColor RedDevil RX480 8 GB :: 32 GB Ram DDR 3 :: macOS 11.1 @ Clover r5 & Windows 10 Pro
    MacBook Pro 15,4 - Terra Mobile 1550 :: 15,6" FullHD
    i5-8265U :: Intel UHD620 :: 8 GB RAM :: DW1560 :: macOS 10.15.5 @ Clover r5096

    MacBook Pro 8,1 - 13" Anfang 2011 :: MacBook Air 7,2 - 13" Anfang 2015


  • was am Ende deiner Odysee dann alles funktionieren wird


    da würde ich auf 100% wetten, so wie ich den @Brumbaer kenne

    ersthilfe vor ort für altes zeugs (-> laptops) 8)

    berliner häckinTosh.stammTisch am 3.monatsmittwoch im maxFish/kunsthaus ACUD

    der stammtisch in berlin ist WIEDER DA!! nächster termin voraussichtlich: mittwoch 15.9.21, 19.00 uhr

  • Illuminati
    Hintergrundbeleuchtung, ist noch so eine Sache mit der ich mich für gewöhnlich nicht rumschlagen muss. Nach meinen bisherigen Erfahrungen mit dem Miix befürchte ich, dass das eher in die Richtung "Ins Dunkle zu treiben" als in die Richtung "hoch im Licht" geht.


    Und wieder beginnt es mit "das geht ganz einfach". Eine SSDT, um ein PNLF Device zu erzeugen, ein Kext in den Other Ordner und gut ist. Meine Reaktion auf solch optimistische Worte ist ein wissendes, aber gequältes Lächeln.


    Ich bin bei der Recherche über zwei Kexte gestolpert eins arbeitet über ACPI und eins über den Intelchipsatz, beide benötigen ein PNLF Device und beide gelten als überholt. Es gibt allerdings eine Patch Anleitung von rehabman.
    Ich habe die SSDT installiert und zwei Kexte ausprobiert, eins crashte, das Intel basierte funktionierte überraschenderweise.
    Dann erinnerte ich mich, dass es in Clover ein AddPNLF Häkchen gibt, also SSDT raus und Häkchen an, geht immer noch.
    Dann hab ich das Kext auch noch rausgeschmissen und es geht immer noch.
    Dann, und dann, dann war ich verblüfft.
    Hintergrundbeleuchtung durch Clover Häkchen. Weil ich gerade solch eine Erleuchtung hatte, gleich noch die Tastenkombination für die Tastaturbeleuchtung ausprobiert. Die Tastaturbeleuchtung ist scheinbar eine reine Tastaturfunktion und geht deshalb ohne Zutun.
    Direkt im Anschluss stieß ich einen lauten Schmerzensschrei auf, weil ich mir auf die Kinnlade getreten bin, die hat ja auch nichts auf dem Boden verloren. Frau und Kinder kommen angerannt, vom Schmerzensschrei alarmiert. Aber ich umarme sie nur und wir tanzen ausgelassen einen Ringelrein. Noch schnell die Nachbarn auf ein Glas Schampus eingeladen und die Feuerwerksreste von Sylvester verschossen und den Tag im Kalender ganz dick angestrichen. Alles um das Ereignis gebührend zu feiern. Und euch Zweiflern und Kleingläubigen sei gesagt, es gibt auch Dinge bei Installation von macos auf dem Miix, die ganz leicht von der Hand gehen. Na ja, da es um den Miix geht, sollte ich vielleicht erst mal die Finger nachzählen.


    Rückblende
    Nach so einem positiven Erlebnis ist es Zeit einmal innezuhalten und an Vergangenes zu denken. Dazu gehört das _LID Problem. Wir erinnern uns, beim Lesen des Klappenstatus klappte der Mac zusammen und nichts ging mehr. Nun hatten wir gerade die DSDT gepatched, weil macos beim Lesen vom 16 Bit Werten aus dem EmbeddedControl Speicherbereich Schwierigkeiten hatte. Vielleicht, aber auch nur vielleicht, ist das Geklapper ja auch so was. Also schauen wir uns die _LID Methode einmal an.



    Die Methode heißt _LID und hat 0 Parameter, so weit, so gehöft. Die Methode selbst ist eher übersichtlich.
    ECRD macht etwas mit LSTE und wenn das Ergebnis 1 ist, wird 0 zurückgegeben ansonsten 1.
    Die zwei Rückgabebefehle mit Konstanten und das else, sollten keine Problem machen.
    Das lässt uns nur die If-Abfrage. ECRD ist kein Standard AML(ACPI Machine Language) Befehl, muss also eine Methode sein. ECRD, klingt wie "EmbeddedControllerReaD" oder "Elf Clowns Rasen Davon".
    RefOf ist ein AML Befehl und entspricht in etwa dem Adresse-Operator in C. RefOf(LSTE) ist dann sowas wie ein Zeiger auf LSTE. RefOf wird verwendet, wenn man ein Objekt an eine Methode übergeben und sicher gehen will, dass der Wert des Objektes erst in der Methode ermittelt wird. Das ist wichtig, wenn sich der Wert zwischen Aufruf und Abfrage in der Methode, z.B. durch Optimierungen oder asynchrone Ereignisse, ändern könnte. RefOf erzeugt einen fatalen Fehler, wenn es das Objekt nicht gibt. Ein kurzes Suchen in der DSDT findet LSTE.
    LEqual überprüft ob seine beiden Parameter gleich sind.
    Wenn es hier irgendwo knallt, dann muss es in der ECRD Methode passieren, oder die Jungs haben doch noch einen übergebliebenen Böller gefunden. Schauen wir nach was ECRD macht.


    Code
    1. Method (ECRD, 1, Serialized)
    2. {
    3. Store (DerefOf (Arg0), Local0)
    4. Return (Local0)
    5. }


    Weniger ist mehr
    Das ist wirklich nicht viel. DerefOf behandelt den Parameter als Zeiger auf ein Objekt und bestimmt dessen Inhalt. Mit Store wird dieser in einer lokalen Variablen gespeichert und diese zurückgegeben. Somit liest ECRD den Inhalt des Objektes auf das sein Parameter zeigt und gibt ihn zurück. Eine Methode um den aktuellen Wert einer Variablen zu bestimmen. Bei einer normalen Variablen würde man das nicht machen, also handelt es sich vermutlich um ein Hardware Register oder etwas Ähnliches, dass sich jederzeit außerhalb der Programm-Kontrolle ändern könnte.
    DerefOf klappt zusammen, wenn es das Objekt auf das sein Argument zeigt nicht gibt. Aber LSTE gibt es.



    Alte Bekannte
    LSTE ist ein Feld in einem Field-Befehl der Operationregion ECF2. Die kennen wir inzwischen so gut, dass ich sie zum Sektumtrunk hätte einladen können. Wichtig daran ist, dass LSTE demzufolge im Speicherbereich EmbeddedControl liegt und der bei 16 Bit Zugriffen Schwierigkeiten macht.


    Auf die Länge kommt es an
    Aber LSTE ist nur 1 Bit lang und nicht 16. Als Arbeitshypothese behaupte ich, dass Apple nicht nur mit Feldern, die länger als 8 Bit sind Probleme hat, sondern mit allen Feldern, die nicht 8 Bit lang sind.
    Wenn dem so wäre, müssten wir den Zugriff auf LSTE so ändern, dass ein ganzes Byte, statt nur eines Bits, gelesen wird und die anderen 7 Bits verworfen werden.
    Wir könnten nun eine Methode schreiben, die ein Byte liest, so wie wir eine Methode geschrieben haben, die ein Wort (16 Bit) byteweise liest (RDWD) - oder wir lesen statt eines Bytes einfach ein Wort und werfen 15 statt 7 Bit weg. Da letzteres weniger Schreibarbeit ist und wir schon wissen, dass die Methode zum 16 Bit Lesen funktioniert, wählen wir diese.
    Wir brauchen für RDWD die Byteadresse an der das erste zu lesende Byte steht. Direkt vor LSTE steht Offset(0x7F) und schon haben wir die die Byteadresse von LSTE.
    RDWD(0x7F) gibt einen 16 Bit Wert zurück indem LSTE enthalten ist. LSTE hat eine Länge von einem Bit und seine Deklaration folgt direkt hinter einem Offset Befehl. LSTE ist also das erste Bit (Bit 0) in dem Byte an der Adresse 0x7F. Wir lesen 16 Bit der Adresse 0x7F, aber da LSTE das erste Bit an dieser Adresse ist, ist es auch das erste Bit im Wort.


    Maskenball
    Um den Wert einer bestimmten Bitkombination aus einem Wert zu ermitteln, verwendet man ein Verfahren namens Maskierung. Die Maske entspricht der Binärzahl die man erhält, wenn man die interessanten Bits auf 1 setzt. Wir haben 16 Bit und uns interessiert Bit 0. Wie bei anderen Zahlen stehen links die höherwertigen Stellen, Bit 0 ist also ganz rechts 0b0000000000000001. Wandelt man das in eine Dezimalzahl erhält man 1.
    Beim Maskieren führt man eine Und-Verknüpfung zwischen Maske und Wert aus. Alle Bits, die in der Maske eine 0 haben, werden zu Nullen und die anderen Bits nehmen den selben Zustand wie im Ausgangswert an.
    And (RDWD(0x7F), 1) liest die 16Bit aus dem Controller und löscht alle Bits außer dem einen (die Maske für Bit 0 ist 1), das uns interessiert. Das Ergebnis des And-Befehls ist 0 oder 1, ganz so als ob wir nur das eine Bit gelesen hätten.


    Wir ändern unsere _LID Methode in


    DSDT.aml geändert, gespeichert und neugestartet. Und ... vergessen den Patch in der Config.plist abzuschalten ... Auf ein Neues, Neustart, im Clover Menü, Optionen, ACPI, Patch abgeschaltet und .... Tadaah, bootet, kein Crash, kein Crash, kein Crash.
    Klappe schließen und der Bildschirm wird dunkel. Kein Sekt mehr da, so ein Pech, Böller sind auch alle, also nur ruhige gelassene Heiterkeit statt ausgelassener Feierstimmung.
    Ach ja, da wir wissen, dass es funktioniert, können wir den eben erwähnten Patch in Clover abschalten oder entfernen.


    Irgendwas ist immer
    Und irgendwo zwischen Verblüffung und heiterer Gelassenheit stelle ich fest, dass die NVME SSD Schwierigkeiten macht und manchmal hängen Maus und Tastatur beim Systemstart. System auf USB Medium hat scheinbar keine Probleme, wenn denn Maus und Tastatur gehen.
    Habe ich wohl was an der DSDT verbastelt. Also alte und neue DSDT verglichen.


    Alles zu seiner Zeit
    DSDTs und SSDTs liegen in zwei Formaten vor. Als aml oder als dsl Datei. Aml Dateien enthalten ausführbaren, maschinenlesbaren Code. Dsl Dateien enthalten nicht ausführbaren, menschenlesbaren Code. Wenn man eine Datei im dsl Format im patched Ordner ablegt, passiert nichts, denn sie enthält keinen ausführbaren Code.
    Wenn man eine aml Datei in MaciAsl öffnet, erzeugt es intern eine dsl Datei, zeigt sie an und lässt sie uns editieren und beim Speichern erzeugt sie aus der internen dsl wieder eine aml Datei. Das erweckt den Eindruck, dass eine aml Datei und eine dsl Datei für Menschen gleich leicht zu lesen seien. Dem ist nicht so.
    Wenn man zwei DSDTs oder SSDTs vergleicht, sollte man das mit den dsl Versionen tun, denn was Unterschiede in den aml Versionen bedeuten, erkennt nur der Geübte. Deshalb vor dem Vergleich die aml Dateien mit MaciAsl in dsl Dateien umwandeln. Dsl Dateien sind normale Textdateien man kann somit die Text-Vergleichs-App seiner Wahl verwenden.
    Wenn man keine hat, kann man FileMerge verwenden. FileMerge findet man in Xcode im XCode Menü unter Open Developer Tool. FileMerge dient dem zusammenfügen von Dateien, zeigt aber auch die Unterschiede an.
    Natürlich habe ich erwartet, die von Hand gemachten Änderungen zu sehen. Aber da gibt es auch auch unerwartete Änderungen.



    Theorie ...
    Irgendwo im BIOS ist eine DSDT gespeichert und diese wird dann an Clover und von dort an macos übergeben. Ändert man was an den BIOS Einstellungen, wird eine neue DSDT erstellt. Speichert man eine eigene DSDT im patched Ordner, ersetzt Clover die BIOS-DSDT durch die eigene. Das ist kein Problem, solange die Änderung einer BIOS Einstellung nicht eine Änderung in der DSDT bewirkt. Denn diese Änderung wird nicht automatisch in die eigene DSDT übernommen. Dann passen verwendete DSDT und BIOS Einstellungen nicht mehr zueinander.
    ... und Praxis
    Das ist das Konzept. Die Realisation kann im Detail anders aussehen. Z.B. spricht nichts dagegen, dass das BIOS die DSDT bei jedem Start komplett neu erstellt. Was bleibt ist das Problem, dass wenn sich etwas in der vom BIOS bereitgestellten DSDT ändert, die Änderung nicht in der gepatchten DSDT wider gespiegelt wird.
    Hier haben wir solch einen Fall. die Adresse der Operationregion GNVS unterscheidet sich. D.h. sie kann sich ändern und dann stimmen die Adressen aus der BIOS DSDT, die sagt wo GNVS tatsächlich gespeichert ist, und der gepatchten DSDT, die sagt wo GNVS gespeichert wurde als die Kopie der DSDT gemacht wurde, nicht mehr überein und die Zugriffe auf GNVS liefern Müll.
    Die Schreiber von Clover wissen um das Problem und deshalb gibt es die Option FixRegions in den ACPI Fixes.
    "Haaaahh, Haaaahh ! Nimm das du Schurke !", denke ich mir und setze die Option. Neustart, Crash. So leicht lassen sich Schurken wohl nicht aufhalten.


    Plan B
    Das Problem lässt sich lösen indem man die DSDT nicht patched, sondern alle Änderungen in einer neuen SSDT zusammenfasst und dort von der BIOS DSDT aufrufen lässt.
    Aber um in der DSDT etwas in der SSDT aufrufen zu können, muss ich die DSDT patchen, "Katze, Schwanz, und so".
    Die Lösung sind Clover DSDT Patches. Diese werden auf die aktuelle DSDT angewandt. Ohne DSDT.aml in patched Ordner wird das die zum BIOS passende sein. Mit Clover nennt man dann die Methoden um, so dass sie nicht mehr in der DSDT gefunden werden. Dann woanders gesucht und hoffentlich in unserer SSDT gefunden werden.


    Klappe, die dritte
    Nehmen wir als Beispiel die _LID Routine.
    Wir packen sie in eine SSDT.
    Das Gerüst einer SSDT sieht wie folgt aus:

    Code
    1. DefinitionBlock ("", "SSDT", 2, "VonMir", "Brumbaer", 0x00000001)
    2. {
    3. }


    MEINER und Brumbaer sind zwei Strings zur Identifikation des Autors und der Tabelle.
    Der Autor darf sechs Zeichen lang sein, der Tabellenname acht.
    Da Brumbaer 8 Buchstaben lang ist, habe ich ihn als Tabellennamen verwendet. Kein guter Stil. Aber solange man nicht zwei SSDTs mit dem Tabellennamen Brumbaer anlegt, geht das.
    Die 1 am Ende ist die Versionsnummer, die 2 davor schaltet in den 64Bit Mode.


    Kopiert man die _LID Routine in die neue SSDT rein, erhält man:


    Alles ein Frage des Kontextes
    Wenn man von Herrn Meier redet, weiß keiner welcher Herr Meier gemeint ist. Es sei denn man erwähnt Herrn Meier in einem bestimmten Kontext, wie in einer Geschichte über das Büro. Oder man man gibt mehr Details: Herr Meier im Büro, Herr Meier, wohnhaft in ....
    So geht es uns mit unserer _LID Methode. Die _LID Routine gehört "in" den momentanen Kontext auf Englisch Scope. Wenn wir wollen, dass die _LID Routine zu unserem LID0 Gerät gehört, müssen wir entweder den Kontext dorthin verschieben oder _LID mit Wohnort, PLZ, Straße und Hausnummer angeben. Wir entschliessen uns den Kontext, den Scope, zu verschieben. Der Befehl dazu heißt Scope, Zufälle gibt's. Der Scope-Befehl hat einen Parameter, der angibt wohin der Scope verlagert werden soll. Scope(LID0) klingt plausibel, ist aber nur korrekt, wenn der Scope vorher schon auf dem Objekt stand zudem LID0 gehört. Um das wasserdicht zu machen, geben wir als Parameter für den Scope-Befehl, die komplette Adresse inklusive Plz. und Hausnummer an. Allerdings müssen wir sie erst finden.
    In der Seitenleiste zeigt MaciAsl einen Objekt-Baum. Wählt man ein Objekt (_LID) an, wird es im Objekt-Baum markiert. Wenn man nun im Objekt-Baum nach oben wandert und die einzelnen Stufen mit Punkten zu einem Namen verknüpft bekommt man:

    _SB.PCI0.LPCB.H_EC.LID0._LID
    _LID ist die Methode und wir suchen das Objekt zu dem sie gehört bzw. die neue gehören soll. Also ist das Objekt _SB.PCI0.LPCB.H_EC.LID0



    Sofortiges Kompilieren führt zu sofortigen Fehlermeldungen.


    _SB.PCI0.LPCB.H_EC.LID0 ist kein Standardobjekt laut ACPI Spezifikation, und deshalb kennt der Compiler es nicht.
    Für die Methode RDWD gilt das Gleiche.



    Die erste External-Anweisung sagt dem Compiler, dass das Objekt _SB_.PCI0.LPCB.H_EC.LID0 ein Gerät (Device) ist und dass es irgendwo anders definiert wurde.
    Die zweite External-Anweisung sagt dem Compiler, dass das Objekt _SB_.PCI0.LPCB.H_EC.RDWD eine Methode ist und dass sie irgendwo anders definiert wurde.
    Der Pfad vor dem RDWD (_SB_.PCI0.LPCB.H_EC) ist komplett in dem Pfad des Scope-Befehls (_SB.PCI0.LPCB.H_EC.LID0) enthalten, deshalb genügt es RDWD in der _LID Routine zu schreiben.
    Wäre das nicht der Fall hätte man

    Code
    1. Schnipp
    2. If (LEqual (And (_SB_.PCI0.LPCB.H_EC.RDWD (0x7F), One), One))
    3. Schnapp


    schreiben müssen. Über Scope ließe sich mehr sagen, aber ich verweise interessierte an die ACPI Spezifikation.
    Jetzt müssen wir noch dafür sorgen, dass unsere neue _LID Methode auch verwendet wird.


    Raus aus die Kartoffeln, rin in die Kartoffeln
    In der DSDT ist ja schon eine _LID Methode und die muss weg, damit unsere neuere, bessere und schönere Methode verwendet wird. Deshalb verwende wir einen Clover DSDT Patch, um die _LID Routine in der DSDT umzubenennen, denn Clover DSDT Patches können nicht löschen.
    Den Patch haben wir im dritten Artikel gemacht und in diesem Artikel weiter oben, wieder rausgeworfen. Jetzt holen wir ihn wieder rein.


    Für mich sieht ein _LID aus, wie das andere
    Die _LID Routine gibt es nur einmal. Was mache ich denn, wenn es eine Routine mehrmals gibt, wie _DSM oder _CRS ?
    Es gibt in der Clover DSDT Patches Tabelle eine Spalte TgtBridge. Dort kann man eine Kennung eines Gerätes eintragen auf das der Patch begrenzt werden soll. Auch wieder als Hexzahlen. TgtBridge ähnelt dem Scope-Befehl. Dummerweise ist die Funktionalität eingeschränkt, da das nur funktioniert, wenn das zu ersetzende Etwas innerhalb des Device-Befehls der TgtBridge steht. Leider werden Scope-Befehle ignoriert.


    Bei den Battery Patches bietet es sich an die gesamten _BST und _BIF Methoden auszulagern. Wichtig ist immer, das man nichts auslagert, was sich wechselnde OperationRegion-Befehle enthält.
    Und siehe da, alles funktioniert noch und die NVME und Maus/Tastatur-Probleme beim Start sind weg.


    Eine Folge hab ich noch.

    3 Mal editiert, zuletzt von Brumbaer ()

  • Ich freu mich sehr auf die Taschenbuchausgabe für 9,95€ :P

  • Ich würde auch die gebundene Ausgabe nehmen - für gewöhnlich erscheint diese auch früher :D

    iMac19,2: Asus B85M-E, Xeon E3-1230 v3, Sapphire Radeon RX580 8GB, 16GB RAM, Clover 5156, macOS 13.6.4

    MacBookPro11,4: Lenovo Thinkpad W541, i5-4340M, intel HD4600 (+nVidia deaktiviert), 16 GB Ram, Whitelist-BIOS-Mod, Clover, macOS 10.14.6, Windows 10