On 07/01/25 03:53, Tom Rini wrote:
On Mon, Jan 06, 2025 at 12:06:25PM +0530, Harsha Vardhan V M wrote:

I would like to propose a new command for U-Boot's fuse programming
functionality to address the challenges posed by the current implementation.
While the existing fuse prog command works well for programming individual
fuse values, it becomes cumbersome especially when dealing with large-scale
programming requirements.

Current Command: fuse prog [-y] <bank> <word> <hexval> [<hexval>...]

This command programs one or more fuse words starting from a specific <bank>
and <word> with the hex values given as input.

While functional, it lacks the efficiency and robustness needed for
programming a significant number of fuses or handling structured fuse
configuration data. Repeatedly specifying values for each fuse bank and word
is not only time-consuming but also prone to errors during manual input or
scripting. This approach does not leverage the ability to process
pre-structured data in memory. For users with complex programming needs, the
current method becomes an obstacle rather than a tool.

Proposed Command: fuse writebuff

It would be good to provide some documentation links to the fuses that
you're wanting to deal with. What we have now works on a number of
diverse SoCs, even if for some cases it might be best to write a
script that's run rather than copy/paste things live. Any sort of new
mechanism needs to get feedback from users at other semiconductor
vendors to make sure it's generic enough for everyones needs. Thanks.


Hi Tom and Simon,

The buffer is not a text file. It is a structure in memory. The buffer is structured to contain all necessary information for the fuse programming process. This can include metadata, fuse programming data etc. The exact structure of the buffer can determined by the command_id, which provides flexibility for supporting different use cases. The memory buffer is typically prepared in user-space code or a script and loaded in memory before invoking the fuse writebuff command. It is not stored as a text file or any other file format, as the command operates directly on memory addresses.

Example of a buffer:

struct fuse_buffer {
    struct fuse_mpkh smpkh;
    struct fuse_msv msv;
    struct fuse_key_cnt key_cnt;
    u8 buffer_hash[64];
};

This fuse_buffer struct will be loaded in memory containing all the necessary information for fuse programming.

struct fuse_mpkh {
    u8 mpkh[64]; // public key hash
    u8 bch[8];
    u32 attributes; // read-protect, write-protect, override, active flag
    u32 reserved[2];
};
struct fuse_msv {
    u32 msv_with_bch; //model specific value
    u32 attributes;
    u32 reserved[2];
};
struct fuse_key_cnt {
    u32 key_cnt; //key count
    u32 attributes;
    u32 reserved[2];
};

-> eFUSE layout is abstract and isn't public as its programming and layout itself is security sensitive (it has authentication and decryption keys etc). So, fuse prog doesn't work as there is no "banks/offset" here. -> Platform Security Core running Secure SW exposes APIs through which these Keys and its attributes can be programmed. Whole content maybe encrypted for enhanced security on unsecure factory floor.
-> There is a definite order in which these fields needs to be programmed.

Its possible to break the struct into 32bit values and send them across but we would end up with ~30 odd fuse prog cmds which is inefficient and error prone. It would be hard on secure core to also ensure correctness of operations against all sorts of silly errors (such of accidentally skipping a word or mess up ordering) which can render Silicon unusable.

So passing a opaque pointer with a command_id to Secure core is all that fuse cmd needs to do which is what writebuff supports.

This can be extended to any vendor; It's just an opaque pointer handoff. I see at least one other vendor do it in custom way: arch/arm/mach-imx/cmd_dek.c which could benefit from this new cmd fuse writebuff.

Here’s how the fuse writebuff command works in a typical flow:
1. Buffer Preparation: Vendors or developers create a complete buffer (e.g., key.bin) containing all fuse programming data using vendor-specific scripts or tools and copied to SD card.
2. The buffer is loaded into memory using commands like:
fatload mmc 1 0x80000000 key.bin
3. The fuse writebuff command passes the memory address (0x80000000) and command_id to the secure core:
fuse writebuff <command_id> 0x80000000
4. The secure core receives the memory address as a pointer and validates, interprets it based on the command_id and then programs the fuses.

Thanks,
Harsha
<[email protected]>

Reply via email to