Firmware re

IVT
The IVT (interrupt vector table / exception vector table) is an array of addresses, each of which is associated with certain exception number. When an interrupt or exception occurs (this includes power-on reset), the mcu fetches the appropriate address and continues execution at that address. This mechanism is described in detail in the datasheet.

The mcu has a hardware register (vbr) that must be set to the desired IVT location, which can be anywhere in ROM or RAM. At power-on reset vbr is set to zero. Many ROMs use this flexibility to have both a minimal IVT used at power-on, and a secondary IVT for normal use. See Power-on reset code for more details.

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}

LOADER metadata
This " LOADER struct" is a small block of data (roughly 50 bytes), always found relatively near the beginning of the ROM, that contains a few strings:


 * " LOADERxx" such as "LOADER40" etc. Most likely the loader version.
 * "DATABASE"
 * a CPU string such as "SH705513N". This doesn't necessarily indicate the mcu type; some ECUs have 7055 here even though the mcu is a 7058. The last two digits before 'N' seem to always match the CPUcode in the FID struct, and give some insight into the structure of the ROM.

This looks a lot like a type of primary bootloader that would be flashed at the ECU factory, before the final programming is determined. Then, later during manufacturing the final ROM would be reflashed using this bootloader. This is just speculation however.

FID metadata
" FID struct " This is a slightly bigger block of data that I now split in two parts to ease analysis. The first part (FID base) is approximately 60 to 70 bytes long and contains these elements:


 * FID string, for " firmware ID" (my own terminology, I have no official source to confirm what this is). This looks like "5X61BECCNA" and other seemingly random combinations of upper case letters and numbers. So far these strings have not proved to be very unique: some ROMs can be slightly different and still share the same FID, but have a different ECUID.
 * " DATABASE"
 * CPU string + CPU code, such as "SH705822". The first four digits are so far always the type of mcu used. The last two digits (CPU code) are some kind of version number, also giving some insight into the structure of the ROM, in particular of the fields present in the second part of the FID struct.
 * in some cases, MSTCR values. This may be a coincidence - often these values are the same as the ones used at reset to set the MSTCR/SYSCR register (this enables/disables certain peripheral clocks). I have found no code referencing these values directly.

