Branch Privilege Injection (CVE-2024-45332, Paper) je nejnovější bezpečnostní problém procesorů Intel. Intel jej řeší ve včerejším opravném vydání 20250512 mikrokódů pro své procesory. Neprivilegovaný uživatel si například může přečíst /etc/shadow (YouTube).
Dle plánu byl vývoj Firefoxu přesunut z Mercurialu na Git. Oficiální repozitář se zdrojovými kódy je na GitHubu.
V terminálovém multiplexoru GNU Screen byly nalezeny a v upstreamu ve verzi 5.0.1 už opraveny bezpečnostních chyby CVE-2025-23395, CVE-2025-46802, CVE-2025-46803, CVE-2025-46804 a CVE-2025-46805. Podrobnosti na blogu SUSE Security Teamu.
Training Solo (Paper, GitHub) je nejnovější bezpečnostní problém procesorů Intel s eIBRS a některých procesorů ARM. Intel vydal opravnou verzi 20250512 mikrokódů pro své procesory.
Byla vydána nová verze 25.05.11 svobodného multiplatformního video editoru Shotcut (Wikipedie) postaveného nad multimediálním frameworkem MLT. Nejnovější Shotcut je již vedle zdrojových kódů k dispozici také ve formátech AppImage, Flatpak a Snap.
Svobodný elektronický platební systém GNU Taler (Wikipedie, cgit) byl vydán ve verzi 1.0. GNU Taler chrání soukromí plátců a zároveň zajišťuje, aby byl příjem viditelný pro úřady. S vydáním verze 1.0 byl systém spuštěn ve Švýcarsku.
Spolek OpenAlt zve příznivce otevřených řešení a přístupu na 209. brněnský sraz, který proběhne tento pátek 16. května od 18:00 ve studentském klubu U Kachničky na Fakultě informačních technologií Vysokého učení technického na adrese Božetěchova 2/1. Jelikož se Brno stalo jedním z hlavních míst, kde se vyvíjí open source knihovna OpenSSL, tentokrát se OpenAlt komunita potká s komunitou OpenSSL. V rámci srazu Anton Arapov z OpenSSL
… více »GNOME Foundation má nového výkonného ředitele. Po deseti měsících skončil dočasný výkonný ředitel Richard Littauer. Vedení nadace převzal Steven Deobald.
Byl publikován přehled vývoje renderovacího jádra webového prohlížeče Servo (Wikipedie) za uplynulé dva měsíce. Servo zvládne už i Gmail. Zakázány jsou příspěvky generované pomocí AI.
Raspberry Pi Connect, tj. oficiální služba Raspberry Pi pro vzdálený přístup k jednodeskovým počítačům Raspberry Pi z webového prohlížeče, byla vydána v nové verzi 2.5. Nejedná se už o beta verzi.
Dobrý deň,
na Thinkpade P14s gen 2 (21A00003CK) mi seká kurzor ak používam trackpoint. Problém sa prejavuje len v Linuxe.
Štandardne má trackpoint vzorkovaciu frekvenciu 80Hz. Keď sa priblížim rukou k touchpadu, alebo sa ho dotknem zníži sa vzorkovacia frekvencia pod 40Hz.
Predpokladám, že trackpoint dokáže komunikovať cez PS2 protokol a zároveň cez i2c, pričom cez PS2 je kvôli multiplexu s touchpadom obmedzená vzorkovacia frekvencia. Aby som tento predpoklad overil rozobral som notebook a odpojil kábel k touchpadu. Po odpojení však prestal fungovať aj trackpoint (touhpad má neobvykle široký kábel, zrejme má v sebe integrovaný kontrolér, ktorý obsluhuje obe zariadenia, takže odpojenie nepripadá do úvahy).
Trackpoint je obsluhovaný modulom psmouse
. Ovládanie cez /sys
, napr. echo 255 > /sys/devices/platform/i8042/serio1/serio3/sensitivity
je pomalé (0m0,291s) a mám taký pocit, že nefunguje.
V dmesg je:
psmouse serio1: synaptics: Your touchpad (PNP: LEN2073 PNP0f13) says it can support a different bus. If i2c-hid and hid-rmi are not used, you might want to try setting psmouse.synaptics_intertouch to 1 and report this to linux-input@vger.kernel.org.
Keď zavediem modul psmouse s parametrom synaptics_intertouch=1
v logu mám:
psmouse serio1: synaptics: Trying to set up SMBus access psmouse serio1: synaptics: SMbus companion is not ready yet
Modul rmi4_smbus
, ktorý by mal spolupracovať so synaptics trackpointom mám zavedený.
Podľa xinput list
je trackpoint rozpoznaný ako ↳ TPPS/2 Elan TrackPoint id=18 [slave pointer (2)]
Pre istotu som overil, či sú zavedené všetky potrebné moduly jadra pre obsluhu i2c. Keďže i2c nemá podporu pre autodetekciu zariadení musel som sa pozrieť do ACPI. Skopíroval som si teda cp /sys/firmware/acpi/tables/DSDT DSDT
a dekompiloval dekompiloval iasl -d DSDT
. Dekompilované DSDT som hodil na pastebin (pár kB som osekal kvôli limitu na upload).
Zaujímavá je sekcia Scope (_SB.I2CB)
. Podľa nej je zariadenie ELAN901C
pripojené na I2CB
. ID zariadenia je PNP0C50
, čo zodpovedá i2c-hid zariadeniu a malo by byť obsluhované modulom i2c_hid_acpi (jediná správa v kernel logu je i2c-core: driver [i2c_hid_acpi] registered
).
Ďalej vidím, že I2CB má hardware ID AMDI0010
, čo je obsluhované modulom i2c-designware-platform
. Modul je načítaný a registruje zbernice i2c-0
a i2c-1
.
Ďalej vidím na riadku 11912 GpioInt (Level, ActiveLow, ExclusiveAndWake, PullNone, 0x0000
. Tomuto pravdu povediac nerozumiem, ale pre istotu som skompiloval a zaviedol moduly i2c-mux-gpio, i2c-mux-pinctrl, i2c-demux-pinctrl, i2c-mux
. GPIO zariadenie má ID AMDI0030
a malo by byť obsluhované modulom pinctrl-amd
. Modul je zavedený a viem manipulovať GPIO. Odkazovaný pin 5 má podľa gpioinfo status:
line 5: unnamed unused input active-high
Volanie gpioget 0 5
vráti 1, takže predpokladám, že je v stave high. Podľa kódu z DSDT mám pocit, že aktívny stav by mal byť low. Pin je však označený ako vstupný a nemôžem nim manipulovať:
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPIO", 0x00, ResourceConsumer, , ) { // Pin list 0x0005 }
Řešení dotazu:
USB HID zariadenie
Len to nie ;) USB je hrozný protokol. Polling nie je dobrý, hlavne nie, ak je dôležitá aj spotreba.
Inak tu v zásade nič špecifické pre embedded nie je. Konfigurácia prebieha cez ACPI, v embedded je zvyčajne konfiguráia v device tree. Rozhranie I2C bolo v x86 asi od začiatku. HID cez i2c je normálna vec, nie špecifická pre embedded.
Snažím sa debugovať ACPI a objavil som niečo takéto. Ak som správne pochopil, tak metóda _STA vracia 0x0 (zariadenie neexistuje) namiesto 0xf (zariadenie existuje a funguje).
Metóda _STA vyzerá takto:
Method (_STA, 0, NotSerialized) // _STA: Status { If ((TSOS >= 0x70)) { If ((IC1E == One)) { Return (0x0F) } Return (0x00) } Else { Return (0x00) } }
Teoreticky by mala vracať 0xf ak je IC1E 1 a TSOS > 0x70. IC1E je definované v sekcii FRTP ako 1. TSOS by malo byť 75 (definované podľa verzie OS).
Name (TSOS, 0x75) If (CondRefOf (\_OSI)) { If (_OSI ("Windows 2009")) { TSOS = 0x50 } If (_OSI ("Windows 2015")) { TSOS = 0x70 } }
V dmesgu zároveň vidím ACPI: [Firmware Bug]: BIOS _OSI(Linux) query ignored via cmdline
, ale to by nemal byť až taký problém. V každom príade neviem, prečo _STA vracia 0 a tak trochu sa to blbo debuguje.
Opatchoval som DSDT, ale vyzerá, to tak, že ELAN901C
je dotykový display (ktorý nemám) a preto ACPI vracia, že zariadenie neexistuje. V tom prípade, ale neviem kde mám hľadať touchpad / trackpoint :\
Takže hľadám zle. ELAN901C je kontrolér pre dotykové LCD, ktoré nemám, takže z BIOSu dostávam správnu hodnotu.
Rozpitval som trochu ovládač trackpointu pre windows. Podľa ovládača by mal byť výrobca synaptics, ale linux ho identifikuje ako elantech. V zásade je to jedno, pretože detekcia zariadenia slúži len na výpis názvu, ale nič nemení v ovládaní.
Podľa ovládača pre windows vidím, že je tu závislosť na SMBus. Tu som momentálne vážne stratený. Neviem, či SMBus vôbec funguje. V každom prípade v logu mám:
[ 0.349576] ACPI: \_SB_.PCI0.SMB1: Unsupported CMI method: _STA [ 0.349629] piix4_smbus 0000:00:14.0: Using IRQ for SMBus [ 0.349630] piix4_smbus 0000:00:14.0: SMBus Host Controller at 0xff00, revision 15 [ 0.349632] piix4_smbus 0000:00:14.0: Using register 0x02 for SMBus port selection [ 0.349652] i2c_dev: adapter [SMBus PIIX4 adapter port 0 at ff00] registered as minor 2 [ 0.349658] i2c i2c-2: adapter [SMBus PIIX4 adapter port 0 at ff00] registered [ 0.349702] i2c_dev: adapter [SMBus PIIX4 adapter port 2 at ff00] registered as minor 3 [ 0.349705] i2c i2c-3: adapter [SMBus PIIX4 adapter port 2 at ff00] registered [ 0.349720] piix4_smbus 0000:00:14.0: Auxiliary SMBus Host Controller at 0xff20 [ 0.349734] i2c_dev: adapter [SMBus PIIX4 adapter port 1 at ff20] registered as minor 4 [ 0.349737] i2c i2c-4: adapter [SMBus PIIX4 adapter port 1 at ff20] registered
V dekompilovanom DSDT ale metódu _STA vidím:
Scope (_SB.PCI0) { Device (SMB1) { Name (_HID, "SMB0001") // _HID: Hardware ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { IO (Decode16, 0x0B20, // Range Minimum 0x0B20, // Range Maximum 0x20, // Alignment 0x20, // Length ) IRQ (Level, ActiveLow, Shared, ) {7} }) Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } } }
Bios najnovší, firmware najnovší. Bez zmeny.
Takže vyzerá, že problém je niekde so zbernicou SMBus. V ovládači psmouse neprejde cez kontrolu:
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY))
Vyzerá, že v systéme nemám SMBus s touto funkciou. V ovládači synapticsu pre windows vidím, že pre AMD by sa mal používať Smb_driver_AMDASFUWP
, pri PCI ID SMB0001
(%SynDeviceDesc% = SynapticsInstallAMDASF, ACPI\SMB0001
). Aký je ekvivalent pre linux?
$ git grep SMB0001 drivers/acpi/acpi_platform.c: {"SMB0001", 0}, /* ACPI SMBUS virtual device */ drivers/i2c/busses/i2c-scmi.c:#define ACPI_SMBUS_MS_HID "SMB0001"
Áno, tie zdrojáky som si pozeral. V acpi_platform je potlačenie varovania pre SMB0001 a v i2c-scmi je skenovanie CMI metód (vyzerá, že nie sú implementované).
Takže pokračujem v hľadaní chyby. SMBus je podľa lspci -nnk
:
00:14.0 SMBus [0c05]: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller [1022:790b] (rev 51) Subsystem: Lenovo FCH SMBus Controller [17aa:5094] Kernel driver in use: piix4_smbus Kernel modules: i2c_piix4, sp5100_tco
Ovládač vyzerá byť normálne inicializovaný:
[ 1265.119221] piix4_smbus 0000:00:14.0: Using IRQ for SMBus [ 1265.119226] piix4_smbus 0000:00:14.0: SMBus Host Controller at 0xff00, revision 15 [ 1265.119228] piix4_smbus 0000:00:14.0: Using register 0x02 for SMBus port selection [ 1265.119324] i2c_dev: adapter [SMBus PIIX4 adapter port 0 at ff00] registered as minor 0 [ 1265.119333] i2c i2c-0: adapter [SMBus PIIX4 adapter port 0 at ff00] registered [ 1265.119386] i2c_dev: adapter [SMBus PIIX4 adapter port 2 at ff00] registered as minor 1 [ 1265.119390] i2c i2c-1: adapter [SMBus PIIX4 adapter port 2 at ff00] registered [ 1265.119405] piix4_smbus 0000:00:14.0: Auxiliary SMBus Host Controller at 0xff20 [ 1265.119426] i2c_dev: adapter [SMBus PIIX4 adapter port 1 at ff20] registered as minor 9 [ 1265.119439] i2c i2c-9: adapter [SMBus PIIX4 adapter port 1 at ff20] registered [ 1557.798611] i2c-core: driver [smbus_alert] registered
Pri pokuse o preskenovanie zariadení dostávam v kerneli výstup:
[ 813.156253] i2c i2c-9: Transaction (pre): CNT=ff, CMD=ff, ADD=ff, DAT0=ff, DAT1=ff [ 813.156259] i2c i2c-9: SMBus busy (ff). Resetting... [ 813.156265] i2c i2c-9: Failed! (ff) [ 813.156272] i2c i2c-9: Probing failed, no device found [ 813.156309] i2c i2c-10: Transaction (pre): CNT=ff, CMD=ff, ADD=ff, DAT0=ff, DAT1=ff [ 813.156313] i2c i2c-10: SMBus busy (ff). Resetting... [ 813.156319] i2c i2c-10: Failed! (ff) [ 813.156325] i2c i2c-10: Probing failed, no device found [ 813.156345] i2c i2c-11: Transaction (pre): CNT=ff, CMD=ff, ADD=ff, DAT0=ff, DAT1=ff [ 813.156349] i2c i2c-11: SMBus busy (ff). Resetting... [ 813.156355] i2c i2c-11: Failed! (ff) [ 813.156355] i2c i2c-11: Probing failed, no device found
Pokračujeme ďalej (aká hlboká je zajačia nora?)
Z výpisu vidíme, že sa používa adresa 0xff00
:
SMBus Host Controller at 0xff00, revision 15
Podľa DSDT z ACPI má mať adresu 0x0B20
Device (SMB1) { Name (_HID, "SMB0001") // _HID: Hardware ID Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { IO (Decode16, 0x0B20, // Range Minimum 0x0B20, // Range Maximum 0x20, // Alignment 0x20, // Length ) IRQ (Level, ActiveLow, Shared, ) {7} }) Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } }
Modul má parameter force_addr:Forcibly enable the PIIX4 at the given address. EXTREMELY DANGEROUS!, ale ten nefunguje s AMD.
Keďže autodetekcia zlyhala, nastavujem smba_en_hi priamo na hodnotu 0x0B
.
Vo výpise kernelu mám teraz správnu adresu a skenovanie zariadenia funguje bez chýb.
i2c_dev: adapter [SMBus PIIX4 adapter port 0 at 0b00] registered as minor 2
i2cdetect -l i2c-3 smbus SMBus PIIX4 adapter port 2 at 0b00 SMBus adapter i2c-10 i2c AMDGPU DM aux hw bus 2 I2C adapter i2c-1 i2c Synopsys DesignWare I2C adapter I2C adapter i2c-8 i2c AMDGPU DM i2c hw bus 3 I2C adapter i2c-6 i2c AMDGPU DM i2c hw bus 1 I2C adapter i2c-4 smbus SMBus PIIX4 adapter port 1 at 0b20 SMBus adapter i2c-11 i2c AMDGPU DM aux hw bus 3 I2C adapter i2c-2 smbus SMBus PIIX4 adapter port 0 at 0b00 SMBus adapter i2c-0 i2c Synopsys DesignWare I2C adapter I2C adapter i2c-9 i2c AMDGPU DM aux hw bus 0 I2C adapter i2c-7 i2c AMDGPU DM i2c hw bus 2 I2C adapter i2c-5 i2c AMDGPU DM i2c hw bus 0 I2C adapter
i2cdetect -q -y 4 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- 1c -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- 2c 2d 2e 2f 30: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70: 70 71 72 73 74 75 76 77
Po vyradení kontroly podpory I2C_FUNC_SMBUS_HOST_NOTIFY
subsystém rmi4 nájde zariadenie, ale niečo ešte nie je v poradku:
[ 272.778401] rmi4_smbus 4-002c: Using Host Notify IRQ [ 272.778402] rmi4_smbus 4-002c: probe [ 272.778403] rmi4_smbus 4-002c: adapter does not support required functionality [ 272.778407] i2c i2c-4: client [rmi4_smbus] registered with bus id 4-002c
Ďalej som vyradil ontrolu I2C_FUNC_SMBUS_HOST_NOTIFY
z rmi_smbus
. Zároveň som vyradil kontrolu prítomnosti IRQ. Vo výpise mám:
[ 3380.608460] rmi4_smbus 4-002c: Using Host Notify IRQ [ 3380.608461] rmi4_smbus 4-002c: probe [ 3380.609338] rmi4_smbus 4-002c: registering SMbus-connected sensor [ 3380.712811] rmi4_f01 rmi4-00.fn01: found RMI device, manufacturer: Synaptics, product: TM3471-030, fw id: 3418235 [ 3380.801834] input: Synaptics TM3471-030 as /devices/rmi4-00/input/input46 [ 3380.814320] serio: RMI4 PS/2 pass-through port at rmi4-00.fn03 [ 3380.816347] i2c i2c-4: client [rmi4_smbus] registered with bus id 4-002c
Takže detekcia zariadenia prebehne v poriadku, model sa načíta, adresy sedia. Problém je, že nefunguje. Predpokladám, že bude problém v chýbajúcom hardvérovom prerušení, takže zariadenie odpovedá na požiadavky, ale nedokáže samo notifikovať. Nie som istý, či ešte z tohto bodu dokážem pokračovať. Nejaké nápady kam a v akej forme poslať informácie o hardvéri, tak aby mali kernel developeri čo najmenej práce s podporou nového hardvéru?
Vďaka, to bude asi najrozumnejšie. Ešte skúsim pozbierať nejaké ďalšie doplňujúce informácie, ak to nebude zložité tak hádam napíšem aj patch. V každom prípade momentálne sa bez pomoci nepohnem keďže som sa zasekol na nefunkčnom IRQ (registrujem devm_request_irq, ale nedostanem ani jedno prerušenie, neviem, či ho musím nejak manuálne odmaskovať, alebo nastaviť niekde flag).
Takže aktualizácia. Zatiaľ som sa nedostal k tomu, aby som problém posunul kernel developerom. V každom prípade na mojom stroji som problém možno vyriešil. V zásade neviem čo som spravil, pretože som toho spravil veľa a neviem, čo nakoniec zabralo. V každom prípade veľa kontrol som zakomentoval, v logoch to vyhadzuje stále chyby ako konflikt pri komunikácii na zbernici, pokus o zmenu senzitivity skončí zablokovaním trackpointu, stabilita ... neviem, zatiaľ pol hodiny funguje a funguje v poriadku. V priebehu zajtrajška musím zostaviť minimálny diff a budem kontaktovať kernel developerov.
Takže som v podstate neurobil nič. Problém je, že to funuje nespoľahlivo. Niekedy po reštarte funguje, niekedy nie, niekedy funguje prvú sekundu po prvom pohybe. Zároveň často znemožňuje hibernáciu. Evidentne je tu nejaký problém pri komunikácii so zbernicou, ale absolútne netuším aký. V každom prípade určite nefunguje detekcia adresy zariadenia, čítanie riadiacich registrov (presnejšie povedané v kóde sú nejaké magické adresy a ja neviem odkiaľ sú, ale dal by som ruku do dverí za to, že sú nesprávne).
Autor to vie, ja asi tiež, ale neviem, či je táto konštanta relevantná aj pre mňa. Síce sa zariadenie hlási s týmto PCI ID, ale na tejto adrese vráti blbosť, takže buď mám nejakú inú revíziu, alebo sa len tvrári ako iný vendor. Problém je, že netuším, kde mám nájsť adresy registrov.
Po dlhšej dobe sa hlásim.
Nikto mi teda neodpovedal, takže v riešení tohto problému zatiaľ pokračujem sám. Ak by mi niekto pomohol, budem rád, ak nie, kľudne táto téma môže slúžiť ako odstrašujúci príklad toho, ako sa lama, ktorá nič nevie o kerneli babre do vecí, do ktorých nemá babrať. Takže o čom si dnes niečo porozprávame? Čo tak:
Detekcia základnej adresy SMBus zbernice
Keď kernel komunikuje so zariadením, musí poznať jeho adresu. V prípade chipserov south bridge 8xx (neviem, či 5850u disponuje práve týmto) ziťuje adresu nasledujúci kód:
outb_p(smb_en, SB800_PIIX4_SMB_IDX); smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX); smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
Funkcia outb_p(data, adresa)
zapíše 1 byte do IO priestoru (môže byť čokoľvek, zariadenie, ROM ...). Opakom je funkcia inb_p(adresa)
, ktorá prečíta 1 byte.
Teraz sa pozrime na magickú koštantu SB800_PIIX4_SMB_IDX
. Na začiatku súboru je definovaná ako:
#define SB800_PIIX4_SMB_IDX 0xcd6
Táto konkrétna adresa pochádza zrejme z AMD BIOS and kernel developer guide. Vo väčšine BKDG je 0xcd6
označená ako PM_Index a o 0xcd7
PM_Data. Napr. strana 733 v tomto manuáli. Podľa tej istej príručky je adresa základného registra SMBus zbernice zapísaná v priestore PM na adrese 1 (strana 984). V niektorých príručkách je to 0x2c, inde 0x2e, inde 0x00. Ja som akurát trafil na príručku, kde je to 0x01, ale správnu adresu nepoznám, pretože najnovšia príručka je pre procesory 15h a ja mám 19h.
Takže doplním do smb_en nejaké číslo, zapíšem, a prečítam z vedľajšej adresy dáta. Možných adries je 256, takže som ich vyskúšal všetky. Všetky vracajú hodnotu 0xff
. Z toho usudzujem, že v novších procesoroch je buď čítanie PM registrov cez IO priestor na inej adrese, alebo nie je implementované vôbec.
Problém so zlou adresou je vyriešený. V nových CPU je možné vypnúť prístup k PM registrom cez IO priestor. Prístup cez MMIO je naďalej funkčný, takže novšie revízie od 51h vyššie by mali používať MMIO.
Zostáva teda problém s chýbajúcim prerušením. Malo by teoreticky stačiť zapnúť SlaveEnable v SMBusSlaveControl registri a nastaviť príslušnú adresu do I2CCommand registra. Problém je, že zápis do I2CCommand registra vôbec nefunguje, čo ma privádza na myšlienku, čo je sakra to zariadenie 0xb20.
Podľa referenčnej dokumentácie od AMD býva štandardne na 0xb20 ASF, nie SMBus. Na tomto linku je moje zdôvodnenie, prečo si myslím, že by mohlo ísť o ASF.
Prečo teda funguje SMBus? Keď pozerám do dokumentácie, tak adresné, command, dátové a stavové registre sú skoro rovnaké, ako má SMBus, takže nie je až tak prekvapujúce, že ovládač SMBusu mi komunikuje s ASF. Riadiace registre však nefungujú. Skúšal som sa teda správať k zariadeniu, ako keby to bolo ASF a používam namiesto SMBusSlaveControl ASFx09 ListenAdr. Zápis 0x2c (adresa synaptics touchpadu / trackpointu) do ASFx09 nemá žiaden efekt, ale pri zápise 0x08 a 0x10 už áno. Pri týchto adresách a inicializácii synapticsu s RMI4 sú generované prerušenia! Teoreticky chápem adresu 0x08, to by mala byť broadcast adresa SMBusu pri použití host notify. Prečo funguje 0x10 netuším. Prerušenia sa generujú v nepravidelných intervaloch, nie sú úplne korelované s dotykmi na touchpade, aj keď mám pocit, že vtedy je prerušení viac. Prerušenia sú generované aj pri bežných prenosoch dá a ja ich neviem rozoznať (nie je tam žiaden príznak, ktorý by naznačoval, že je to prerušenie pri ukončení prenosu, alebo pri udalosti zo slave zariadenia).
Podľa dokumentácie k ASF je zariadenie používané na vzdialenú správu a okrem iného sprístupňuje SMBus. Takže situácia je taká, že komunikácia mi funguje cez ASF rozhranie so synaptics zariadením na I2C adrese 0x2c. Ja by som mal ale komunikovať cez SMBus priamo a to ma privádza na myšlienku, čo ak ovládač SMBusu na adrese 0xb00 nefunguje správne? Čiste náhodou na 0xb00 mám I2C zariadenie na adrese 0x58, čo je presne 2c posunuté o 1 adresu doľava. Náhoda? Neviem, asi sa na to pozriem budúci víkend. Mimochodom v zdrojákoch ovládača je posun adresy v súlade so starou dokumentáciou od AMD (novú nemám).
Malá aktualizácia stavu.
Už viem, že polohovacie zariadenie je pripojené k zbernici ASF, nie SMBus. Základ je síce rovnaký, ale riadiace registre sa líšia.
Takže potrebujem donútiť zariadenie, aby generovalo prerušenia pri aktivite polohovacieho zariadenia. To autonómne vysiela svoju adresu (0x2c) v poli command na broadcast adresu (0x08). Podľa dokumentácie od AMD k ASF (strana 866) by som mal nastaviť ListenAdr
na (0x08 << 1) | 0x01
a bit SlaveIntrListenEn
registra SlaveEn
. Ak je to takto nastavené zariadenie začne autonómne posielať prerušenia.
Dôležitý fakt je, že každá transakcia posiela prerušenie. Aktuálny linuxový ovládač je napísaný pomocou aktívneho čakania (v slučke sa kontroluje bit HostBusy registra HostStatus). Absolútne katastrofálna implementácia, ale chápem, pretože staršie revízie ASF asi nemali prerušenie. Teraz ignorujem, ale ak sa mi podarí vyriešiť zvyšné problém prepíšem celý ovládač tak, aby používal prerušenia.
Ako teda rozlíšiť prerušenia po transakcii a po attention signále? Doteraz som si nevšímal register DataBankSel. No teda všimol som si, že pri autonómnych prerušeniach sú nastavené bity DatabankXFull, ale netušil som čo s tým. Odpoveď je nastavenie SetReadHostDataBank na 0 a nastavenie SetReadRevDataBank na príslušnú banku. Nasledujúce čítanie z registra DataIndex vráti 0x08 (broadcast) a ďalšie čítanie 0x2c (adresa polohovacieho zariadenia). Ok, trochu zjednodušujem, pretože občas mi to vráti zlé dáta, alebo prehodené, ale stáva sa to dosť zriedkavo, takže zatiaľ ignorujem. Teraz už stačí len notifikovať synaptics ovládač, že má aktivitu a všetko teoreticky funguje.
Problém je, že niekoľko krát za sekundu dochádza ku kolízii na zbernici. Inak ASF sa používa aj na také drobnosti, ako vypnutie zariadenia, takže stačí 10 minút nechať takto kolidovať zbernicu a kľudne sa počítač tvrdo vypne, alebo reštartuje (na to stačí poslať špecifických 16 bitov). Problém som sa snažil vyriešiť odstavením Integrated Micro-Controlleru získaním HostSemaphore pred transakciou (to funguje vždy), ale stále dochádza ku kolíziam. Celú transakciu mám ošetrenú čistým softvérovým mutexom + odstavením IMC.
Takže prepísal som všetky používané časti ovládača podľa disassemblovaného ovládača z windowsu. Predpokladám, že prepis je správny, ale nefunguje to, z čoho usudzujem, že kernel robí niečo zle.
V prvom rade ResourceTemplate z ACPI vyzerá takto:
Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { IO (Decode16, 0x0B20, // Range Minimum 0x0B20, // Range Maximum 0x20, // Alignment 0x20, // Length ) IRQ (Level, ActiveLow, Shared, ) {7} })
Dôležité je, že IRQ je level triggered s aktívnym stavom low.
Moja registrácia IRQ handleru vyzerá takto:
retval = devm_request_irq(&dev->dev, dev->irq, piix4_isr, IRQF_SHARED | IRQF_TRIGGER_LOW, "piix4_smbus", piix4_aux_adapter);
Výpis z /proc/interrupts vyzerá takto:
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 0: 110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-IO-APIC 2-edge timer 1: 0 0 0 0 0 0 0 0 0 0 0 3298 0 0 0 0 IR-IO-APIC 1-edge i8042 7: 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 IR-IO-APIC 7-edge piix4_smbus
Kernel síce registruje môj interrupt handler, ale je nastavený ako edge triggered, nie level triggerred.
Súčasný kernel driver používa pre kontrolu stavu aktívne čakanie v slučke. Teda nastaví príslušné registre a v slučke kontroluje, vyčistenie bitu busy. Ja sa snažím prepísať ovládač, tak, aby bol riadený priamo prerušeniami bez použitia aktívneho čakania. Teraz prichádza paradox:
Po spustení prvej transakcie nedôjde k volaniu prerušenia. Pri druhej, tretej atď áno. V prerušení je vždy status 0, teda zariadenie nie je busy, nedokončilo operáciu, neskončilo chybou. Teda v stave, v akom by malo byť pred transakciou. Tak mi to vŕtalo v hlave a pozrel som sa na časovanie:
[ 297.581942] Quick [ 297.581949] isr HostStatus=00
Interrupt handler je spustený o 7µs. Pripomeňme si, čo je vlastne quick write. Na I2C zbernici môže byť niekoľko zariadení. Každé zariadenie má 7-bitovú adresu. Komunikácia s každým zariadením začína tým, že master vyšle start bit, potom adresu, R/W bit a nakoniec čaká na potvrdenie od zariadenia. Ak zariadenie potvrdí príjem, komunikácia môže pokračovať. Quick write príkaz je len odoslanie adresy, čo je veľmi pekne vymyslené, pretože umožňuje enumerovať zariadenia (každé zariadenie, ktoré chce komunikovať musí najskôr odpovedať na svoju adresu). No ok, to som už asi zašiel trochu do detailov.
Takže pošlem 10 bitov a interrupt handler sa spustí o 7µs po spustení druhého a každého ďalšieho zápisu. Z PM registra namapovaného cez MMIO viem, že frekvencia zbernice je 100kHz. Maximálna frekvencia je 1MHz. Ak beriem do úvahy to, čo viem prečítať z registrov, potom minimálny čas do ukončenia transakcie mal byť 100µs. Aj keby zbernica bežala na maximálnej frekvencii, nebolo by to pod 10µs. Takže interrupt handler sa mi spúšťa určite pred spustením transakcie (alebo prejsnejšie povedané po uvoľnení interrupt line), zatiaľ čo vo windowse to funguje po ukončení transakcie. Preto mám neplatný stav a preto zrejme dochádza ku kolíziám, pretože sa snažím vysielať presne v momente, keď sa o to snaží zariadenie.
Otázka znie, prečo kernel ignoruje moju požiadavku o level triggered interrupt?
Vďaka, som rád, že si to aj niekto prečíta ;)
Mimochodom vyše spomenutý problém s prerušeniami ... tak som to skúmal teda ďalej.
Prerušenia na PCI majú aktívnu 0, po inicializácii sú v stave 1 a pri prerušení sa preklopí do 0.
Teraz, drobná analýza, čo sa deje. Pri prvom prenose nedostávam prerušenie vôbec. Pri druhom a ďalších prenosoch dostanem prerušenie, ale pred samotným prenosom, nie po.
Takže budem špekulovať. Povedzme, že body r-1 a r-2 sú body, kde vyčistím interrupt príznak. Body s-1 a s-2 je reálny začiatok prenosu na zbernici. Body e-1 a e-2 sú ukončenie prenosu na zbernici. Takto zrejme vyzerá priebeh signálu.
11111111111111111111111111 111111111111111111 0 1 0 0 1 0 0 1 0 00000000 0000000 | | | | | | r-1 s-1 e-1 r-2 s-2 e-2
Pri dokončení transakcie sa preklápa signál z 1 do 0. Pri začiatku transakcie (alebo presnejšie povedané presne v momente, keď vyčistím interrupt príznak) sa preklopí opäť do 1 a po ukončení transakcie zase do 0. Že je tomu tak nazvedčuje aj to, že prerušenie dostanem po predchádzajúcej transakci aj v prípade keď vypnem zariadenie (teda prepne sa z neaktívneho stavu 0 do aktívne 1).
Linux neberie do úvahy, že ja chcem prerušenie pre aktívny stav v 0. Prečo je tomu tak? Neviem. Informácia o tom, ktorý stav je aktívny je preberaná za APIC subysystému a ten má napevno nastavený aktívny stav 0 ak je prerušenie asociované s PCI zbernicou. U mňa z nejakého dôvodu asociované nie je. V každom prípade po pridaní podmienky if (index == 7) return true
(active low) sa prerušenia aktivujú v správnom čase.
Teraz idem doplniť do prerušenia podporu pre completion a uvidím, čo to spraví. Teoreticky by som potom mohol mať dnes funkčný ovládač, ale to predbieham. Ak by to bola aj pravda, bude to stáť ešte veľa času, kým zistím, prečo kernel neinicializuje správne prerušenia a celkovo ignoruje konfiguráciu IRQ pre SMBus / ASF.
Takže aby som doplnil stav. Je to presne tak, prerušenie bolo generované s nesprávnou polaritou, takže dostával som prerušenia keď som ich nemal dostávať a nedostával keď som ich mal dostávať. Aktuálne to vyzerá tak, že trackpoint funguje stabilne.
Vtipné na tom je, že ten notebook je certifikovaný pre linux ;) Inak bez driveru je v pohode použiteľný, akurát tých necelých 40Hz pre polohovacie zariadenie považujem za slušnú nepríjemnosť, ak pracujem s grafikou.
Zverejnil som aktuálny patch. V zásade to +/- funguje, ale neviem vypnúť generovanie prerušení.
Natočil som aj krátke video.
Aktuálna situácia je taká, že ovládač SMBusu vyzerá byť funkčný. Napriek tomu zaznamenávam veľa konfliktov na zbernici a dostávam cca 1000 prerušení za sekundu keď je zariadenie nečinné.
Aby som presnejšie špecifikoval. Prerušenia sa negenerujú kým neinicializujem touchpad. Počas komunikácie sa samozrejme za každou transakiou spustí prerušenie, ale to je očakávané správanie. Po inicializácii zariadenie nič ďalšie neposiela do prvého dotyku ak mám zapnutú len funkciu F12 (touchpad), alebo automaticky začne posielať host notify správu ak mám zapnutú funkciu F03 (PS2 host).
Pred ďalším textom sa trochu vráťme k prerušeniam. Aby som mal v správnom momente spustenú obsluhu prerušenia musel som zmeniť polaritu aj typ prerušenia z rising edge na level low. Typ edge spúšťa obsluhu prerušenia jediný krát, keď dochádza k zmene stavu z 0 do 1, alebo opačne. Typ level spustí obsluhu prerušenia vždy keď je daná hodnota, takže v mojom prípade keď je low spustí sa obsluha. Ak v obsluhe nevyčistím všetky bity, ktoré zmenili stav interrupt line, spustí sa obsluha znovu a bude sa spúšťať kým nevyčistím všetky bity. Logické odôvodnenie pre veľa prerušení by bolo to, že som zabudol vyčistiť niektorý bit. To som však kontroloval a som si 100% istý, že tu postupujem správne. Ak by som tu mal chybu, prerušenia by sa generovali aj po vypnutí touchpadu.
Momentálne neviem o žiadnej zásadnej chybe mojej úprav SMBus ovldádača. To isté aj RMI4, kde by na vyčistenie vektoru prerušenia malo stačiť prečítanie interrupt status registra (ak to nie je definované inak pri danej funkcii). Ten sa číta pri každom prerušení, ak práve nehýbem kurzorom má hodnotu 0. K funkcii F03 nemám dokumentáciu, takže neviem, či je potrebné urobiť ešte nejakú akciu na vyčistenie interrupt registra. Funkcia F12 je zdokumentovaná a príslušné registre, ktoré sa musia čítať na vyčistenie registra sa čítajú.
Jednotlivé I2C signály sú dostupné aj cez GPIO. Skúšal som napísať malý program buď priamo s gpio.h z kernelu, alebo knižnicou gpiod, ale nebolo to moc rýchle. Skúšal som izoláciu CPU a spustiť s najvyššou možnou prioritou, ale kernel mi proces aj tak prerušoval. Nakoniec som si napísal kus kódu do kernelu, ktorý číta GPIO a zaznamenáva ich do bufferu. Síce tiež neviem vynútiť presné časovanie, ale je to dostatočne presné, aby som videl, čo sa deje na zbernici (chyba sa vyskytuje v asi 1/50 bitoch).
Na prvom obrázku je pekne vidieteľné, že najskôr synaptics posiela najskôr 2 byty (adresa 0x08 - SMBus nost, vlastná adresa 0x2c / 0x58). Následne ovládač RMI4 prečíta interrupt status (posledné 2 byty, zvyšok je status a adresa registra, registre sú v RMI4 premapované). V druhom obrázku je komunikácia priblížená na jednotlivé bity. Tretí obrázok je oddialený. Občas sa tam nachádzajú krátke 1-bytové zápisy. Tie sa vyskytujú len preto, že počas komunikácie v režime mastra vypínam spracovanie signálov zo slave a prepnutie chvíľu trvá, takže synaptics len vyšle adresu a SMBus host neodpovie. V zásade toto môžem zmeniť a na zbernici budú vždy len dlhé zápisy (pretože host bude akceptovať notifikáciu vždy). Trochu stúpne počet kolízií, ale inak žiaden rozdiel.
Takže podľa dokumentácie robím všetko správne, ale synaptics stále posiela attention signál. Asi čas na to, aby som kontaktoval ľudí okolo synapticsu. Buď to bude chyba firmvéru, alebo nový firmvér používa iný spôsob vyčistenia vektoru prerušenia.
Takže prešlo pár týždňov a dozvedel som sa maximálne tak, že synaptics má podobné problémy aj vo windowse. Nuž čo čakať od zariadenia, ktoré má dlhú kapitolu o spontánnom resete. Fakt kvalita. Dovolím si malú citáciu z Lenovo fóra:
I'll forward those on to Synaptics as well in case it's useful - though it sounds like it matches what they're looking at but there are some interesting pieces in there with the interrupts being so bad. Synaptics have asked me not to discuss their investigation details publicly and I'm respecting that.
I will note that my understanding is that this issue is impacting Windows too.
Okrem toho som sa babral v PS2 kóde synapticsu. Našiel dokumentáciu k všetkým bitom synaptics módu okrem bitu 5. Tak som ho teda nastavil a zrazu nič nefunguje a PS/2 hlási chyby v protokole. Reloadnem psmouse a touchpad je preč. Normálne chýba na PS/2 zbernici. Zostal len trackpoint so stabilnou reporting rate 100Hz. Tak teda reštartujem systém a v biose nejde touchpad. Reštartujem do windowsu a vo windowse nejde touchpad. Reštartujem do linuxu a v linuxe žiaden touchpad ;) Toto som teda hľadal.
Potom som našiel dokument Synaptics PS/2 TouchPad Interfacing Guide. Na strane 39 je bit 5 označený ako Transparent Mode, teda prenáša PS/2 príkazy priamo a nemultiplexuje ich s touchpadom. Zároveň je tam aj špeciálny príkaz, ktorým sa touchpad dá vrátiť do normálneho stavu. Tak som teda napísal malý patch a tadaaa, funguje to super.
Za mňa je tento problém vyriešený, samozrejme plánujem dopracovať aj ovládač SMBusu / ASF, ale tam zatiaľ narážam na chybu BIOSu, takže čakám až ju Lenovo opraví. Potom sa skúsim poradiť s kernel developermi, či by to bolo lepšie spraviť ako rozšírenie i2c-piix4.c, alebo ako úplne nový ovládač napr. i2c-kerncz.c, pretože je tam veľa špecifického kódu pre AMD kerncz.
Tiskni
Sdílej: