APS Logo APS_TUNING [ ABOUT ] [ BLOG ]
← VISSZA A LOGOKHOZ

Reverse Engineering Bosch ME9/MED9: Állapottartó változók implementálása az NVRAM tükör segítségével

TIMESTAMP: 2026.02.22 | TARGET: BOSCH ME9 / MED9 | AUTHOR: APS TUNING

A modern motorvezérlő egységek (ECU-k) szoftverének módosítása során – például egy többprogramos "Map Switcher" vagy ALS (Anti-Lag System) logika integrálásakor – az egyik leggyakoribb mérnöki kihívás az állapotok perzisztens tárolása. Ha azt szeretnénk, hogy az ECU a gyújtás levétele, majd ismételt ráadása után "emlékezzen" a kiválasztott programra, a memóriakezelés mélyebb megértésére van szükség.

Ebben a bejegyzésben a Ford Focus ST/RS (és számos más típus) Bosch ME9 architektúrájának példáján keresztül vizsgáljuk meg, miért elégtelen a hagyományos RAM használata, és hogyan integrálhatjuk egyedi változóinkat a gyári NVRAM (Non-Volatile RAM) menedzser folyamataiba.

A "Volatile" RAM és a Power Latch fázis korlátai

A legegyszerűbb szoftveres megoldás egy új funkció állapotának (pl. map_selector) tárolására egy fel nem használt külső RAM terület (pl. a 0x80xxxx címtartomány) kijelölése. Futásidőben (runtime) ez a megoldás hibátlanul működik.

A probléma a leállítási szekvenciában keresendő. A gyújtás (Terminal 15) lekapcsolása után az ECU egy úgynevezett Power Latch (utánkeringetés) fázisba lép, amely során a főrelét maga a vezérlő tartja behúzva, amíg be nem fejezi az adatmentési és diagnosztikai folyamatokat. Amikor a főrelé elenged, a processzor tápellátása megszűnik, és a hagyományos RAM területek tartalma törlődik. A következő indításkor a rendszer újra inicializálja a memóriát, így az egyedi állapotok elvesznek.

Miért kerülendő a közvetlen EEPROM írás?

A fenti probléma logikus megoldásának tűnhet a változók közvetlen írása a soros (általában SPI buszon kommunikáló, pl. 95640 típusú) EEPROM chipbe, minden egyes állapotváltozáskor. Ez a megközelítés azonban architektúrális szempontból hibás:

Az OEM Megoldás: A Bosch NVRAM Menedzser és a RAM Tükör

A Bosch szoftvermérnökei a fenti problémákat egy dedikált NVRAM Driver implementálásával kerülték meg. A rendszer a következőképpen operál:

A memóriatérkép felépítését az EEPROM_Block_Descriptor_Table szabályozza. Ez a struktúra definiálja az egyes blokkok azonosítóját (Block ID), a fizikai EEPROM offsetet (nv_offset), a RAM tükör címét (mirror_offset), a gyári alapértékeket tartalmazó Flash címet (const_offset), a hosszt és a Checksum algoritmus típusát (flags).

Rendszerszintű integráció: Változók beágyazása a RAM Tükörbe

Az igazi mérnöki megoldás az, ha a saját változónkat "ráültetjük" egy létező, gyárilag menedzselt blokk RAM tükrére.

Reverse engineering során azonosítható egy megfelelő méretű blokk – például a Block ID 02, amelynek hossza 32 bájt, és a RAM tükre a 0x7FD7D8 címen kezdődik. Ha az egyedi map_selector változónkat ennek a blokknak egy fel nem használt (vagy kevésbé kritikus) offsetjére, például a 0x7FD7F3 címre irányítjuk, az alábbi folyamat megy végbe:

A kritikus láncszem: A Runtime Checksum Frissítése

A fenti metódus egyetlen sebezhetősége a memóriablokkok integritás-ellenőrzése. A Bosch rendszerek ciklikus háttérfolyamatok (NVRAM consistency task) segítségével periodikusan validálják a RAM tükör tartalmát a blokk végén tárolt checksum alapján. Ha a kódunk módosítja a RAM tükröt, de a checksum elavult marad, a rendszer adatsérülést detektál, és a blokkot visszaállítja a Flash-ben tárolt alapértékekre (const_offset), törölve a módosításunkat.

A probléma elkerülése érdekében az érték módosításakor azonnal, inline frissíteni kell a checksumot. A ME9 specifikus ellenőrzőösszeg képlete a legtöbb standard blokk (így a 2-es blokk) esetében:

Checksum = -(Sum + BlockID + 1) & 0xFFFF

Ez a kettes komplemens (Two's Complement) aritmetika sajátosságai miatt PowerPC assembly-ben rendkívül hatékonyan, egy bitfordítással és a Block ID kivonásával implementálható saját patchként:

// SAJÁT INLINE CHECKSUM PATCH
; Előfeltétel: A célváltozó módosítása megtörtént a RAM tükörben
; r13 = SDA Base (0x7FFFF0)
; A 2-es blokk (Block ID: 0x02) hossza 32 bájt (30 bájt adat + 2 bájt CHK)

li      r5, 0               ; Összeg (Sum) regiszter nullázása
li      r6, 0               ; Ciklus index nullázása
subi    r11, r13, 0x2818    ; A Block 2 RAM tükör báziscíme (0x7FD7D8)

calc_loop:
lbzx    r8, r11, r6         ; Következő adatbájt betöltése
add     r5, r5, r8          ; Hozzáadás az összeghez
addi    r6, r6, 1           ; Index inkrementálása
cmpwi   r6, 30              ; Végigértünk a 30 adatbájton?
blt     calc_loop           ; Ha nem, ugrás a ciklus elejére

; --- A Gyári Képlet Számítása: -(Sum + BlockID + 1) ---
xori    r5, r5, 0xFFFF      ; 1. Lépés: Bitwise NOT (~Sum)
subi    r5, r5, 2           ; 2. Lépés: Block ID kivonása: -(Sum + BlockID + 1)

; --- Ellenőrzőösszeg Tárolása ---
sth     r5, 30(r11)         ; A 16-bites Checksum kiírása

A Gyári Bosch Checksum Rutin Kielemezve

Ha visszafejtjük magát a Bosch firmware-t egy decompiler (pl. Ghidra vagy IDA) segítségével, megtalálhatjuk a gyári EEP_checksum kalkulátor rutint is. Bár a szintaxisa és a felépítése elsőre sokkal hosszabbnak és kaotikusabbnak tűnik a mi optimalizált patch-ünknél, a matematikai logika hajszálpontosan megegyezik.

A gyári Bosch EEP_checksum rutin Assembly kódja Ghidra-ban

Nézzük meg, mi történik a motorháztető alatt a képen látható gyári rutinban:

// A GYÁRI KÉPLET AZ EREDETI KÓDBAN
LAB_00033c30:
add     r12, r8, r3      ; r12 = Sum (r8) + BlockID (r3)
addi    r12, r12, 0x1    ; r12 = (Sum + BlockID) + 1
neg     r12, r12         ; r12 = -(Sum + BlockID + 1) -> Kettes komplemens (előjelváltás)
sthx    r12, r4, r7      ; A 16-bites eredmény kiírása (ez automatikusan levágja & 0xFFFF-re)

Mi a különbség a gyári kód és a mi patch-ünk között?
Kizárólag a negáció végrehajtásának módja! A gyári kód a beépített neg (Negate) utasítást használja, ami automatikusan elvégzi az előjelváltást. Mi azért használtunk xori (bitfordítás) és subi kombinációt a saját patchünkben, mert bizonyos szituációkban – amikor "ellopott" (stolen) utasításokat pótolunk – a logikai bitműveletek beillesztése biztonságosabb, mivel ezek kevésbé bolygatják meg a processzor kritikus állapotjelző (Carry) flag-jeit. Matematikailag a kettő tökéletesen megegyezik.

Ennek az egyetlen gyári rutinnak a 100%-os megértése nagyon fontos, mert ez garantálja, hogy az egyedi Map Switcher vagy ALS állapotainkra "emlékezzen" az ECU a motor leállítását követően is.

← VISSZA A LOGOKHOZ