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

View file

@ -28,133 +28,93 @@
#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
static bool ejected = false;
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
// We will use Flash as read-only disk with board that has
// CFG_EXAMPLE_MSC_READONLY defined
static struct disk_lba lba_cache;
static int lba_cached = -1;
#define README_CONTENTS \
"This is the password vault utilities directory.\r\n\r\nWork in progress\r\n"
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
DISK_BLOCK_SIZE = 512
struct drive {
const uint8_t lun;
const char vid[8];
const char pid[16];
const char rev[4];
const uint32_t n_lba;
};
#ifdef CFG_EXAMPLE_MSC_READONLY
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,
#define N_DRIVES 2
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 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,
const char global_vid[8] = "DLX";
const char host_pid[16] = "MEP Tools";
const char vault_pid[16] = "MEP Vault";
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, 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
static const struct drive Drives[N_DRIVES] = {
{ 0, "DLX", "MEP Tools", "0.1", 1024},
{ 1, "DLX", "MEP Vault", "0.1", 1024}
};
uint8_t tud_msc_get_maxlun_cb(void)
{
return 1;
}
// Invoked when received SCSI_CMD_INQUIRY
// 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) lun;
const char vid[] = "DLX";
const char pid[] = "Vault tools";
const char rev[] = "0.1a";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
const struct drive *drv;
if (lun >= N_DRIVES) {
return;
}
drv = &Drives[lun];
memcpy(vendor_id , drv->vid, strlen(drv->vid));
memcpy(product_id , drv->pid, strlen(drv->pid));
memcpy(product_rev, drv->rev, strlen(drv->rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void) lun;
// RAM disk is ready until ejected
if (ejected) {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
return true;
if (lun >= N_DRIVES) {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
if (drv_active[lun]) {
return true;
} else {
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
return false;
}
}
// 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
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
if (lun >= N_DRIVES) {
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
} else {
*block_count = Drives[lun].n_lba;
*block_size = DISK_BLOCK_SIZE;
}
}
// 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
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
(void) power_condition;
const struct drive *drv;
(void) power_condition;
if ( load_eject )
{
if (start)
{
// load disk storage
}else
{
// unload disk storage
ejected = true;
if (lun < N_DRIVES) {
drv = &Drives[lun];
if ( load_eject )
{
if (start)
{
drv_active[lun] = 1;
}else
{
drv_active[lun] = 0;
}
}
}
}
return true;
return true;
}
// Callback invoked when received READ10 command.
// 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)
{
(void) lun;
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
const struct drive *drv;
uint8_t const *addr;
if (lun >= N_DRIVES)
return -1;
drv = &Drives[lun];
uint8_t const* addr = msc_disk[lba] + offset;
memcpy(buffer, addr, bufsize);
if ( lba >= drv->n_lba )
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)
{
(void) lun;
/* Read only. */
return false;
if (lun != 1) {
/* Read only. */
return false;
} else {
return true;
}
}
// 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
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;
int32_t resplen = 0;
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
// most scsi handled is input
bool in_xfer = true;
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)
switch (scsi_cmd[0])
{
memcpy(buffer, response, resplen);
}else
{
// SCSI output
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;
// 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