1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

NVRAM -- The 16 initial mystery bytes

Discussion in 'Tomato Firmware' started by Planiwa, Apr 5, 2012.

  1. Planiwa

    Planiwa LI Guru Member

    After the Magic Header "FLSH", there are 16 bytes before the start of the settings.
    Code:
    00018000  46 4c 53 48 40 61 00 00  e5 01 19 04 04 01 5a 1a  |FLSH@a........Z.|
    
    Does anyone here know what these 16 bytes might be used for?

    Number of writes? Date of last write? Wear levelling?

    Thanks.
     
  2. mstombs

    mstombs Network Guru Member

    Look in the source - bcmnvram.h

    Code:
    struct nvram_header {
        uint32 magic;
        uint32 len;
        uint32 crc_ver_init;    /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
        uint32 config_refresh;    /* 0:15 sdram_config, 16:31 sdram_refresh */
        uint32 config_ncdl;    /* ncdl values for memc */
    };
    
    Not that it means that much...

    The whole nvram thing is exact opposite to wear levelling, any change committed re-writes the same flash block every time.
     
  3. Planiwa

    Planiwa LI Guru Member

    Thanks. Can we take this one step further, please?
    Let's compare the previous dump with the current one:
    Code:
    46 4c 53 48   40 61 00 00    e5 01 19 04   04 01 5a 1a   2a 16 26 7f
    46 4c 53 48   f8 64 00 00    d6 01 19 04   04 01 5a 1a   2a 16 26 7f
    

    1. len -- length of what, exactly? what is the value, exactly (a 32-bit unsigned integer that starts with F8 looks really, really large; and why is it so different from the previous one? And why are the zeroes at the end?

    2. crc -- 8 bits: ok, this can be useful for determining if it has changed. (although cmp is cheap)
    3. ver -- 8 bits: "01". version of what?
    4. sdram_init -- 16 bits: "19 04" what?

    5. sdram_config -- 16 bits: "04 01" what?
    6. sdram_refresh -- 16 bits: "5A 1A" what?

    7. config_ncdl: 32 bits.

    Looks like not much useful information there -- not even a write-count or a timestamp.
    Looks like only LEN and CRC change.
     
  4. mstombs

    mstombs Network Guru Member

    The length is the nvram flash in use - in little endian form (little end first), your hex viewer should have options for this?

    Your usage gone up from 24896 to 25848 bytes?

    crc is a CRC8 - starts after the crc location.

    Code:
    /* The NVRAM version number stored as an NVRAM variable */
    #define NVRAM_SOFTWARE_VERSION"1"
    The sdram vars are "special SDRAM parameters" they are synched with normal nvram vars

    Code:
    # nvram find sdram*
    sdram_config=0x104
    sdram_init=0x419
    sdram_ncdl=0x7f26162a
    sdram_refresh=0x1a5a
     
  5. Planiwa

    Planiwa LI Guru Member

    Fascinating. So the size "40 61 00 00" is really 0x00004061 which is 24896.
    Now to reconcile 24896:
    Code:
    00018000  46 4c 53 48 40 61 00 00  e5 01 19 04 04 01 5a 1a  |FLSH@a........Z.|
    00018010  2a 16 26 7f 72 72 75 6c  65 30 3d 30 7c 31 33 32  |*.&.rrule0=0|132|
    . . .
    0001e130  5f 61 6e 74 64 69 76 3d  2d 31 00 00 00 00 00 00  |_antdiv=-1......|
    0001e140  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
    
    0x1E140 == 123200
    0x18000 == 98304
    123200-98304 = 24896 indeed.

    Of course this includes the 20 byte header and 6 Nulls at the end to fill out the 8-byte block.

    The current NVRAM has 986 lines with 24840 bytes which adds up to 25826.

    25826 +20 (header) +2 (padding nulls at the end) == 25828.

    So: Number of elements + number of content bytes +20 +(0-7 to make it a multiple of 8) == Size

    Just for fun I did an nvram commit.

    So, we have:

    984 + 24817 = 25801 +20 = 25821 +3 == 25824
    Let's look at the dump:
    Code:
    00018000  46 4c 53 48 e0 64 00 00  b5 01 19 04 04 01 5a 1a  |FLSH.d........Z.|
    
    0x64E0= 25824

    QED :)

    Now, let's try this:

    Code:
      nvram show|tail -1
    984 entries, 25821 bytes used, 6947 bytes free.
    
    I also ran this before the "commit", with identical results.

    Isn't that interesting?!

    The nvram command correctly predicts the size of the NVRAM if it were to be flashed.

    (Some people might assume that it measures the NVRAM, or uses the NVRAM's "LEN", but of course that is not the case. I have some very nice tools to show what is actually the case.)
     
  6. mstombs

    mstombs Network Guru Member

    Looking at the source code it appears there is always 3 NUL's at the end of the nvram, one for final string end, then an extra 2 to mark the end of file, then its padded to fill the last 4-byte block:-

    nvram.c

    Code:
        /* End with a double NUL */
        ptr += 2;
     
        /* Set new length */
        header->len = ROUNDUP(ptr - (char *) header, 4);
     
  7. Planiwa

    Planiwa LI Guru Member

    Ah, very nice. Thanks for this. So there may be from 3 to 6 NULs at the end.
    And size = (elements + bytes + 20 + 2) rounded up to the nearest multiple of 4, if necessary.
     

Share This Page