Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: add serial command that prints the flash unique id #80

Closed
wants to merge 2 commits into from

Conversation

Ferdi265
Copy link

@Ferdi265 Ferdi265 commented Apr 24, 2023

This PR adds a command to display the flash unique id from boards currently in BOOTSEL mode.

Since the bootrom RPC interface does not have a way to directly issue flash commands such as CMD_RUID, the only way I found to fix this is to copy the fash_get_unique_id function to RAM and use the EXEC command to read out the unique id.

the code blob uploaded to the pico was compiled using the following C and ASM code:

#include "hardware/regs/io_qspi.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/ssi.h"
#include "hardware/flash.h"

asm(
    ".macro static_assert value, msg\n"
        ".if !(\\value)\n"
        ".err \\msg\n"
        ".endif\n"
    ".endm\n"

    ".set FLASH_RUID_CMD, 0x4b\n"
    ".set FLASH_RUID_DUMMY_BYTES, 4\n"
    ".set FLASH_RUID_DATA_BYTES, 8\n"
    ".set FLASH_RUID_TOTAL_BYTES, (1 + FLASH_RUID_DUMMY_BYTES + FLASH_RUID_DATA_BYTES)\n"
);

void flash_do_cmd(const uint8_t * txbuf, uint8_t *rxbuf, size_t count);
void __attribute__((naked)) flash_get_unique_id_raw(void) {
    asm(
        ".Lflash_get_unique_id_raw:\n"
            "adr r0, .Ltxbuf\n"
            "adr r1, .Lrxbuf\n"
            "ldr r2, .Lbuflen\n"
            "b flash_do_cmd\n"
        ".Lbuflen:\n"
            ".word FLASH_RUID_TOTAL_BYTES\n"
        ".Ltxbuf:\n"
            ".byte FLASH_RUID_CMD\n"
            ".zero (FLASH_RUID_TOTAL_BYTES - 1)\n"
            ".zero (16 - FLASH_RUID_TOTAL_BYTES)\n"
        ".Lrxbuf:\n"
            ".zero FLASH_RUID_TOTAL_BYTES\n"
            ".zero (16 - FLASH_RUID_TOTAL_BYTES)\n"
        "static_assert ((.Lrxbuf - flash_get_unique_id_raw) == 28), \"rxbuf offset incorrect\"\n"
    );
}

static inline void __attribute__((always_inline)) flash_cs_force(_Bool high) {
    uint32_t field_val = high ?
        IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH :
        IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
    hw_write_masked(&ioqspi_hw->io[1].ctrl,
        field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB,
        IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS
    );
}

void flash_do_cmd(const uint8_t * txbuf, uint8_t *rxbuf, size_t count) {
    flash_cs_force(0);
    size_t tx_remaining = count;
    size_t rx_remaining = count;
    // We may be interrupted -- don't want FIFO to overflow if we're distracted.
    const size_t max_in_flight = 16 - 2;
    while (tx_remaining || rx_remaining) {
        uint32_t flags = ssi_hw->sr;
        bool can_put = !!(flags & SSI_SR_TFNF_BITS);
        bool can_get = !!(flags & SSI_SR_RFNE_BITS);
        if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) {
            ssi_hw->dr0 = *txbuf++;
            --tx_remaining;
        }
        if (can_get && rx_remaining) {
            *rxbuf++ = (uint8_t)ssi_hw->dr0;
            --rx_remaining;
        }
    }
    flash_cs_force(1);
}

@Ferdi265
Copy link
Author

Tagging relevant issues: #12, #54

@Ferdi265 Ferdi265 marked this pull request as draft April 24, 2023 12:49
@Ferdi265
Copy link
Author

Converted into a draft to signify incompleteness.
I am open to suggestions on how to best work this into picotool. See this PR as an RFC of sorts on how to implement this.

For devices still in application mode, the serial number could be read directly from the serial device, since the default serial for that is the flash unique id.

Optimally it would be great to be able to select devices not only by --bus B --addr A, but potentially by --serial SERIAL to simplify working with multiple picos at once.

@Ferdi265
Copy link
Author

Seeing as this is executing raw flash commands on any attached RP2040, regardless of the actually attached flash chip, this can of course potentially go badly on custom boards that do flash differently (however, the internal tinyusb code from pico-sdk would be similarly scary if not patched accordingly).

I'm not sure what to make of this; executing (a nontrivial amount of) code on any attached RP2040 at random just to figure out its serial number is a bit scary.

@Ferdi265 Ferdi265 changed the title DRAFT: add serial command that prints the serial number DRAFT: add serial command that prints the flash unique id Apr 24, 2023
@tomas-pecserke
Copy link

Optimally it would be great to be able to select devices not only by --bus B --addr A, but potentially by --serial SERIAL to simplify working with multiple picos at once.

I implemented this in PR #84.

@lurch
Copy link
Contributor

lurch commented Jun 3, 2023

I know this is only a draft, but it should probably be targeting the develop branch?

@Ferdi265
Copy link
Author

Ferdi265 commented Jun 3, 2023

Oh yes, I basically made this in a hurry; will rebase this when I get home today :)

@Ferdi265 Ferdi265 changed the base branch from master to develop June 3, 2023 11:35
@Ferdi265
Copy link
Author

Ferdi265 commented Jun 3, 2023

Rebased; since I forgot to create a feature branch before I pushed this into my fork, this now looks like a merge from master into develop, but the master branch in Ferdi265/picotool now actually tracks develop.

@Ferdi265 Ferdi265 closed this Jun 3, 2023
@Ferdi265 Ferdi265 deleted the master branch June 3, 2023 11:40
@Ferdi265
Copy link
Author

Ferdi265 commented Jun 3, 2023

Okay, in fixing my repo I accidently closed this branch since I renamed the master branch in my repo; I will recreate this PR later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants