Skip to content

HOST BSP and Vehicle Coding

Kristiyan edited this page Oct 3, 2026 · 8 revisions

HOST BSP, /tffs0/ Filesystem, and Vehicle Coding

This page covers what's actually running on the RNS510's separate HOST processor, and the real diagnostic protocol the factory uses to configure a unit for a specific vehicle. See SWL Disc: Boot Chain and Build System for how these files get onto the unit in the first place, and Firmware Reversing for FHDD6.FLI's own disassembly. Reader/analysis code: research/swl_5238_reader.py.

HOST\...\H_*.FRG — DECOMPRESSED: the real VxWorks bootrom/BSP source

Every H_*.FRG file (one per vehicle project variant — see the disc structure on the build-system page) hides a real zlib (RFC 1950) stream at a fixed file offset, 16051. zlib.decompress() on it succeeds immediately — no scanning needed once the offset is known. Consumes exactly 497,964 compressed bytes -> 1,573,904 bytes decompressed, byte-identical (same SHA256) across every variant tested (H_PQEE.FRG, H_SB_HDD.FRG, H_SE_DAB.FRG, H_AK.FRG) — one shared image, not a per-variant build. The decompressed bytes open with the same function-prologue signature FHDD6.FLI's own disassembly uses (stwu+mflr); find_prologues() finds 3,079 real prologues in it — genuine, substantial compiled code.

