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

Add support for UF2 format #971

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions source/daplink/drag-n-drop/file_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "file_stream.h"
#include "util.h"
#include "intelhex.h"
#include "uf2.h"
#include "flash_decoder.h"
#include "error.h"
#include "cmsis_os2.h"
Expand Down Expand Up @@ -75,9 +76,15 @@ static error_t open_hex(void *state);
static error_t write_hex(void *state, const uint8_t *data, uint32_t size);
static error_t close_hex(void *state);

static bool detect_uf2(const uint8_t *data, uint32_t size);
static error_t open_uf2(void *state);
static error_t write_uf2(void *state, const uint8_t *data, uint32_t size);
static error_t close_uf2(void *state);

stream_t stream[] = {
{detect_bin, open_bin, write_bin, close_bin}, // STREAM_TYPE_BIN
{detect_hex, open_hex, write_hex, close_hex}, // STREAM_TYPE_HEX
{detect_uf2, open_uf2, write_uf2, close_uf2}, // STREAM_TYPE_UF2
};
COMPILER_ASSERT(ARRAY_SIZE(stream) == STREAM_TYPE_COUNT);
// STREAM_TYPE_NONE must not be included in count
Expand Down Expand Up @@ -119,6 +126,8 @@ stream_type_t stream_type_from_name(const vfs_filename_t filename)
return STREAM_TYPE_BIN;
} else if (0 == strncmp("HEX", &filename[8], 3)) {
return STREAM_TYPE_HEX;
} else if (0 == strncmp("UF2", &filename[8], 3)) {
return STREAM_TYPE_UF2;
} else {
return STREAM_TYPE_NONE;
}
Expand Down Expand Up @@ -364,3 +373,50 @@ static error_t close_hex(void *state)
status = flash_decoder_close();
return status;
}

/* UF2 file processing */

static bool detect_uf2(const uint8_t *data, uint32_t size)
{
return 1 == validate_uf2block(data, size);
}

static error_t open_uf2(void *state)
{
error_t status;
status = flash_decoder_open();
return status;
}

static error_t write_uf2(void *state, const uint8_t *data, uint32_t size)
{
error_t status;
uint32_t start_addr;
const flash_intf_t *flash_intf;
const UF2_Block *block;

if (1 != validate_uf2block(data, size)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code assumes the calls to write_uf2() are one sector (512 bytes) long. Looking at file_data_handler() in source/daplink/drag-n-drop/vfs_manager.c, it looks like it could be multiple sectors (though I am not sure this can actually happen).
There is also the CMSIS-DAP / WebUSB commands (see source/daplink/cmsis-dap/DAP_vendor.c) for flashing files, because it works over the HID endpoint will (once framing has been removed) write about 40 bytes at a time.
We might need a buffer (the shared_state_t variant from hex files already has a 256 bytes buffer).

return ERROR_FD_UNSUPPORTED_UPDATE;
}

block = (const UF2_Block *)data;
if (block->flags & UF2_FLAG_NOFLASH) {
return ERROR_SUCCESS;
}

status = flash_decoder_get_flash(FLASH_DECODER_TYPE_TARGET, 0, false, &start_addr, &flash_intf);
if (ERROR_SUCCESS != status) {
return status;
}

status = flash_decoder_write(start_addr + block->targetAddr, block->data, block->payloadSize);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The start_addr + block->targetAddr part does not seem to match the UF2 specification in the sense that block->targetAddr is supposed to be an address, not an offset (from start_addr). It probably works in many case where start_addr is 0.
The code should verify that block->targetAddr is within flash bounds, and probably strictly increasing.


return status;
}

static error_t close_uf2(void *state)
{
error_t status;
status = flash_decoder_close();
return status;
}
1 change: 1 addition & 0 deletions source/daplink/drag-n-drop/file_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef enum {

STREAM_TYPE_BIN = STREAM_TYPE_START,
STREAM_TYPE_HEX,
STREAM_TYPE_UF2,

// Add new stream types here

Expand Down
63 changes: 63 additions & 0 deletions source/daplink/drag-n-drop/uf2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**

Microsoft UF2

The MIT License (MIT)

Copyright (c) Microsoft Corporation

All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/
#ifndef UF2FORMAT_H
#define UF2FORMAT_H 1

#include <stdint.h>
#include <stdbool.h>

// All entries are little endian.

#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
#define UF2_MAGIC_END 0x0AB16F30UL // Ditto

// If set, the block is "comment" and should not be flashed to the device
#define UF2_FLAG_NOFLASH 0x00000001

typedef struct {
// 32 byte header
uint32_t magicStart0;
uint32_t magicStart1;
uint32_t flags;
uint32_t targetAddr;
uint32_t payloadSize;
uint32_t blockNo;
uint32_t numBlocks;
uint32_t reserved;

// raw data;
uint8_t data[476];

// store magic also at the end to limit damage from partial block reads
uint32_t magicEnd;
} UF2_Block;

#endif
2 changes: 1 addition & 1 deletion source/daplink/drag-n-drop/vfs_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ static void file_change_handler(const vfs_filename_t filename, vfs_file_change_t
}

// Handler for file data arriving over USB. This function is responsible
// for detecting the start of a BIN/HEX file and performing programming
// for detecting the start of a BIN/HEX/UF2 file and performing programming
static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_of_sectors)
{
stream_type_t stream;
Expand Down
22 changes: 22 additions & 0 deletions source/daplink/validation.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "target_config.h"
#include "target_family.h"
#include "target_board.h"
#include "drag-n-drop/uf2.h"

static inline uint32_t test_range(const uint32_t test, const uint32_t min, const uint32_t max)
{
Expand Down Expand Up @@ -94,3 +95,24 @@ uint8_t validate_hexfile(const uint8_t *buf)
return ((buf[0] == ':') && ((buf[8] == '0') || (buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') || (buf[8] == '5'))) ? 1 : 0;
}
}

uint8_t validate_uf2block(const uint8_t *buf, uint32_t size)
{
if (size != sizeof(UF2_Block)) {
return 0;
}

const UF2_Block *block = (const UF2_Block *)buf;

if (block->magicStart0 != UF2_MAGIC_START0 ||
block->magicStart1 != UF2_MAGIC_START1 ||
block->magicEnd != UF2_MAGIC_END) {
return 0;
}

if (block->payloadSize > sizeof(block->data)) {
return 0;
}

return 1;
}
1 change: 1 addition & 0 deletions source/daplink/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern "C" {

uint8_t validate_bin_nvic(const uint8_t *buf);
uint8_t validate_hexfile(const uint8_t *buf);
uint8_t validate_uf2block(const uint8_t *buf, uint32_t size);

/*!
* @brief Baseline implementation of NVIC validator.
Expand Down