@@ -2083,34 +2083,45 @@ struct picoboot_memory_access : public memory_access {
2083
2083
vector<uint8_t> write_data; // used when erasing flash
2084
2084
if (flash == get_memory_type(address, model)) {
2085
2085
connection.exit_xip();
2086
- if (erase) {
2087
- // Do automatically erase flash, and make it aligned
2088
- // we have to erase in whole pages
2089
- range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2090
- ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2091
- assert(aligned_range.contains(address));
2092
- assert(aligned_range.contains(address + size));
2093
-
2094
- uint32_t pre_len = address - aligned_range.from;
2095
- uint32_t post_len = aligned_range.to - (address + size);
2096
- assert(pre_len + size + post_len == aligned_range.len());
2097
-
2098
- // save data before the changing data
2099
- write_data.resize(pre_len);
2100
- if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2101
- // now add the data that is changing
2102
- write_data.insert(write_data.end(), buffer, buffer + size);
2103
- // save data after the changing data
2104
- write_data.resize(aligned_range.len());
2105
- if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2106
-
2107
- // Do the erase
2108
- connection.flash_erase(aligned_range.from, aligned_range.len());
2109
-
2110
- // Update what will now be written
2111
- address = aligned_range.from;
2112
- buffer = write_data.data();
2113
- size = aligned_range.len();
2086
+ // Flash Translation Layer - auto-erase, and only write changed data
2087
+ if (enable_ftl) {
2088
+ // Check what's there already
2089
+ write_data.resize(size);
2090
+ read(address, write_data.data(), size, false);
2091
+ // Check if we even need to write
2092
+ if (std::equal(write_data.cbegin(), write_data.cend(), buffer)) {
2093
+ return;
2094
+ }
2095
+ // Check if we need to erase (ie check for non 0xff)
2096
+ if (!std::all_of(write_data.cbegin(), write_data.cend(), [](uint8_t v) { return v == 0xff; })) {
2097
+ // Do automatically erase flash, and make it aligned
2098
+ // we have to erase in whole pages
2099
+ range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2100
+ ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2101
+ assert(aligned_range.contains(address));
2102
+ assert(aligned_range.contains(address + size));
2103
+
2104
+ uint32_t pre_len = address - aligned_range.from;
2105
+ uint32_t post_len = aligned_range.to - (address + size);
2106
+ assert(pre_len + size + post_len == aligned_range.len());
2107
+
2108
+ // save data before the changing data
2109
+ write_data.resize(pre_len);
2110
+ if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2111
+ // now add the data that is changing
2112
+ write_data.insert(write_data.end(), buffer, buffer + size);
2113
+ // save data after the changing data
2114
+ write_data.resize(aligned_range.len());
2115
+ if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2116
+
2117
+ // Do the erase
2118
+ connection.flash_erase(aligned_range.from, aligned_range.len());
2119
+
2120
+ // Update what will now be written
2121
+ address = aligned_range.from;
2122
+ buffer = write_data.data();
2123
+ size = aligned_range.len();
2124
+ }
2114
2125
}
2115
2126
}
2116
2127
if (is_transfer_aligned(address, model) && is_transfer_aligned(address + size, model)) {
@@ -2128,7 +2139,8 @@ struct picoboot_memory_access : public memory_access {
2128
2139
write(addr, (uint8_t *)v.data(), v.size() * sizeof(typename raw_type_mapping<T>::access_type));
2129
2140
}
2130
2141
2131
- bool erase = false;
2142
+ // Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2143
+ bool enable_ftl = false;
2132
2144
private:
2133
2145
picoboot::connection& connection;
2134
2146
};
@@ -4122,7 +4134,7 @@ bool config_command::execute(device_map &devices) {
4122
4134
picoboot::connection connection(std::get<2>(handles), std::get<0>(handles));
4123
4135
picoboot_memory_access access(connection);
4124
4136
// Enable auto-erase
4125
- access.erase = true;
4137
+ access.enable_ftl = true;
4126
4138
auto partitions = get_partitions(connection);
4127
4139
vector<uint32_t> starts;
4128
4140
if (partitions) {
@@ -5395,7 +5407,12 @@ void setup_bdevfs(picoboot::connection con) {
5395
5407
string s = ss.str();
5396
5408
fos << "embedded drive: " << s << "\n";
5397
5409
5398
- bdevfs_setup.base_addr = bi_bdev.address;
5410
+ if (bi_bdev.address < FLASH_START) {
5411
+ // Some devices have the block device address relative to the start of flash
5412
+ bdevfs_setup.base_addr = bi_bdev.address + FLASH_START;
5413
+ } else {
5414
+ bdevfs_setup.base_addr = bi_bdev.address;
5415
+ }
5399
5416
bdevfs_setup.size = bi_bdev.size;
5400
5417
});
5401
5418
visitor.visit(access, hdr);
@@ -5452,15 +5469,17 @@ DWORD get_fattime (void) {
5452
5469
return fattime;
5453
5470
}
5454
5471
5472
+ static_assert(FF_MAX_SS == FF_MIN_SS, "FF_MAX_SS must be equal to FF_MIN_SS");
5473
+ #define SECTOR_SIZE FF_MAX_SS
5455
5474
5456
5475
DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count) {
5457
- bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t*)buff, count * FF_MAX_SS , false);
5476
+ bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t*)buff, count * SECTOR_SIZE , false);
5458
5477
return RES_OK;
5459
5478
}
5460
5479
5461
5480
DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
5462
5481
if (bdevfs_setup.writeable) {
5463
- bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t*)buff, count * FF_MAX_SS );
5482
+ bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t*)buff, count * SECTOR_SIZE );
5464
5483
return RES_OK;
5465
5484
} else {
5466
5485
fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
@@ -5474,11 +5493,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5474
5493
return RES_OK;
5475
5494
5476
5495
case GET_SECTOR_COUNT:
5477
- *(DWORD*)buff = bdevfs_setup.size / FF_MAX_SS;
5496
+ *(DWORD*)buff = bdevfs_setup.size / SECTOR_SIZE;
5497
+ return RES_OK;
5498
+
5499
+ case GET_SECTOR_SIZE:
5500
+ *(DWORD*)buff = SECTOR_SIZE;
5478
5501
return RES_OK;
5479
5502
5480
5503
case GET_BLOCK_SIZE:
5481
- *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS ;
5504
+ *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE ;
5482
5505
return RES_OK;
5483
5506
5484
5507
case IOCTL_INIT:
@@ -5488,6 +5511,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5488
5511
return RES_OK;
5489
5512
}
5490
5513
5514
+ case CTRL_TRIM: {
5515
+ if (bdevfs_setup.writeable) {
5516
+ DWORD* p = (DWORD*)buff;
5517
+ uint32_t start = (*p * SECTOR_SIZE) + bdevfs_setup.base_addr;
5518
+ uint32_t end = (*(p + 1) * SECTOR_SIZE) + bdevfs_setup.base_addr;
5519
+ // Only trim complete flash sectors
5520
+ if (start % FLASH_SECTOR_ERASE_SIZE) start += FLASH_SECTOR_ERASE_SIZE - (start % FLASH_SECTOR_ERASE_SIZE);
5521
+ end -= end % FLASH_SECTOR_ERASE_SIZE;
5522
+ for (uint32_t addr = start; addr < end; addr += FLASH_SECTOR_ERASE_SIZE) {
5523
+ bdevfs_setup.con->flash_erase(addr, FLASH_SECTOR_ERASE_SIZE);
5524
+ }
5525
+ return RES_OK;
5526
+ } else {
5527
+ fail(ERROR_NOT_POSSIBLE, "This block device is not writeable");
5528
+ return RES_WRPRT;
5529
+ }
5530
+ }
5531
+
5491
5532
default:
5492
5533
fail(ERROR_NOT_POSSIBLE, "Unknown ioctl %d", cmd);
5493
5534
return RES_PARERR;
@@ -5559,14 +5600,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
5559
5600
FATFS fatfs;
5560
5601
5561
5602
// Enable auto-erase, as FatFS has no Flash Translation Layer
5562
- bdevfs_setup.access->erase = true;
5603
+ bdevfs_setup.access->enable_ftl = true;
5563
5604
5564
5605
int err = f_mount(&fatfs);
5565
5606
if (err == FR_NO_FILESYSTEM) {
5566
5607
if (settings.bdev.format) {
5567
5608
if (bdevfs_setup.formattable) {
5568
5609
fos << "Formatting FatFS file system\n";
5569
- uint8_t work_buf[FF_MAX_SS ];
5610
+ uint8_t work_buf[SECTOR_SIZE ];
5570
5611
err = f_mkfs(&fatfs, FM_ANY | FM_SFD, 0, work_buf, sizeof(work_buf));
5571
5612
if (err) {
5572
5613
fail(ERROR_CONNECTION, "FatFS Format Error %d", err);
0 commit comments