This is the real VxWorks bootrom/BSP (Board Support Package) source for the RNS510 hardware, self-named directly in its own strings: SSW_VW-RNS and (c) 2005 Siemens VDO Automotive AG — the first direct internal evidence tracing this codebase specifically to Siemens VDO Automotive (Continental's predecessor here, acquired 2007; everywhere else this project only ever found "Continental"). Real, dated internal revision-control stamps span 2004-2011, well before this disc's own Sep 2012 build stamp — a long-lived, actively maintained codebase.

Real embedded C source file names: usrStartup.c, usrConfig.c, usrCache.c, usrBreakpoint.c, usbPciStub.c, sysTffs.c (True FFS flash filesystem — the real driver behind the /tffs0/ paths below), sysSerial.c, sysPciManualConfig.c, sysLib.c, sysGpTimer.c, sysGpioDemux.c, sysAta.c (ATA/IDE disk driver — almost certainly what the HDD-equipped variants need this for), ssw_memorymap.c, pca9554LedI2CSlave.c, nvRamToImageIO.c, nvRamToFlash.c, minicoreStubs.c, flashMem.c, bootInit.c, bootConfig.c.

Functionally, this BSP owns: MMU setup and machine-check/exception handling; a full PCI bus scanner/enumerator (M5200 PCI Configuration — the real Freescale MPC5200 chip already identified elsewhere in this project — vendor/device ID and BAR-register dumps, Mediator/CoralP graphics-controller config-space access); video-input source switching — cpdrVideoInSetSource JN/DVD/TV/RVC confirms rear-view- camera/DVD/TV-tuner video-in muxing lives at this layer, driven through real Analog Devices video-decoder chips (ad9883/adv7400) over I2C; flash/NAND image management with real A/B-style rollback versioning (BuildFlashTable, RF_ProcessImage) against a real Samsung NAND part number, K9F12088U0; and a detailed physical memory map (SDRAM/NOR/ NAND/PCI0-2/FPGA/PCMCIA regions, named image slots including InfoLog 1/2, SplashScr, BootLoader 1/2, host img, Bestcomm [Freescale's real MPC5200 DMA engine]). A live interactive VxWorks debug shell is present too (sp adr,args... Spawn a task — real WindShell command help text, matching the sp command literally used in the .WSH scripts below).

Settles HOST vs APPS directly: HOST is the base hardware platform layer — boot, low-level drivers, PCI/flash/video-mux/graphics- chip bring-up, the persistent fault-log store — completely separate from the navicore/dbal map codebase (zero db_*/navicore/ MDCache-family strings appear anywhere in it). APPS (FHDD6.FLI) is the actual navigation/media application logic.

Per-variant differences: the outer .FRG file sizes differ (994,140 / 1,286,592 / 1,855,592 bytes across the 3 tested) purely because of what comes AFTER the shared 497,964-byte compressed BSP stream — a separate, non-zlib, tightly-repetitive-pattern binary region containing exactly one real readable string each: a genuine VW part number (matching the #VwSwPartNumber format already known from VERSION.TXT) plus the literal product-family label "RNS-MID" — almost certainly a per-variant boot splash-screen bitmap, not decoded further.

WA/*.WSH — real VxWorks target-shell scripts, not a custom language

Every cleanup script uses the real WindShell sp xdelete, "<path>" (spawn a task) / rmdir syntax — confirmed against the BSP's own shell help text above. CYCFLAG0.TXT/CYCFLAG1.TXT are each one line, dlpSetCyclicFlag 0/dlpSetCyclicFlag 1.

The real /tffs0/lib/ filesystem tree

DEL_LANG.WSH deletes /tffs0/data/speech/{uvo,synth,recog} — matches INOUT.TXT's own UVO_*.ZIP/LANG_*.FRG(synth)/REC_*.FRG (recog) naming exactly.

DEL_FOLD.WSH deletes /tffs0/FLASH, with a real German comment ("30.04.2008 MaRu # Flash-Ordner wird gelöscht") matching CDSTRUCTTMP.CFG's own changelog entry for this exact file, word for word.

DEL_OUT.WSH (dated 06.07.2010, author RoNe — the same initials as USER.CFG's own <AUTHOR> tag, a real engineer active across at least 2010-2012) references a real internal change-request ID, CR 54634 (a different tracker from the TlaWtz# bug IDs), and deletes ~20 real compiled-module paths — the first direct evidence of the live /tffs0/ lib/ filesystem layout (previously only file-internal debug strings were known, never a real deployed directory tree):

Path What it is
/tffs0/lib/mm/mostgen.out, WMADEC.out, dab.out, servicebroker.out, mpeg4_celp_lib.out, MpegAtaSwitcher.out, ... multimedia modules. servicebroker.out matches the vdo::svc::dispatcher::Dispatcher command/event-dispatch pattern found in FHDD6.FLI's own disassembly (see Firmware Reversing)
/tffs0/lib/pos/pos.out the real positioning/GPS library
/tffs0/lib/arriba/navcore.out first direct confirmation that "Arriba" (previously only ever a bare string count in FHDD6.FLI) is a real product/codebase name — its actual compiled navigation-core module
/tffs0/lib/kernel/libDelayImage.out, fileMgr.out kernel-level modules

FIXCOD.WSH independently confirms and extends this: sp xdelete, "/tffs0/lib/Arriba/dbal.out" — dbal.out (this whole project's single most-studied subsystem) sits in the SAME Arriba/ directory as navcore.out — direct, concrete proof dbal and navcore are sibling compiled modules of the same product line. References /tffs0/data/fwdir/bundles/4 and calls IL_Flush (InfoLog flush — ties to the InfoLog 1/2 flash regions in the BSP above).

Vehicle coding — the real byte-level protocol

The .WSH coding scripts

5 region scripts (EURPQTO.WSH, EURPQTOD.WSH, EURSEDAB.WSH, ESKHDDL.WSH, ESKHDDDL.WSH — dated March 2013, 5 months after the rest of this disc, a later patch) each call SetCoding(0x400, value, offset, width) and SetRegData/ SetRegDataHex(reg, value, ?, width, extra). Comparing all 5 files against each other resolves the real byte layout directly:

Coding-array offset Meaning Values seen
1 manufacturer 0x02=VW, 0x05=Skoda
2 HDD active 0/1
5 Tuner "RUDI" active real internal tuner codename
6 DAB active 0 (EURPQTO/EURPQTOD) / 1 (EURSEDAB/ESKHDDL/ESKHDDDL)
7 SDARS active 0 for EUR everywhere — SDARS is Sirius XM's own formal name, ties to SIRIUS.DB3 (NAR-only)
8 MPEG active 0/1

Plus real register-level commands, identical across all 5 files: SetRegData(0xa91,0,0,2,0x8a) ("Delete Presets"), SetRegDataHex(0x21, "01",0x0,0x1,0x1) ("Testmode: Active"), SetRegDataHex(0x0B3A,"012C", 0x0,0x2,0x89) ("Speed limit DVD/TV: 300km/h" — 0x012C=300 decimal, a real factory-override of the "no video while driving" safety lockout). ESKHDDDL.WSH (Skoda) adds SetRegDataHex(0x0a0a,"01",0x0,0x1,0x1) ("Big VW Splashscreen in NAND: Not Active") — a real per-brand splash-screen selector register.

WA/CTEST.OUT — the ELF tool that implements them, fully disassembled

CTEST.OUT (89,576 bytes) is a real, complete, standalone PowerPC ELF relocatable object (ET_REL, EM_PPC) with a full symbol table — already known to this project as a factory ECU coding/diagnostics test utility (source files CodingTest.c, RegTest.c, ConfigFblockTest.c, ctdt.c). Its symbol table names the exact functions the .WSH scripts above call: SetCoding (.text+2336, 620 bytes), SetRegData (.text+6796, 872 bytes), SetRegDataHex (.text+7668, 1152 bytes), SetRegDataStr (.text+8820, 668 bytes), ReadRegData (.text+5816, 448 bytes), DeleteRegData (.text+6544, 252 bytes), SaveRegData (.text+6264, 280 bytes) — all 7 disassembled with capstone, relocations resolved via .rela.text (real external call targets, not guesses; R_PPC_ADDR16_HI/_LO relocations target the instruction's own 2-byte immediate field, i.e. offset+2 from the instruction start, not the instruction's own address — easy to get wrong on a first pass).

SetCoding(reg, value, offset, width) — real UDS-style "long coding" (Kodierung) byte-array read/patch/write:

  1. The logical register id (0x400) is transformed into the real ECU diagnostic identifier by adding 0x3000 -> 0x3400.
  2. ReadEcuData(status, 1, 0x3400, &buffer, 0xff, 0) reads the current coding byte array.
  3. value (shifted into the correct byte position by width) is copied into buffer[offset] via memcpy — patching exactly width bytes at byte-offset offset, not a bit index.
  4. WriteEcuData(status, 1, 0x3400, &buffer, length, 0) writes the patched array back.

SetRegData/SetRegDataHex/SetRegDataStr/ReadRegData/ DeleteRegData/SaveRegData — a separate register channel through a real 4-slot function-pointer table, pReg: a global object, registered once via svcb_addServiceListener(sServiceReg) on first use, requiring a cached 2-byte global accKey (see the correction below) fetched once through pReg[0x10]. Tracing all 6 of these functions against each other maps pReg out completely — it's a real service vtable, not just a read/write pair:

pReg offset Role Confirmed by
0x00 read ReadRegData, SetRegData, SetRegDataHex, SetRegDataStr
0x04 write SetRegData, SetRegDataHex, SetRegDataStr
0x14 delete DeleteRegData
0x1c save SaveRegData

SetRegData/SetRegDataHex share SetCoding's exact read -> shift- into-byte-position -> memcpy -> write-back shape, just via pReg[0x00]/pReg[0x04] instead of ReadEcuData/WriteEcuData directly. SetRegDataStr is a genuinely different, 2nd write style: instead of a fixed-width integer, it strlen()s the input string, bounds-checks against 0xfe, and memcpys the STRING content directly into the buffer — a variable-length write, not an integer patch. ReadRegData is the pure read half, no patch/write-back.

A real access-control asymmetry, confirmed structurally: Read/ Set* silently call pReg[0x10] to acquire accKey if it's still 0; DeleteRegData/SaveRegData do NOT — if accKey is 0 when either is called, they immediately printf an error and return early, requiring the caller to have already authenticated via a prior Read/Set* call. SaveRegData additionally has the most complex signature in the family: a real 9-argument call to pReg[0x1c] (param1, 2, 0,0,0,0,0, accKey, param2 — the literal 2 is plausibly a record-type/save-mode constant; param2 spills to the stack past the 8 GPR argument registers) — and no .WSH script on this disc actually calls it.

Correction — accKey is NOT a UDS SecurityAccess key. That label was used when first describing this to the user and is wrong, caught 2 ways: accKey is a plain 2-byte .data global — too small for a real seed-key, and unable to hold every possible 5-digit VCDS-style code (65536-99999 doesn't fit a uint16). Decisively, FHDD6.FLI itself has 2 real debug strings using the exact same name in a completely unrelated context — "registry srv %s avail., accessKey: 0x%x" and "...suppData.accesskey %x MASK_EVT %x" — both about a service registering ITSELF with this codebase's own internal message-broker framework, printed as a raw hex handle. A 2nd candidate, checkSecurityAccess, is also unrelated — its surrounding bytes show it's Java's own standard SecurityManager.checkSecurityAccess() (sitting inside java/util/Vector's method list), not anything automotive. accKey is CTEST.OUT's own internal service-registry handle, unrelated to the vehicle's real security code.

The real VCDS-style vehicle Login/SecurityAccess PIN validation was searched for directly and not found in FHDD6.FLI's own load-base-recovered, disassemblable 0-9MB region — resolved since: TpPvVerifyPin (the real PIN-check entry point) DOES exist in FHDD6.FLI, verbatim, at file offset ~82.6MB — inside the already-known 76-85.6MB VxWorks/BSP region (a different linking unit this project's PowerPC load base doesn't cover), and is furthermore confirmed LIVE and callable over a real serial console. This spans a large, separate real investigation (a custom ST10/C166 disassembler for the CAN gateway chip, a byte-level-confirmed EEPROM state machine, the real vehicle-ClusterID pairing design, and the serial-console confirmation) — see Theft Protection, the CAN Gateway, and TpPvVerifyPin for the complete writeup, including a real 26-pin-connector wiring diagram and the commercial SetConfig tool's own "Theft protection"/"PIN verification" coding toggles.

Net result: two genuinely distinct, real UDS (ISO 14229) diagnostic write paths (direct ReadEcuData/WriteEcuData, and the pReg service vtable), both confirmed at the disassembly level with real function names, real argument roles, and the real identifier-namespace offset (+0x3000) — not inferred from the .WSH comments alone.

External validation: a real commercial coding tool

BASE/Other/Setconfig-for-rns510.pdf is a real manual for "SetConfig for RNS510", a commercial third-party coding/diagnostic tool (sold with an FTDI cable). Its "Theft protection"/"PIN verification" coding toggles and PIN read/write field are covered on the Theft Protection page; the rest of what it independently corroborates, from a working tool's own UI against real hardware:

  • Its Coding tab's "Display protocol: BAP" dropdown value confirms BAP is a real, user-facing, independently togglable protocol choice, not only an internal implementation detail (see the BAP protocol section below).
  • Its Logo tab requires a custom boot screen as an 800×480 BMP — a 3rd independent confirmation of the real screen resolution (already found 2 other ways via FHDD6.FLI's own widget-bounds strings; see Firmware Reversing).
  • Its Monitor tab shows a real captured debug log from a running unit, including GW_print and RTDD_PS_VuC_HB — real strings tying directly to the CAN gateway ("VuC") diagnostic protocol.
  • A real, literal # by SetConfig 000015B4 comment was found LEFT BEHIND by this exact tool in one SWL disc's own HDD_20GB/ RNSMIDEC/CONFIG/DLSCRIPT.TXT (build 3810a, BASE/Firmware/) — direct, concrete proof the tool really performs the same SetRegDataHex(0x21,...)/SetRegDataHex(0x0B3A,...) edit documented in the testmode-unlock pattern on SWL Disc: Boot Chain and Build System, caught in the wild rather than only inferred from the manual.

The BAP wire protocol — recovered from a real, working community implementation

BASE/Other/rns510-online-dest-master and rns510-tv-input-master are real C source (SocketCAN, Raspberry Pi target — one ships a prebuilt ARM ELF binary, confirming it's genuinely used) implementing BAP from the PC side: each emulates a MOST-over-CAN "function block" device and talks BAP to a real RNS510 over its CAN bus. The first byte-exact BAP transport this project has examined directly, rather than only inferring the protocol's existence.

Real frame framing: long frames (data_len > 6, ISO-TP-style segmented, but with BAP's own header baked into the start frame rather than ISO-TP's PCI byte) — start frame: byte0 = 0x80 | (len>>8), byte1 = len&0xFF, byte2 = (opcode<<4)|(lsg_id>>2), byte3 = (lsg_id<<6)|fct_id, bytes4-7 = first 4 data bytes; continuation frames: byte0 = 0xC0|(seqno&0x0F), up to 7 more data bytes. Short frames (data_len<=6): byte0 = (opcode<<4)|(lsg_id>>2), byte1 = (lsg_id<<6)|fct_id, remaining bytes = data. opcode(3 bits)/ lsg_id("Logical Service Group", 6 bits)/fct_id(6 bits) — a real 3-level MOST/BAP function-addressing scheme.

Real, distinct CAN IDs per emulated virtual MOST device: the Online Connectivity Unit (lsg_id=0x37, online-destination injection) sends on 0x6FD, listens on 0x6B7; the hybrid-TV-tuner emulator sends on 0x6D3, listens on 0x6C7, and sends its own presence heartbeat on 0x602; both also watch 0x575 (ignition) and 0x661 (radio on/off).

Real function-ID catalogs: OCU (lsg_id=0x37) — GET_ALL=0x01, MOST_CATALOG_VERSION=0x02, FUNCTION_LIST=0x03, FBLOCK_AVAILABILITY=0x04, FSG_CONTROL=0x0D, FSG_SETUP=0x0E, FSG_OPERATION_STATE=0x0F, DESTINATION_LIST=0x10, ASG_CAPACITY=0x11. Hybrid-TV (25 IDs, same FSG_* triad shared — plausibly a real MOST/BAP base-class convention): MOST_CATALOG_ VERSION=0x01 ... TVDISPLAY_NOTIFICATION=0x28 (full list in research/swl_5238_reader.py).

A worked DESTINATION_LIST payload — the field layout is real, the coordinates are NOT: the active example encodes a named destination ("Pacanow", a real Polish town) as length-prefixed name/street/house- number/city/country/postal-code strings plus a 2-byte icon/flag field — a real, concrete template for the on-wire address format. The apparent lat/lon sub-field is proven fake: a 2nd, commented-out example in the same source ("Miekinia", a real, different, far-away Polish town) uses the byte-for-byte IDENTICAL coordinate bytes — two different real places cannot share one real coordinate pair, so these are placeholder/test bytes the tool's author reused, not real geocoded values for either place. Do not spend time trying to fit a fixed-point scale to these specific bytes.

rns510-online-dest-master's own README notes this only works for NAR (North American Region) because VW CarNet was only available there.

A 3rd, standalone Qt/gstreamer DVB-T tuner application (BASE/Other/rns510_dtv-master) was initially assumed to build on this same BAP/MOST mechanism — corrected: its real QMostInterface class does NOT speak BAP at all, despite the name. It instead talks over a plain RS232 UART with its own separate, much simpler custom protocol — out of scope for this wiki (which documents the RNS510 head unit itself, not 3rd-party retrofit hardware's own protocols).

UPDATE, a later session: the real on-unit consumer of BAP phone events (BapPhoneListener), Bluetooth pairing/HFP state, and climate- control/park-distance-control integration was found — all implemented in a substantial embedded Java application layer inside FHDD6.FLI itself (2,806+ real class paths found, e.g. Lvdo/dvc/pdc/impl/parrot/ CT... naming Parrot as the real Bluetooth hands-free module vendor), not in APPS's native PowerPC C++ code or here in HOST's BSP. See The Embedded Java Application Layer for the full writeup.

PQTABLE.FLI/SKTABLE.FLI (GWTABLE.FLI) — the real gateway routing-table header, cracked

These are the real per-platform CAN-gateway routing tables named GWTABLE.FLI internally (see INFO/INOUT.TXT's own manifest), flashed straight to the gateway ECU via LOAD_ECU_BLOCK (see the boot-chain page for that command). A plain hex dump of the first 128 bytes (any build, either table) shows real, readable embedded text: K2L GmbHVer.1.43<hex>. <hex>.<hex>.<hex> 01.43... — K2L GmbH is a real, named third-party automotive CAN/LIN/MOST bus tooling vendor, evidently the real source of the tool that generates these tables. Same AA55 AA55 magic already known from FHDD.FLI's own header (see the boot-chain page) — a real, shared container-format signature across multiple file types on this platform.

The version field is fully decoded: the 4 hex-pair groups in that embedded string (e.g. A5.2A.04.00) are literally the raw header bytes at offset 0x18-0x1B, rendered as dotted hex for a human reading a raw dump — verified byte-for-byte across every build checked. Using this, both tables' real version histories are now known exactly (900=2008-05-29 through 6276_original_update =2014-03-20):

SKTABLE.FLI: A5.2A.02.00 (900) -> A5.2A.03.00 (1300, 2680) -> A5.2A.04.00 (3810 onward, stable)
PQTABLE.FLI: 44.2A.03.00 (900) -> 44.2A.05.00 (1300)        -> 44.2A.09.00 (3810 onward, stable)

PQTABLE.FLI (the main/EU table, first header byte 44) revised more times than SKTABLE.FLI (Skoda-specific, first header byte A5 — plausibly a per-table-type id, not decoded further) over the same period — consistent with it being the more heavily used variant. A direct byte diff between the oldest and newest SKTABLE.FLI versions found 2,764 of 8,192 bytes differ (33.7%) — a real, substantial content revision, not a trivial stamp change. Neither table's real per-entry routing content is decoded at the field level — this closes the header/versioning question, not the full routing-table format.

Reproducing this work

import struct, capstone

with open("H_PQEE.FRG", "rb") as f:
    data = f.read()
payload = zlib.decompress(data[16051:])   # the real BSP image, 1,573,904 bytes

with open("CTEST.OUT", "rb") as f:
    data = f.read()
# Elf32_Ehdr fields after e_ident (16 bytes): '>HHIIIIIHHHHHH'
# .symtab/.strtab/.rela.text section offsets from the section header table
# give SetCoding/SetRegData/SetRegDataHex's real .text offsets directly.

Full narrative and every validation number: research/ swl_5238_reader.py's own module docstring — search for "DECOMPRESSED", "real VxWorks bootrom/BSP", "CRACKED (a still-later session, user-asked \"check the files here\")", "Setconfig-for-rns510.pdf", "rns510-online-dest-master", and "SOLVED: PQTABLE.FLI/SKTABLE.FLI's header format". For TpPvVerifyPin, the CAN gateway, and the theft- protection state machine specifically, see Theft Protection, the CAN Gateway, and TpPvVerifyPin and its own "Reproducing this work" section.

Clone this wiki locally