Firmware re

Power-on reset code
There are two first checks for ROM state :
 * 1) checks for a "NHU\0xF8" signature near the end of the ROM
 * 2) checks for possibly a "ROM_written" flag, also near the end of the ROM.

If either of these checks fail, the ROM boots in a type of Nissan bootloader mode; it seems it would accept a limited set of iso14230 commands, based on static analysis. This is untested.

If the checks succeed, then the code sets the vbr register to point to the secondary vector table. Note : some older ROMs (without the "LOADERxx" metadata structure in the ROM) do not have a secondary vector table at all !

Sasha @ RR posts the following example of signatures in a "MY06 350Z ROM":

ROM:000A79B0 .datab.b h'585D0, h'FF ROM:000FFF80 NissanMarkWritten_byte_FFF80:.data.b 1 ; DATA XREF: ROM:off_2A8�o ROM:000FFF81 .data.b h'FF ROM:000FFF82 .data.b h'FF ROM:000FFF83 .data.b h'FF ROM:000FFF84 NissanSignature_byte_FFF84:.data.b h'4E ; N ; DATA XREF: ROM:off_2A0�o ROM:000FFF85 .data.b h'48 ; H ROM:000FFF86 .data.b h'55 ; U ROM:000FFF87 .data.b h'F8 ; ° It appears Nissan always use those same 4 bytes for all its ROMs {0x4E 0x48 0x55 0xF8}

Disassembly analysis and patterns
Nissan ROMs are possibly compiled with the Renesas "shc" C compiler, and it generates sometimes confusing or obfuscated code sequences. Here are a few:

Sign extension for RAM addresses
Very, very frequent. Put to good use since RAM addresses are often >= 0xFFFF 8000, and the SH "mov" instruction is sign-extending. This allows the compiler to load a 16-bit value (the lower 16bits of the address) from a literal pool, which sign-extends to the desired RAM address, instead of storing the desired 32-bit value in the literal pool. mov.w @(0x60,PC), r11   ;if the 16bit word stored at (PC + 0x60) is 0x8438, this would set r11 = 0xFFFF8438

shll8 to get peripheral register base address
This is most probably due to the fact that peripheral registers are defined as a "struct" in the compiler headers, and the compiler almost always accesses the members by adding the base address of the struct with "offsetof(struct_member)" :

mov 0xFFFFFFF5, r2	;encoded as "mov -0x0B, r2", or "mov -11, r2" ! shll8 r2		; now r2=0xFFFFF500 (&TCNT6A), the base address for the Channel 6 timer ! mov 0, r0 mov.w r0, @(0x10,r2)	; clear 0xFFFF F510 (BFR6A), the actual register we're interested in.

global variable structs
Confusing and inconsistent, some global vars are accessed sometimes with a direct address, sometimes with gbr-based addressing. TODO

Checksums
see Checksum algorithms

EEPROM
see EEPROM access functions

security / encryption
It seems everything uses the same algorithm. Somewhere Nissan calls this algo "01", so I'll use that notation. It operates thus: They are the inverse of each other, i.e. ( rev_01( fwd_01(data, scode), scode) == data )
 * 1) uint32_t fwd_01(uint32_t data, uint32_t scode);   // encodes 'data' using 'scode'.
 * 2) uint32_t rev_01(uint32_t data, uint32_t scode);   // decodes 'data' using 'scode'.

The 01 algo is used for on most known ROMs. Algo description and equivalent C code [posted here].
 * SID 27 key exchange (use "fwd_01" to generate key from seed)
 * SID 36 RAM bootloader kernel download ("rev_01" to decode the payload; fwd_01 was used to encrypt it)
 * SID 36 firmware payload download (rev_01 to decode the payload)

Arbitrary code execution !
Note : this section applies mainly to K-line based ECUs. It's possible some of the steps will work on CAN-only ECUs ?

This is the stepping stone towards reflashing over the OBD K line or CAN interface, without opening the ECU case. Some nice things that could be done :
 * Run a "fastdump" kernel to read out the ROM much faster than the standard K line method
 * Read / write the external EEPROM
 * Reflash all, or part of the ROM

The method is as follows :
 * 1) write / compile payload, either as position-independant code, or linked to run at the ECU's "RAMjump" address.
 * 2) Pad payload to next multiple of 32 bytes
 * 3) Calculate "cks16" : unsigned 16bit sum of all 8-bit bytes of the (unencrypted) payload
 * 4) encrypt payload using "sid36 key 1"
 * 5) Connect to ECU
 * 6) SID 27 seed/key exchange
 * 7) SID 34 80, enter programming mode
 * 8) SID 36 XX YY 0x20 B_00 B_01 B_02... B_31
 * 9) Increment XXYY at every line : "36 00 00 20 ...... 36 00 01 20 ...."
 * 10) SID 37 cks16_H cks16_L TransferExit
 * 11) SID BF 00 ramjump check
 * 12) SID BF 01 actual ramjump.

The payload must be crafted to disable all interrupts and take over the manual generation of the WDT pulse train. Or, it might be possible (if the goal isn't a reflash) to use the firmware's mechanism for the WDT ? i.e. enable a limited set of interrupts, etc)

A very simple test payload that simply freezes the ECU (causing the supervisor to reset it) could look like 00 02	stc	sr, r0	CB F0	or	#h'F0, r0	40 0E	ldc	r0, sr deathloop: AF FE	bra	deathloop 00 09	nop