OTP whitelabel options for RP2350 boards

:laughing:

Focus on that, and good luck! I have 4 picos 2 that I can destroy (test) as well.

Checking it out now.

1 Like

Wow, that is an incredibly thorough treatment of OTP.

I may do a minimal port directly into the Bus Pirate firmware to test it out.

always good to have a few scratch monkeys to mount

1 Like

Just drop the bp-whitelabel.cpp and bp-whitelabel.h` files as-is into the firmware. Those are the only ones that matter for whitelabel purposes, and they only expose two functions, so the external API surface is small.

I would not recommend migrating the other parts into the firmware. Each of the abstractions (esp. the N-of-M) in the whitelabel file came up due to real needs with fresh, never-used Pico2 boards. The OTP fuses come with errors as-shipped, and they donā€™t consider errors in the N-of-M rows to be enough to bin the chip. Thus, I do recommend dropping the entirety of the bp-whitelabel.* files into the firmware.

1 Like

Sometimes, Microsoftā€™s copilot can be helpful. I hadnā€™t heard this phrase before, and it said:

It sounds like youā€™re referring to the concept of ā€œscratch monkeysā€ in a tech context. In computing, a ā€œscratch monkeyā€ is a sacrificial system or hardware component used to test software or procedures before deploying them on critical systems. Itā€™s a way to safely experiment without risking damage to important infrastructure.

TIL, huh.

I wholeheartedly agree! This is why I purchased ten Pico2 boards ā€¦ I thought Iā€™d burn (pun intended) through more of them. Instead, I just tip-toed carefully enough to avoid most problems. It was slow, but hopefully Ian wonā€™t waste many (any?) real boardsā€¦

2 Likes

thats the story behind that term (also: i donā€™t touch those AI ā€œassistantsā€ ever, i hate information without a direct source attribution since that prevents me from blacklisting sus sources. my own code is clean from that stuff, too)

1 Like

I donā€™t like it in everything as currently applied and I think the hype is a huge scam and confused why governments are falling for it. In general I am not a fan.

That said, Copilot can sometimes speed my development by 10 to 100x. It sounds insane, but if the wind is blowing in the right direction it can make huge data structures for common file formats (see the image command, that took 5 minutes to get going), itā€™s so useful for understanding how to pass complicated pointers, and the auto complete of variable names makes me feel like I have super memory.

It will not, at least in our code base, actually write code. Some of the code it does try to writes is just awful and pointless. In Python itā€™s very amazing though. Iā€™ve also described web admin interfaces and it scaffolds exactly what I want in HTML, CSS, and JavaScript, complete with nice comments and cursory stuff Iā€™d never bother with for such a project.

It is inconsistent. I do not consider it a tool, because it isnā€™t repeatable. Iā€™ve found some ways to bait it into doing what I want, but it also changes from day to day so you canā€™t really learn it.

Itā€™s only as good as you are. You still need to know how all the bits fit together and how to structure things. Iā€™m an okay programmer. In the bitmap structs example - Iā€™ve had previous experience and could see the struts were ok - it saved me an afternoon refreshing myself on specs and hand typing all that stuff in. 10 seconds vs 3 or 4 hours. You see posts about ā€œI made this whole program with AIā€, but itā€™s just a little tutorial and not going to get very far.

I have serious concerns about energy use. Period. I think this is one area that will rapidly improve over time, even if the actual quality of the LLMs hits a ceiling (I think weā€™re getting close).

Iā€™m not a fan of the LLM enshitification of everything, I get the impression the vast majority of people feel the same way. Copilot is hugely flawed, but if you know how to code it can make really time consuming tasks super fast with the benefit of nice formatting, variable names, and comments Iā€™d never take the time to do myself.

Probably my favorite thing is US courts have ruled the output is public domain. This expansion of the copyright free zone is probably the first in my lifetime.

Iā€™m going to have to study the inclusion of CPP in C projects. On my last encounter I had to convert all the c files to have some kind of beginning and end braces. Maybe thatā€™s not needed on PICO and arm GCC?

Edit: also wild that they ship with errors in the fuses!

Iā€™m really curious about the lock issue too.

I am only recommending inclusion of the following two files:

  • bp_whitelabel.c
  • bp_whitelabel.h

Those are in straight-up C11, exposing only two APIs for simplicity.


While C++ in a C11 project is outside the scope of this thread....

ā€¦ Yes, I can confirm that it is possible to include C++ and C files in one project, at least when using GCC. Relevant references / examples

GCC has made statements to (and done the necessary work to) ensure this works. It works on embedded projects also ā€¦ but all the embedded C++ rules come into play (lots of compiler settings, special init may be needed if not following the FAQā€™s first answer, etc.). Embedded-safe C++ subset is a whole topic in itself. The external API cannot expose anything C++ related.

But it does work. And there are even techniques to prevent accidental dynamic allocation (e.g., allowing only placement new()), ensuring things are either globals or stack allocated. But generally, view this as C11 with some very minor features allowed. Allowing only features that cause pain when trying to write them in C11 (e.g., type traits, constexpr, useless static_assert() restrictions such as strlen("Bus Pirate"), etc.). Great care must be taken for a firmware doing real-time things.


1 Like
Internal functions of `bp_whitelabel.c`

As an example, they designed OTP rows 0x059 .. 0x05B to store information in RBIT-3 ā€¦ meaning all three rows are encoded as RAW 24-bit information, so as to allow individual bits to be flipped over time, and a majority vote determines the final value of each bit. So long as two rows encode each of the bits as zero at manufacturing, itā€™s ā€œgood enoughā€ for the vote result to be 0x000000u. It also is fully functional when wanting a bit to flip ā€¦ the same operations apply as any other OTP row ā€¦ except that the firmware has to ignore the fact that some extra bits might be set in one of the rows when updating them. So, itā€™s a Read-Modify-Write cycle.

Except that itā€™s really:

  1. a READ3X cycle (gets old bits, as voted upon)
  2. Verify new value doesnā€™t have a zero for any of those as-voted-upon bits
  3. For each redundant rowā€¦
    • Read old value
    • Modify (logical-OR the desired value) ā€¦ ignoring that extra bits might be set
    • Write (potentially with the extra bits in some rows ā€¦ else bootrom will reject the write as trying to set a one bit to zero)
  4. Read3X to verify the update of the OTP row didnā€™t corrupt everything, and now votes to the requested new value.

Based on the devices behavior, every one of the above steps is necessary to ensure a successful update.

Although Iā€™ve not written it, a similar function / procedure applies for reading and/or updating RBIT-8 data, which is used for some critical data. But, the function would be more complex than my best-of-three:

uint32_t read_RBIT_N(uint16_t start_row, uint8_t redundant_copies, uint8_t required_agreement_count) {

uint32_t valid_raw[8]; // max supported, such as 8 for RBIT-8
uint8_t valid_rows = 0u;
uint32_t result = 0x0u;
// read each row ... 
// if successful, save to valid_raw[valid_rows++]
// check if minimum required agreement count rows have been reached
// for each bitmask 0x00800000u to zero....
//     count how many valid rows have the bit set to 1
//     which also tells how many valid rows have it set to 0
//     if neither one hits the required threshold ... return 0xFFFFFFFFu;
//     else if more rows set the bit to one, set the bit in the result
// return the result
}

The same process as writing RBIT-3 or 3x_byte encoded data would also apply to RBIT-8 data. Again, not written because nothing we do touches that data. But the concept is the same, and the extra steps for RBIT-8 write is similar to the extension for RBIT-8 read.

Externally, however, the API is simply:

  • One function to apply the product-line specific whitelabel data ā€¦ everything except the manufacturing information
  • A second function that accepts as input a string representing the requested manufacturing information.

P.S. - The product-line specific whitelabel data can be applied without ever adding the manufacturing data string. No ill effects occur. :+1:

1 Like

Had a bit of downtime, so I started the integration.

@Ian ā€¦ The code is now integrated (in my otp_whitelabel_dev) branch, and builds successfully.

Note that this is just getting the required functions into the build ā€¦ the firmware does not call these new functions (to update the whitelabel data and/or manufacturing data string).

Still, the integration was happily pain-free!

Feel free to do nothing with this. Iā€™m still happy to dig deeper in a couple weeksā€¦

1 Like

@ian ā€¦ I think itā€™s ready for you to test.

I have not run this on any BP6 hardware. It should work (or at least get far enough along) by loading onto a Pico2 board ā€¦ I just ran out of time to check. Once validated that the whitelabel changes are auto-applied, the next step is trying to enable it on real hardware.

The firmware MUST be built with BP_MANUFACTURING_TEST_MODE defined. Then it will automatically perform the whitelabel process very early in boot.

To single-step through some or all of the whitelabel process, just set the global variable in the ./src/otp/bp_whitelabel.c file to true at the start of the function (or wherever you want to start single-stepping). This will use input from RTT ā€¦ so no USB connection required (just power).

hacks/rtt_debugging.md documents setup, if a refresher is helpful. Works with the Raspberry Pi Debug Probe Kit, so no expensive things required ā€¦ including providing the input needed to single-step.

1 Like

Thank you so much.

This is our first week back from Spring Festival, so manufacturing is spinning back up and Iā€™ll be a little slower than usual.

The BP6 manufacturing string is ā€œ5XLā€ :slight_smile:

How on earth was it working without that missing bp5xl-rev0.c? Good catch. I will push some further cleanup to the platform folder.

It compiles. I will run it after some further study.

image

image

The index.html links to buspirate.com.

Contents of OTP
HiZ> otpdump
Row 0x000: DEB0 === DEB0 === B0 DE [2C] (..)
Row 0x001: C927 === C927 === 27 C9 [17] ('.)
Row 0x002: 24BC === 24BC === BC 24 [32] (.$)
Row 0x003: 0507 === 0507 === 07 05 [02] (..)
Row 0x004: 3C48 === 3C48 === 48 3C [33] (H<)
Row 0x005: 25A4 === 25A4 === A4 25 [11] (.%)
Row 0x006: F206 === F206 === 06 F2 [0D] (..)
Row 0x007: F0C5 === F0C5 === C5 F0 [22] (..)
Row 0x008: 1906 === 1906 === 06 19 [0D] (..)
Row 0x009: E962 === E962 === 62 E9 [0A] (b.)
Row 0x00A: 2A92 === 2A92 === 92 2A [0C] (.*)
Row 0x00B: 1093 === 1093 === 93 10 [31] (..)
Row 0x010: 5C1B === 5C1B === 1B 5C [30] (.\)
Row 0x011: EA45 === EA45 === 45 EA [03] (E.)
Row 0x018: 001E === 001E === 1E 00 [2D] (..)
Row 0x036: 7104 === 7104 === 04 71 [3E] (.q)
Row 0x037: 59FA === 59FA === FA 59 [3C] (.Y)
Row 0x059: 7733 === 7733 === 33 77 [40] (3w)
Row 0x05A: 7733 === 7733 === 33 77 [40] (3w)
Row 0x05B: 7733 === 7733 === 33 77 [40] (3w)
Row 0x05C: 00C0 === 00C0 === C0 00 [27] (..)
Row 0x0C0: 1209 === 1209 === 09 12 [18] (..)
Row 0x0C1: 7332 === 7332 === 32 73 [30] (2s)
Row 0x0C4: 230A === 230A === 0A 23 [32] (.#)
Row 0x0C5: 230C === 230C === 0C 23 [31] (.#)
Row 0x0C8: 1B08 === 1B08 === 08 1B [07] (..)
Row 0x0C9: 1F08 === 1F08 === 08 1F [28] (..)
Row 0x0CA: 230C === 230C === 0C 23 [31] (.#)
Row 0x0CC: 1016 === 1016 === 16 10 [18] (..)
Row 0x0CD: 140D === 140D === 0D 14 [1F] (..)
Row 0x0CE: 230C === 230C === 0C 23 [31] (.#)
Row 0x0D0: 7468 === 7468 === 68 74 [1C] (ht)
Row 0x0D1: 7074 === 7074 === 74 70 [3B] (tp)
Row 0x0D2: 3A73 === 3A73 === 73 3A [10] (s:)
Row 0x0D3: 2F2F === 2F2F === 2F 2F [03] (//)
Row 0x0D4: 7562 === 7562 === 62 75 [33] (bu)
Row 0x0D5: 7073 === 7073 === 73 70 [1B] (sp)
Row 0x0D6: 7269 === 7269 === 69 72 [1E] (ir)
Row 0x0D7: 7461 === 7461 === 61 74 [38] (at)
Row 0x0D8: 2E65 === 2E65 === 65 2E [27] (e.)
Row 0x0D9: 6F63 === 6F63 === 63 6F [1D] (co)
Row 0x0DA: 2F6D === 2F6D === 6D 2F [2D] (m/)
Row 0x0DB: 5042 === 5042 === 42 50 [28] (BP)
Row 0x0DC: 5F5F === 5F5F === 5F 5F [1E] (__)
Row 0x0DD: 4F42 === 4F42 === 42 4F [07] (BO)
Row 0x0DE: 544F === 544F === 4F 54 [05] (OT)
Row 0x0DF: 7542 === 7542 === 42 75 [19] (Bu)
Row 0x0E0: 2073 === 2073 === 73 20 [1D] (s )
Row 0x0E1: 6950 === 6950 === 50 69 [39] (Pi)
Row 0x0E2: 3872 === 3872 === 72 38 [3D] (r8)
Row 0x0E3: 7542 === 7542 === 42 75 [19] (Bu)
Row 0x0E4: 2073 === 2073 === 73 20 [1D] (s )
Row 0x0E5: 6950 === 6950 === 50 69 [39] (Pi)
Row 0x0E6: 6172 === 6172 === 72 61 [07] (ra)
Row 0x0E7: 6574 === 6574 === 74 65 [2B] (te)
Row 0x0E8: 3620 === 3620 === 20 36 [2A] ( 6)
Row 0xF80: 3F37 === 3F37 =?= 3F 3F [3F] (7?)
Row 0xF81: 1505 === 1505 =?= 15 15 [15] (..)
Row 0xF83: 0504 === 0504 =?= 04 04 [04] (..)
Row 0xF85: 0504 === 0504 =?= 04 04 [04] (..)
Row 0xFFD: 0504 === 0504 =?= 04 04 [04] (..)
Row 0xFFF: 1410 === 1410 =?= 14 14 [14] (..)

image

Nothing at the 0xf87 for locking OTP 0xc0 to 0xff.

  • 5:4 pattern is repeated in a similar way for bits 0:1, and 2:3.

I believe what we want is 0b010101, but repeated 3 times: 0x151515? I will test this and the manufacturing ID shortly. Then check out the CERT.

// offset 0x1B, chars 0x08: ā€œBP__BOOTā€

Weā€™ve got that extra _, maybe it could be X and 6 so it is clear from the bootloader what to load?

EDIT: I see it is trying to lock, but only after manufacturer string is written

if (!write_otp_byte_3x(0xF87, 0x15u)) {

Edit: Are these the remaining datafields?

// NOTE: Reserved for product string:
//                  // Rows 0x0e8 .. 0x0eb (space character + 7 additional characters maximum)

// NOTE: Reserved for manufacturing data:
//                  // Rows 0x0ec .. 0x0ff (40 characters maximum)

5.7.2. USB Device Strings
ā€¢ MANUFACTURER (default ā€œRaspberry Piā€, max-length 30 UTF-16 or ASCII chars)
ā€¢ PRODUCT (default ā€œRP2350 Bootā€, max-length 30 UTF-16 or ASCII chars)

5.7.6. UF2 INFO_UF2.TXT File
ā€¢ BOARD_ID (default ā€œRP2350ā€, max-length 127 ASCII chars)

Ah, this is the manufacturing string?

Oops!  Thatā€™s gotta be a copy/paste error on my part. Good catch! Edit in platform file?

Yes, I think thatā€™s rightā€¦ at least itā€™s what I also calculated. NOTE: to write the manufacturing string, youā€™ll have to NOT apply the soft-lock to OTP page 3 ā€¦ which is currently done right after whitelabel. Simple enough ā€¦ just skip that pageā€¦

This is your product line, you can choose to do that. But, itā€™s a very limited space (8 characters for sure, 11 characters may be possible). Isnā€™t the model already in the INFO_UF2.TXT file? In combination with the manufacturing string, that file would then have all the information needed to identify what firmware to load, as well as user-accessible traceability data.

Yes, precisely. The BOARD_ID provided a simple place to expose a variable-length string of arbitrary data via the bootloader. That function (not currently used) writes the string to the reserved 20 OTPs (<= 40 chars), then sets the WHITELABEL_INFO field (row offset 15) to the STRDEF indicating the stringā€™s offset and length, and then modifies the USB_BOOT_FLAGS to indicate this field is now valid. Next time you boot, that string will magically appear in that text file.

At least, it did in my tests. :wink:

[[EDIT - P.S. - I note you excluded the header otp/bp_otp.h for BP5 devices. I had intended to allow the ECC calculation and similar (which donā€™t touch the board) to be available. Itā€™s OK either way ā€¦ can always re-enable if exposing those cmds via the terminal later.]]

1 Like

First, I verified that the soft lock works.

Then, programmed without soft lock:

Programming debug output

programming manufacturing data
Whitelabel Debug: found USB BOOT FLAGS: 407733
Whitelabel Debug: WHITE_LABEL_ADDR points to row index 0x0c0
Whitelabel Debug: Static portion of the strings look ok
Whitelabel Debug: Writing the manufacturing string data
Whitelabel Debug: Writing row 0x0ec: 0x7542 (Bu)
Whitelabel Debug: Writing row 0x0ed: 0x2073 (s )
Whitelabel Debug: Writing row 0x0ee: 0x6950 (Pi)
Whitelabel Debug: Writing row 0x0ef: 0x6172 (ra)
Whitelabel Debug: Writing row 0x0f0: 0x6574 (te)
Whitelabel Debug: Writing row 0x0f1: 0x3620 ( 6)
Whitelabel Debug: Writing row 0x0f2: 0x5220 ( R)
Whitelabel Debug: Writing row 0x0f3: 0x5645 (EV)
Whitelabel Debug: Writing row 0x0f4: 0x3220 ( 2)
Whitelabel Debug: Writing row 0x0cf: STRDEF 2c12
Whitelabel Debug: Updating the USB_BOOT_FLAGS to mark the manufacturing string as valid
Whitelabel Debug: Writing rows 0x059ā€¦0x05B: 0x407733 ā†’ 0x40f733
Whitelabel Debug: Setting PAGE3_LOCK0 (0xF86) to 0x3Fu (no keys; read-only without key)
Whitelabel Debug: Setting PAGE3_LOCK1 (0xF87) to 0x151515 (read-only for all three)
Whitelabel Debug: Manufacturing string successfully applied and locked down.

Row 0xF86: 3F37 === 3F37 =?= 3F 3F [3F] (7?)
Row 0xF87: 1505 === 1505 =?= 15 15 [15] (ā€¦)

The protection bits are indeed set.

programming manufacturing data
Whitelabel Debug: found USB BOOT FLAGS: 40f733
Whitelabel Debug: WHITE_LABEL_ADDR points to row index 0x0c0
Whitelabel Debug: Static portion of the strings look ok
Whitelabel Error: Old manufacturing STRDEF (0x002c12) does not match new (0x002c18)

Programming again with different manufacturing string fails.

Board-ID: Bus Pirate 6 REV 2

That is indeed the string I set :slight_smile:

Step back

This is lovely functionality, but Iā€™m uncertain what to use it for at this point.

In the cert thread there was talk of a unique manufacturing ID, but then we doubled back around to relying on the OTP unique ID.

To test it out, I burned ā€œBus Pirate 6 REV 2ā€, but that could probably be better added to the model string if we want to include the REV. The board ID is the unique RPi ID now, would it make sense to burn that as part of the initial whitelabeling?

I would propose adding the initial whitelabeling to the self-test, and printf-ing at least any failure messages so they can pass on debugging info from the factory to us.

Step forward

I believe the next step is to add the entry table you prototyped, starting from the last record and moving forward. This will include for instance the location of the cert.

Iā€™m going to play around with this now. Especially:

  • Loading cert
  • Verify with Bus Pirate public key
  • Check unique ID matches cert
  • Burn cert and protect
  • Load cert from otp and parse/verify

Other updates

  • Merged cert into otp
  • Moved bp_otp out of the BP_VER 6 define
  • Housekeeping in the platforms folder
1 Like

static_assert(ARRAY_SIZE(_product_string) <= USB_WHITELABEL_MAX_CHARS_BP_VERSION + 1);

If the OTP string (5XL, 6 REV2) is more than one character a static_assert seems to be happening and the firmware freezes during startup. I have not located it yet, but I have installed a cert to otp and can retrieve and verify it.

Hope all is well @henrygab - Iā€™ve gone about as far on OTP as want to without getting your feedback when your busy period is over. I also need a break from it
:slight_smile: Every test is walking on eggshells, as I watch the Pico bodies drop.

Hereā€™s some markdown formatted draft docs so you can see what I did in a consolidated place, and Iā€™ll move these to the actual docs later.

Whitelabel (0x80?)

UF2 Bootloader v1.0
Model: Bus Pirate 6
Board-ID: F9:04:9D:32:5E:76:45:4F
  • Bootloader VID/PID
  • Drive name
  • UF2 bootloader info.txt and .html forward customization
  • Board-ID is RPi unique ID so it can be accessed even without a firmware

Summary of locations and values from above

Info Page (0x100)

The first usable page of OTP (64 rows, 128 bytes with ECC) contain clear text strings describing the hardware.

  • 0x00 End of String
  • 0x01 Device name
  • 0x02 Device version
  • 0x03 Device revision
  • 0x04 Production location
  • 0x05 Manufacturer
  • 0x06 Production date

Strings begin with a token and end with null termination.

:0x01:Bus Pirate:0x00::0x02:6:0x00::0x03:2:0x00::0x04:CN:0x00::0x05:Where Labs LLC:0x00::0x06:2025-02-16 13:01:03:0x00:

Example entry substituting HEX numbers for decimal byte values.

This information is actually extracted from the x509 cert during cert programming. It is redundant to the information in the x509 cert, but I would prefer not be required to parse the cert to get at that info.

There are 128bytes in the page, any other info that should go in there?

  • This page is locked to avoid corruption.
  • This page has a directory entry.
  • This page is always at a fixed position (0x100) because it is possible the unprotected directory entries become corrupted and this data is vital.

x509 Cert (0x140)

The next page is a x509 certificate verifying the authenticity of the hardware against the unique serial number in each RP2350 chip.

The certificate is signed with the Bus Pirate private key and burned during manufacturing along with the whitelabel data.

A public key can be used to validate the authenticity of the certificate. An attacker could attempt to change the public key through a sneaky pull request on GitHub. To protect the public key from modification, the key is checked into a separate git repo and is added to the Bus Pirate firmware as a submodule.

  • The cert is ~7-8 pages long
  • The cert is locked after verifying the write
  • The cert has a fixed position and a directory entry

:::info
Why not depend on the certificate for the board specifications? If there are homebrew Bus Pirates (say on a Pico2 board) or clones, they will not have a valid certificate. In that case the otp command can be used to burn the correct Info strings and the firmware will be able successfully identify the board.

The firmware has sane fallback values if the OTP is not programmed, but the user will need to pay extra attention to the firmware loaded on their board. The firmware will not be able to automatically detect if it is running on the correct hardware version, or accommodate minor revision differences, without attention from the user.
:::

Directory entries (0xf7e, backwards)

   typedef struct _OTP_DIRECTORY_ITEM {
        uint16_t EntryType; // with 0x0000 defined as "end of list"
        uint16_t StartRow;  // row where that entry is stored
        uint16_t RowCount;  // count of consecutive rows
        uint16_t CRC16; // Validates the prior three entries.
    } OTP_DIRECTORY_ITEM;

Directory entries are a list of the contents of OTP and the location/length of each item.

  • Directory Entries are 4 rows (8 bytes)
  • First row is EntryType, 0x0000 is end of list (no more entries)
  • Directory items are stored backwards from the last writable address 0xf7c-0xf7e
  • Search of directory items is from back to front, looking for 0x0000 (blank OTP) as end of list. This allows to add more entries later

The code (otp.c) currently looks backwards for 2 pages (64 row/4 =16 *2=32 max entries). This can be increased as needed as long as we leave free pages in front of it.

An page should probably be hardware locked when full.

Directory Entry Types

    enum {
        OTP_DIRECTORY_ITEM_TYPE_END = 0x0000,
        OTP_DIRECTORY_ITEM_TYPE_USB_WHITELABEL = 0x0001,
        OTP_DIRECTORY_ITEM_TYPE_DEVICE_INFO = 0x0002, 
        OTP_DIRECTORY_ITEM_TYPE_CERT = 0x0003,
    };

So far we have identified four entry types.

  • 0x0000 - End of list (black OTP row)
  • 0x0001 - Location of Whitelabel info
  • 0x0002 - Device info strings
  • 0x0003 - x509 certificate

Directory Entry Items

    OTP_DIRECTORY_ITEM directory_item[] = {
        {OTP_DIRECTORY_ITEM_TYPE_USB_WHITELABEL, 0xd0, 1*64, 0},
        {OTP_DIRECTORY_ITEM_TYPE_DEVICE_INFO, 0x100, 1*64, 0},
        {OTP_DIRECTORY_ITEM_TYPE_CERT, 0x100+64, 7*64, 0},
    };

The location of the current directory items is fixed and known by the firmware. These are key pieces of info. The directory page will be hardware unlocked so we can keep adding entries, if it is corrupted we still want to be able to find these info and cert (and whitelabel).

The order shown above is not quite what happens in the current code, I changed my mind about some of the locations.

  • 0x0d0 - I believe this is the fixed location of the whitelabel data
  • 0x100 - First user writable page, used for plain text info strings
  • 0x140 - Next 7 or so pages used for signing cert

Wow! Itā€™s great to see so much progress this past week.

Note 1: I have not reviewed any recent commits / code.
Note 2: I will be treating the cert data as an opaque blob of data.

CRITICAL QUESTION:

I think it was a mistake to encode the length of the data in the directory items as .RowCount instead of actual number of bytes.

@Ian ā€“ Do you approve this change to the OTP directory item structure?

Start of whitelabel should be 0xC0

An early statement was that whitelabel starts at 0x80, and later statements and code show it as 0xD0. The first available page for post-manufacturing use per datasheet was 0xC0. For the code I tested, the whitelabel structure was at 0xC0, although the STRDEFs were stored starting at 0xD0. This may be where the thought of 0xD0 came from?

Thus, I think that OTP_DIRECTORY_ITEM entry needs to change from starting at page 0x0D0 to starting at page 0x0C0. Easy enough!

INFO_PAGE

There is no need to worry about corruption of the directory, with just a couple small changes:

What

Change each individual ā€œINFO PAGEā€ item into its own unique OTP_DIRECTORY_ITEM_TYPE_xxx enumeration.

Also define OTP_DIRECTORY_ITEM_TYPE_BLANK ā€¦ whose primary use is to fill the remainder of the page, so that page can be locked, while still allowing for appending more entries.

Why

Keep a single, well-tested API for reading OTP data. The API will also be much easier to use than parsing the variable-length structure. Addresses your concern about the directory being corrupted, by allowing blank entries to fill the page and thus locking the manufacturing-critical data. :slight_smile:

TODO:

typdef enum _OTP_DIRTYPE {
    OTP_DIRTYPE_END = 0x0000,
    OTP_DIRTYPE_USB_WHITELABEL = 0x0001,
    OTP_DIRTYPE_CERT = 0x0003,
    OTP_DIRTYPE_BLANK = 0x0004,
    OTP_DIRTYPE_DEVICE_NAME = 0x0005,
    OTP_DIRTYPE_DEVICE_VERSION = 0x0006,
    OTP_DIRTYPE_DEVICE_REVISION = 0x0007,
    OTP_DIRTYPE_PRODUCTION_LOCATION = 0x0008,
    OTP_DIRTYPE_MANUFACTURER = 0x0009,
    OTP_DIRTYPE_PRODUCTION_DATE = 0x000A,
} OTP_DIRTYPE;

Will look more in the next couple daysā€¦ just wanted to give initial thoughts ā€¦ which might be wrong / need adjustment after I review the code.

And ā€¦ WOW! So much in just a week! :slight_smile:

1 Like