Added read-only USB drive with host utils for linux

This commit is contained in:
Daniele Lacamera 2023-06-11 18:46:39 +02:00
parent 11b1951b2a
commit f49e1a5eb7
5 changed files with 180 additions and 159 deletions

View file

@ -25,6 +25,7 @@ target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/fsm.c ${CMAKE_CURRENT_SOURCE_DIR}/src/fsm.c
${CMAKE_CURRENT_SOURCE_DIR}/src/flash.c ${CMAKE_CURRENT_SOURCE_DIR}/src/flash.c
${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c ${CMAKE_CURRENT_SOURCE_DIR}/src/hid.c
${CMAKE_CURRENT_SOURCE_DIR}/src/disk0.c
${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wc_port.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wc_port.c
${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wolfmath.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/wolfmath.c
${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hash.c ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl/wolfcrypt/src/hash.c

View file

@ -164,6 +164,7 @@ To compile the firmware run the following from the source directory:
``` ```
mkdir build mkdir build
cd build cd build
make -C ../msc_content
cmake .. -DFAMILY=rp2040 -DPICO_SDK_PATH=/path/to/motenpoche/pico-sdk cmake .. -DFAMILY=rp2040 -DPICO_SDK_PATH=/path/to/motenpoche/pico-sdk
``` ```

View file

@ -1,7 +1,26 @@
all: mep all: ../src/disk0.c
mep: mep.c mep: mep.c
gcc -g -ggdb -o mep mep.c -lwolfssl gcc -g -ggdb -o mep mep.c -lwolfssl
../src/disk0.c: mep FORCE
dd if=/dev/zero of=disk0.img bs=1K count=128
sudo mkfs.vfat disk0.img
sudo mkdir -p tmpfs
sudo mount -o loop disk0.img tmpfs
sudo mkdir -p tmpfs/mep
sudo cp mep.c mep tmpfs/mep
sudo cp Makefile.flash tmpfs/mep/Makefile
sudo cp ../README.md tmpfs
sudo umount tmpfs
xxd -i disk0.img | sed -e "s/unsigned/const unsigned/g" \
| sed -e "s/char/char __attribute__((section(\".disk0\")))/g" > ../src/disk0.c
clean: clean:
rm -f mep rm -f mep fatfs ../fatfs.ld
sudo umount tmpfs || true
sudo rm -rf tmpfs
FORCE:

View file

@ -21,6 +21,7 @@
__stack (== StackTop) __stack (== StackTop)
*/ */
MEMORY MEMORY
{ {
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k
@ -93,6 +94,13 @@ SECTIONS
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
. = ALIGN(4); . = ALIGN(4);
} > FLASH } > FLASH
.fatfs_rodata : {
. = ALIGN(512);
__fatfs_start = .;
KEEP(*(.disk0*));
__fatfs_end = .;
} > FLASH
.ARM.extab : .ARM.extab :
{ {
@ -115,7 +123,8 @@ SECTIONS
*(.binary_info.*) *(.binary_info.*)
} > FLASH } > FLASH
__binary_info_end = .; __binary_info_end = .;
. = ALIGN(4);
/* End of .text-like segments */ /* End of .text-like segments */
__etext = .; __etext = .;
@ -178,6 +187,7 @@ SECTIONS
. = ALIGN(4); . = ALIGN(4);
*(.uninitialized_data*) *(.uninitialized_data*)
} > RAM } > RAM
/* Start and end symbols must be word-aligned */ /* Start and end symbols must be word-aligned */
.scratch_x : { .scratch_x : {
@ -234,6 +244,7 @@ SECTIONS
.flash_end : { .flash_end : {
__flash_binary_end = .; __flash_binary_end = .;
} > FLASH } > FLASH
/* stack limit is poorly named, but historically is maximum heap ptr */ /* stack limit is poorly named, but historically is maximum heap ptr */
__StackLimit = ORIGIN(RAM) + LENGTH(RAM); __StackLimit = ORIGIN(RAM) + LENGTH(RAM);

View file

@ -28,133 +28,93 @@
#if CFG_TUD_MSC #if CFG_TUD_MSC
#define MSC_RO_ORIGIN (0x10180000)
#define DISK_BLOCK_NUM 1024
#define DISK_BLOCK_SIZE 512
extern const unsigned char disk0_img[];
struct disk_lba {
uint8_t data[DISK_BLOCK_SIZE];
};
// whether host does safe-eject // whether host does safe-eject
static bool ejected = false; static bool ejected = false;
// Some MCU doesn't have enough 8KB SRAM to store the whole disk static struct disk_lba lba_cache;
// We will use Flash as read-only disk with board that has static int lba_cached = -1;
// CFG_EXAMPLE_MSC_READONLY defined
#define README_CONTENTS \ struct drive {
"This is the password vault utilities directory.\r\n\r\nWork in progress\r\n" const uint8_t lun;
const char vid[8];
enum const char pid[16];
{ const char rev[4];
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount const uint32_t n_lba;
DISK_BLOCK_SIZE = 512
}; };
#ifdef CFG_EXAMPLE_MSC_READONLY #define N_DRIVES 2
const
#endif
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'V' , 'a' , 'u' , 'l' , 't' ,
' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code static uint8_t drv_active[N_DRIVES] = {1, 0};
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, const char global_vid[8] = "DLX";
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, const char host_pid[16] = "MEP Tools";
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, const char vault_pid[16] = "MEP Vault";
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, const char global_rev[4] = "0.1";
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, static const struct drive Drives[N_DRIVES] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, { 0, "DLX", "MEP Tools", "0.1", 1024},
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, { 1, "DLX", "MEP Vault", "0.1", 1024}
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'V' , 'a' , 'u' , 'l' , 't' , ' ' , 'T' , 'o' , 'o' , 'l' , 's' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is readme file
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: Readme Content -------------//
README_CONTENTS
}; };
uint8_t tud_msc_get_maxlun_cb(void)
{
return 1;
}
// Invoked when received SCSI_CMD_INQUIRY // Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{ {
(void) lun; const struct drive *drv;
if (lun >= N_DRIVES) {
const char vid[] = "DLX"; return;
const char pid[] = "Vault tools"; }
const char rev[] = "0.1a"; drv = &Drives[lun];
memcpy(vendor_id , drv->vid, strlen(drv->vid));
memcpy(vendor_id , vid, strlen(vid)); memcpy(product_id , drv->pid, strlen(drv->pid));
memcpy(product_id , pid, strlen(pid)); memcpy(product_rev, drv->rev, strlen(drv->rev));
memcpy(product_rev, rev, strlen(rev));
} }
// Invoked when received Test Unit Ready command. // Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted // return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun) bool tud_msc_test_unit_ready_cb(uint8_t lun)
{ {
(void) lun; if (lun >= N_DRIVES) {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
// RAM disk is ready until ejected return false;
if (ejected) { }
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); if (drv_active[lun]) {
return false; return true;
} } else {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return true; return false;
}
} }
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size // Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{ {
(void) lun; if (lun >= N_DRIVES) {
*block_count = DISK_BLOCK_NUM;
*block_count = DISK_BLOCK_NUM; *block_size = DISK_BLOCK_SIZE;
*block_size = DISK_BLOCK_SIZE; } else {
*block_count = Drives[lun].n_lba;
*block_size = DISK_BLOCK_SIZE;
}
} }
// Invoked when received Start Stop Unit command // Invoked when received Start Stop Unit command
@ -162,45 +122,74 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz
// - Start = 1 : active mode, if load_eject = 1 : load disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{ {
(void) lun; const struct drive *drv;
(void) power_condition; (void) power_condition;
if ( load_eject ) if (lun < N_DRIVES) {
{ drv = &Drives[lun];
if (start) if ( load_eject )
{ {
// load disk storage if (start)
}else {
{ drv_active[lun] = 1;
// unload disk storage }else
ejected = true; {
drv_active[lun] = 0;
}
}
} }
} return true;
return true;
} }
// Callback invoked when received READ10 command. // Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{ {
(void) lun;
// out of ramdisk const struct drive *drv;
if ( lba >= DISK_BLOCK_NUM ) return -1; uint8_t const *addr;
if (lun >= N_DRIVES)
return -1;
drv = &Drives[lun];
uint8_t const* addr = msc_disk[lba] + offset; if ( lba >= drv->n_lba )
memcpy(buffer, addr, bufsize); return -1;
return bufsize;
if (lun == 0) {
struct disk_lba *msc_ro = (struct disk_lba *)disk0_img;
memcpy(buffer, msc_ro[lba].data + offset, bufsize);
asm volatile("DMB");
return bufsize;
} else {
#if 0
if ( lba != lba_cached) {
if (lba == 0) {
memcpy(lba_cache.data, mbr.data, sizeof(struct disk_lba));
lba_cached = lba;
return 0;
}
memcpy(lba_cache.data, msc_ro[lba].data, sizeof(struct disk_lba));
lba_cached = lba;
return 0;
}
memcpy(buffer, lba_cache.data + offset, bufsize);
#endif
memset(buffer, 0xA5, bufsize);
return bufsize;
}
} }
bool tud_msc_is_writable_cb (uint8_t lun) bool tud_msc_is_writable_cb (uint8_t lun)
{ {
(void) lun; if (lun != 1) {
/* Read only. */
/* Read only. */ return false;
return false; } else {
return true;
}
} }
// Callback invoked when received WRITE10 command. // Callback invoked when received WRITE10 command.
@ -221,45 +210,45 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
// - READ10 and WRITE10 has their own callbacks // - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{ {
// read10 & write10 has their own callback and MUST not be handled here // read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL; void const* response = NULL;
int32_t resplen = 0; int32_t resplen = 0;
// most scsi handled is input // most scsi handled is input
bool in_xfer = true; bool in_xfer = true;
switch (scsi_cmd[0]) switch (scsi_cmd[0])
{
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
// Host is about to read/write etc ... better not to disconnect disk
resplen = 0;
break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{ {
memcpy(buffer, response, resplen); case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
}else // Host is about to read/write etc ... better not to disconnect disk
{ resplen = 0;
// SCSI output break;
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
} }
}
return resplen; // return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, resplen);
}else
{
// SCSI output
}
}
return resplen;
} }
#endif #endif