The second half ("RAMF" - my own terminology) is mostly pointers to RAM areas, and in some cases information about checksum areas (see https://nissanecu.miraheze.org/wiki/Checksums ) TODO

Serial comms : SID tree
This is how I call the functions that parse ISO14230 requests. SID stands for service ID, see https://nissanecu.miraheze.org/wiki/Std_14230 and in particular the standards themselves (the SSF version is freely available).

There are two main types of trees: messy and clean. The type of tree is mainly decided by what compiler and compiler options were used, in other words "coin toss". TODO : screenshot of IDA graph view The original source code no doubt contained a few "switch" statements such as

switch (SID_requestnumber) { case 0x1A: ...	case 0x27: .... } With a number of complications: in some operating modes, certain requests are denied (especially during SID27 + SID36 operations).

The messy tree (e.g. CF43D) has all the handling code inlined in one huge function. The clean tree (e.g. 6Z68A) has every SID handler in a separate subfunction; this makes it much easier to see how each handler works.

In every ROM, there are at least two SID trees: a larger one handling all the requests available when connecting normally to the ECU, and a smaller one that may be part of a rescue/production reprogramming mode. Which tree is called depends on a complex selection function, and involves a ridiculous number of global variables and flags.

So far most (all?) 7055 and 7058 ROMs have some interrupt driven code that parses each incoming byte and assembles them into complete 14230 frames. The data part of these frames gets copied at a fixed location in RAM, 0xffff8003. The few bytes at 0xffff8000, before the data payload, contain source/destination addresses (and length?) and usually aren't very important.

Since the first byte the payload is the SID, the handlers work on the subsequent bytes.

Call tables
These ECUs don't use an OS; they mainly use interrupts and large tables of function pointers, polled continuously in a loop. It turns out these call tables are fairly big (often over 100 entries), this is very helpful for delimiting functions and automating code analysis, for example in IDA.

Disassembly analysis and SH assembly patterns
I won't duplicate the info found in the datasheet and the software Manual (read them!!), these are just highlights and tips that aren't immediately obvious. Nissan ROMs are probably compiled with the Renesas "shc" C compiler, which 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.

Function calling convention
Almost every function respects this ABI convention (described in the compiler docs; GCC and Renesas SHC ABIs are compatible):


 * Arguments to functions are passed in r4,r5,r6,r7 as needed;
 * Return values of functions are returned in r0.

Delay slot
This is well explained in the datasheets, but easy to forget when starting out: most branch/jump instructions execute the next opcode before jumping to their destination. Some examples:

bra next_iter mov 0, r0 .... next_iter: more code Easy. r0 gets set to zero before we reach next_iter.

Also very common: mov @(0x66, pc), r2	;r2 = 0x6a24 jsr @r2		;sub_6A24 mov 0x68, r4 Here, as defined by the ABI, the first argument to sub_6A24 is passed in r4.

More confusing: bsr sub_whatever1 mov 0x55, r5	bsr sub_whatever2 mov.w r0, @(0x18, gbr) In this case, the last mov.w is actually storing the return value of the *first* function call (sub_whatever1), just before executing sub_whatever2 !

Interrupt disable/lock
A very common pattern; quick to recognize. The first half updates the IMASK bits in the sr register to disable all interrupts, saving the original IMASK for later. The second half is the exact opposite and restores the IMASK bits. The purpose of this maneuver is to protect a section of code so it runs from beginning to end without interruption.

stc    sr, r0 shlr2   r0 shlr2   r0 and     #h'F, r0 mov     r0, r4	;saving original IMASK to r4 stc     sr, r0 mov.w   @(h'FA,pc), r1 ; [00045BB2] = h'FFFFFF0F and    r1, r0	;useless or     #h'F0, r0	;set IMASK to b'1111 ldc    r0, sr	;update

..... critical code here .....

mov    r4, r0 and     #h'F, r0 shll2   r0 shll2   r0 stc     sr, r2 mov.w   @(h'16,pc), r3 ; [00045BB2] = h'FFFFFF0F and    r3, r2	;clear IMASK bits or     r0, r2	;restore orig imask ldc    r2, sr

stack management
How a stack works is mostly common knowledge and beyond the scope of this page, so I'll skip over the basics. Unlike x86, there are no dedicated push/pop opcodes. To accomplish the same, r15 is used as a stack pointer. Then, in function prologues, this type of code sequence is used to save registers:

mov.l  r13, @-r15 mov.l  r14, @-r15 sts.l  pr, @-r15 stc.l  gbr, @-r15 ...

The "@-" notation means "pre-decrement", so the r15 value is updated before storing each register to the stack area. Then just before returning, the function will restore the regs with the corresponding "@r15+" post-increment operator:

... ldc.l  @r15+, gbr lds.l  @r15+, pr mov.l   @r15+, r14 rts mov.l  @r15+, r13

Note the crafty use of the delay slot !

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

algo
see Checksum algorithms

Checksum functions
For the standard checksum (calculated over the entire ROM), these functions are usually present:


 * main checksum calculation function which computes the sums on a fraction of the ROM and updates the current totals. This function eventually runs a few times before the whole ROM is covered.
 * single step function, where one dword of the ROM is added to the current computation. I assume this is to make a very fast function, maybe called from time-sensitive sections where the main function would take too much time.
 * comparison function, that runs after the current computation is finished, and compares the calculated values with the hardcoded expected values.
 * validation function, checks the result of the comparison and sets some flags and DTCs if necessary.

For the alt1 checksum (TODO

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'.

In both forward (encrypt) and reverse (decrypt) directions, this uses three helper functions, one of which simply swaps data between registers and is common to both directions (the two other helper functions are different for encrypting and decrypting). The swap function is fairly easy to find and leads directly to SID27 and SID36 code.

The details of the algorithm itself are not very important, but are implemented and partly documented in the source code for nisprog CLI tools (TODO : links ?).

The fwd / rev functions, for some reason, don't strictly follow the ABI convention of passing the three first parameters in the r4, r5, r6 registers. Instead they assume the key to be stored in hardcoded RAM locations. Even more, these RAM locations are often the same between ROMs. One set of popular locations is 0xFFFF8416 and 0xFFFF8418, where each half-key is stored and used. Again the details of this aren't very important.

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)

Of keys
Every ROM has a set of three keys, one for SID27 and two for SID36. The SID27 key is used in the first step of the reflashing process for the security handshake.

The first SID36 key is used to decrypt the payload (such as a reflashing kernel) sent from the host, which is then executed from RAM.

The second SID36 key is contained in the ROM, but not used directly by it. It is only copied into a "preload" structure just before running the payload (in effect passing a bunch of parameters to the payload); the original Nissan kernels then retrieve it and use it to decrypt the new ROM payload. This third key is of course only used during a factory reflash, and is not very useful to us.

Some keysets are common to more than one ROM, so far there are a few ways to determine which keyset is used:


 * maintain a list of ECUID - keyset pairs
 * similar ECUIDs often use the same keyset, this can be used to expand the list for new ECUIDs
 * dump the ROM and look for known keys, this often works because some keysets occur frequently
 * dump the ROM and run a key finding utility, this almost always works except for new code patterns that the utility isn't aware of
 * dump the ROM and manually find the keys, a last resort method.

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

DTC
TODO

ADC
TODO

iso14230 Common Identifiers (CID)
TODO

Timer blocks
TODO

Example from CF43D :

loc_25DC:                              ; CODE XREF: INT_ATU31_IMI3A+1AE mov.l  #tmrblock_3BD4, r5	mov     #h'FFFFFFC9, r4	extu.b  r4, r4	mov     r5, r2	add     r4, r2          ; r2= &tmrblock_3bd4 + 0xc9 (end of tmr block) cmp/hs r2, r5	bt/s    finished_3bd4 mov    r5, r6

tb_3bd4_loop:                          ; CODE XREF: INT_ATU31_IMI3A+1EE mov.b  @r6, r2	tst     r2, r2	bt      t3bd4_next      ; b if tmr value was 0 mov.b  @r6, r2	add     #-1, r2         ; dec tmr extu.b r2, r2	mov.b   r2, @r6         ; update tmr value

t3bd4_next:                            ; CODE XREF: INT_ATU31_IMI3A+1DC add    #1, r6	mov     r5, r2	add     r4, r2          ; inc ptr cmp/hs r2, r6	bf      tb_3bd4_loop

finished_3bd4:                         ; CODE XREF: INT_ATU31_IMI3A+1D4

ASCD code
To find the ASCD stuffI started with some code that parsed ADC values, then found an area in RAM where a couple of those values are stored; I already knew (from tracing signals on the PCB) which ADC channel was wired to the ASCD switch, so I just followed references to that channel and ended up in the ASCD stuff.

Now it's easier to just look at the call tables; the ASCD function is always in the same place: the second call table, item number 5 or 6: