diff --git a/README.md b/README.md index 572586c..c83c4ae 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ SYNOPSIS: picotool config [-s ] [-g ] [-t ] picotool load [--ignore-partitions] [--family ] [-p ] [-n] [-N] [-u] [-v] [-x] [-t ] [-o ] [device-selection] - picotool encrypt [--quiet] [--verbose] [--embed] [--fast-rosc] [--use-mbedtls] [--otp-key-page ] [--hash] [--sign] [-t - ] [-o ] [-t ] - picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] [-t ] [-o ] [-t ] - [--major ] [--minor ] [--rollback [..]] + picotool encrypt [--quiet] [--verbose] [--embed] [--fast-rosc] [--use-mbedtls] [--otp-key-page ] [--hash] [--sign] [--clear] + [--pin-xip-sram] [-t ] [-o ] [-t ] + picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] [--pin-xip-sram] [-t ] [-o ] [-t + ] [--major ] [--minor ] [--rollback [..]] picotool link [--quiet] [--verbose] [-t ] [-t ] [-t ] [] [-t ] [-p ] picotool save [-p] [-v] [--family ] [-t ] [device-selection] picotool save -a [-v] [--family ] [-t ] [device-selection] @@ -578,8 +578,8 @@ SEAL: Add final metadata to a binary, optionally including a hash and/or signature. SYNOPSIS: - picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] [-t ] [-o ] [-t ] - [--major ] [--minor ] [--rollback [..]] + picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] [--pin-xip-sram] [-t ] [-o ] [-t + ] [--major ] [--minor ] [--rollback [..]] OPTIONS: --quiet @@ -603,6 +603,8 @@ OPTIONS: Sign the file --clear Clear all of SRAM on load + --pin-xip-sram + Pin XIP SRAM on load File to load from The file name @@ -648,8 +650,8 @@ ENCRYPT: Encrypt the program. SYNOPSIS: - picotool encrypt [--quiet] [--verbose] [--embed] [--fast-rosc] [--use-mbedtls] [--otp-key-page ] [--hash] [--sign] [-t - ] [-o ] [-t ] + picotool encrypt [--quiet] [--verbose] [--embed] [--fast-rosc] [--use-mbedtls] [--otp-key-page ] [--hash] [--sign] [--clear] + [--pin-xip-sram] [-t ] [-o ] [-t ] OPTIONS: --quiet @@ -679,6 +681,10 @@ OPTIONS: Hash the encrypted file --sign Sign the encrypted file + --clear + Clear all of SRAM on load + --pin-xip-sram + Pin XIP SRAM on load File to load from The file name diff --git a/bintool/BUILD.bazel b/bintool/BUILD.bazel index 8ec1cb6..d4ec42b 100644 --- a/bintool/BUILD.bazel +++ b/bintool/BUILD.bazel @@ -24,10 +24,6 @@ cc_library( "HAS_MBEDTLS=1", # Bazel build always has mbedtls. ], includes = ["."], - # In the CMake build, there's a workaround where this library is built with - # NO_PICO_PLATFORM, but that define shouldn't propagate to other - # dependencies. - local_defines = ["NO_PICO_PLATFORM=1"], deps = [ "//elf", "//errors", diff --git a/bintool/CMakeLists.txt b/bintool/CMakeLists.txt index 4e3edb5..0c3bebf 100644 --- a/bintool/CMakeLists.txt +++ b/bintool/CMakeLists.txt @@ -3,7 +3,6 @@ if (NOT TARGET mbedtls) add_library(bintool STATIC bintool.cpp) target_compile_definitions(bintool PRIVATE - NO_PICO_PLATFORM=1 HAS_MBEDTLS=0 ) @@ -18,7 +17,6 @@ else() bintool.cpp mbedtls_wrapper.c) target_compile_definitions(bintool PRIVATE - NO_PICO_PLATFORM=1 HAS_MBEDTLS=1 ) diff --git a/bintool/bintool.cpp b/bintool/bintool.cpp index 26b8b42..8dace90 100644 --- a/bintool/bintool.cpp +++ b/bintool/bintool.cpp @@ -687,22 +687,52 @@ void hash_andor_sign_block(block *new_block, const public_t public_key, const pr } -std::vector get_lm_hash_data(elf_file *elf, block *new_block, bool clear_sram = false) { +bool check_generic_load_map(std::shared_ptr load_map, model_t model, bool &pin_xip_sram) { + if (load_map == nullptr) { + return false; + } + + // generic xip pinning from the SDK + pin_xip_sram = load_map->entries.size() == 1 + && load_map->entries[0].storage_address == 0x0 + && load_map->entries[0].runtime_address == model->xip_sram_start() + && load_map->entries[0].size == 0x0; + return pin_xip_sram; +} + + +std::vector get_lm_hash_data(elf_file *elf, block *new_block, model_t model, bool clear_sram = false, bool pin_xip_sram = false) { std::vector to_hash; std::shared_ptr load_map = new_block->get_item(); + if (check_generic_load_map(load_map, model, pin_xip_sram)) { + new_block->items.erase(std::remove(new_block->items.begin(), new_block->items.end(), load_map), new_block->items.end()); + load_map = nullptr; + } if (load_map == nullptr) { std::vector entries; if (clear_sram) { // todo tidy up this way of hashing the uint32_t - std::vector sram_size_vec = {SRAM_END_RP2350 - SRAM_START}; + std::vector sram_size_vec = {model->sram_end() - model->sram_start()}; entries.push_back({ 0x0, - SRAM_START, + model->sram_start(), sram_size_vec[0] }); auto sram_size_data = words_to_lsb_bytes(sram_size_vec.begin(), sram_size_vec.end()); std::copy(sram_size_data.begin(), sram_size_data.end(), std::back_inserter(to_hash)); - DEBUG_LOG("CLEAR %08x + %08x\n", (int)SRAM_START, (int)sram_size_vec[0]); + DEBUG_LOG("CLEAR %08x + %08x\n", (int)model->sram_start(), (int)sram_size_vec[0]); + } + if (pin_xip_sram) { + // todo tidy up this way of hashing the uint32_t + std::vector xip_pin_size_vec = {0x0}; + entries.push_back({ + 0x0, + model->xip_sram_start(), + xip_pin_size_vec[0] + }); + auto xip_pin_size_data = words_to_lsb_bytes(xip_pin_size_vec.begin(), xip_pin_size_vec.end()); + std::copy(xip_pin_size_data.begin(), xip_pin_size_data.end(), std::back_inserter(to_hash)); + DEBUG_LOG("PIN XIP SRAM %08x + %08x\n", (int)model->xip_sram_start(), (int)xip_pin_size_vec[0]); } for(const auto &seg : sorted_segs(elf)) { if (!seg->is_load()) continue; @@ -761,24 +791,41 @@ std::vector get_lm_hash_data(elf_file *elf, block *new_block, bool clea } -std::vector get_lm_hash_data(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, get_more_bin_cb more_cb, bool clear_sram = false) { +std::vector get_lm_hash_data(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, get_more_bin_cb more_cb, model_t model, bool clear_sram = false, bool pin_xip_sram = false) { std::vector to_hash; std::shared_ptr load_map = new_block->get_item(); + if (check_generic_load_map(load_map, model, pin_xip_sram)) { + new_block->items.erase(std::remove(new_block->items.begin(), new_block->items.end(), load_map), new_block->items.end()); + load_map = nullptr; + } if (load_map == nullptr) { - to_hash.insert(to_hash.begin(), bin.begin(), bin.end()); std::vector entries; if (clear_sram) { - // todo gate this clearing of SRAM - std::vector sram_size_vec = {0x00082000}; + // todo tidy up this way of hashing the uint32_t + std::vector sram_size_vec = {model->sram_end() - model->sram_start()}; assert(sram_size_vec[0] % 4 == 0); entries.push_back({ 0x0, - 0x20000000, + model->sram_start(), sram_size_vec[0] }); auto sram_size_data = words_to_lsb_bytes(sram_size_vec.begin(), sram_size_vec.end()); - to_hash.insert(to_hash.begin(), sram_size_data.begin(), sram_size_data.end()); + std::copy(sram_size_data.begin(), sram_size_data.end(), std::back_inserter(to_hash)); + DEBUG_LOG("CLEAR %08x + %08x\n", (int)model->sram_start(), (int)sram_size_vec[0]); } + if (pin_xip_sram) { + // todo tidy up this way of hashing the uint32_t + std::vector xip_pin_size_vec = {0x0}; + entries.push_back({ + 0x0, + model->xip_sram_start(), + xip_pin_size_vec[0] + }); + auto xip_pin_size_data = words_to_lsb_bytes(xip_pin_size_vec.begin(), xip_pin_size_vec.end()); + std::copy(xip_pin_size_data.begin(), xip_pin_size_data.end(), std::back_inserter(to_hash)); + DEBUG_LOG("PIN XIP SRAM %08x + %08x\n", (int)model->xip_sram_start(), (int)xip_pin_size_vec[0]); + } + to_hash.insert(to_hash.begin(), bin.begin(), bin.end()); DEBUG_LOG("HASH %08x + %08x\n", (int)storage_addr, (int)bin.size()); entries.push_back( { @@ -823,8 +870,8 @@ std::vector get_lm_hash_data(std::vector bin, uint32_t storage } -int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram) { - std::vector to_hash = get_lm_hash_data(elf, new_block, clear_sram); +int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, model_t model, bool hash_value, bool sign, bool clear_sram, bool pin_xip_sram) { + std::vector to_hash = get_lm_hash_data(elf, new_block, model, clear_sram, pin_xip_sram); hash_andor_sign_block(new_block, public_key, private_key, hash_value, sign, to_hash); @@ -858,8 +905,8 @@ int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, } -std::vector hash_andor_sign(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram) { - std::vector to_hash = get_lm_hash_data(bin, storage_addr, runtime_addr, new_block, nullptr, clear_sram); +std::vector hash_andor_sign(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, model_t model, bool hash_value, bool sign, bool clear_sram, bool pin_xip_sram) { + std::vector to_hash = get_lm_hash_data(bin, storage_addr, runtime_addr, new_block, nullptr, model, clear_sram, pin_xip_sram); hash_andor_sign_block(new_block, public_key, private_key, hash_value, sign, to_hash); @@ -872,7 +919,7 @@ std::vector hash_andor_sign(std::vector bin, uint32_t storage_ } -void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *block, verified_t &hash_verified, verified_t &sig_verified, get_more_bin_cb more_cb) { +void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *block, model_t model, verified_t &hash_verified, verified_t &sig_verified, get_more_bin_cb more_cb) { std::shared_ptr load_map = block->get_item(); std::shared_ptr hash_def = block->get_item(); hash_verified = none; @@ -880,7 +927,7 @@ void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runt if (load_map == nullptr || hash_def == nullptr) { return; } - std::vector to_hash = get_lm_hash_data(bin, storage_addr, runtime_addr, block, more_cb, false); + std::vector to_hash = get_lm_hash_data(bin, storage_addr, runtime_addr, block, more_cb, model); // auto it = std::find(block->items.begin(), block->items.end(), hash_def); // assert (it != block->items.end()); @@ -941,8 +988,8 @@ void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runt } -void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, std::vector &iv_data, std::vector &enc_data) { - std::vector to_enc = get_lm_hash_data(elf, new_block); +void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, model_t model, std::vector &iv_data, std::vector &enc_data) { + std::vector to_enc = get_lm_hash_data(elf, new_block, model); std::random_device rand{}; assert(rand.max() - rand.min() >= 256); @@ -966,11 +1013,11 @@ void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, std: } -int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, std::vector iv_salt, bool hash_value, bool sign) { +int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, model_t model, std::vector iv_salt, bool hash_value, bool sign) { std::vector iv_data; std::vector enc_data; - encrypt_guts(elf, new_block, aes_key, iv_data, enc_data); + encrypt_guts(elf, new_block, aes_key, model, iv_data, enc_data); // Salt IV assert(iv_data.size() == iv_salt.size()); @@ -1054,13 +1101,13 @@ int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const publ new_block->items.erase(std::remove(new_block->items.begin(), new_block->items.end(), load_map), new_block->items.end()); } - hash_andor_sign(elf, new_block, public_key, private_key, hash_value, sign); + hash_andor_sign(elf, new_block, public_key, private_key, model, hash_value, sign); return 0; } -std::vector encrypt(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, std::vector iv_salt, bool hash_value, bool sign) { +std::vector encrypt(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, model_t model, std::vector iv_salt, bool hash_value, bool sign) { std::random_device rand{}; assert(rand.max() - rand.min() >= 256); @@ -1114,6 +1161,6 @@ std::vector encrypt(std::vector bin, uint32_t storage_addr, ui new_block->items.erase(std::remove(new_block->items.begin(), new_block->items.end(), load_map), new_block->items.end()); } - return hash_andor_sign(bin, storage_addr, runtime_addr, new_block, public_key, private_key, hash_value, sign);; + return hash_andor_sign(bin, storage_addr, runtime_addr, new_block, public_key, private_key, model, hash_value, sign); } #endif diff --git a/bintool/bintool.h b/bintool/bintool.h index 20029ac..90b4c0b 100644 --- a/bintool/bintool.h +++ b/bintool/bintool.h @@ -7,6 +7,7 @@ #endif #include "elf_file.h" #include "metadata.h" +#include "model.h" typedef enum verified_t { none, @@ -24,9 +25,9 @@ typedef enum verified_t { std::unique_ptr find_first_block(elf_file *elf); block place_new_block(elf_file *elf, std::unique_ptr &first_block, bool set_others_ignored=false); #if HAS_MBEDTLS - int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram = false); - void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, std::vector &iv_data, std::vector &enc_data); - int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, std::vector iv_salt, bool hash_value, bool sign); + int hash_andor_sign(elf_file *elf, block *new_block, const public_t public_key, const private_t private_key, model_t model, bool hash_value, bool sign, bool clear_sram = false, bool pin_xip_sram = false); + void encrypt_guts(elf_file *elf, block *new_block, const aes_key_t aes_key, model_t model, std::vector &iv_data, std::vector &enc_data); + int encrypt(elf_file *elf, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, model_t model, std::vector iv_salt, bool hash_value, bool sign); #endif // Bins @@ -37,7 +38,7 @@ std::vector> get_all_blocks(std::vector &bin, ui block place_new_block(std::vector &bin, uint32_t storage_addr, std::unique_ptr &first_block, bool set_others_ignored=false); uint32_t calc_checksum(std::vector bin); #if HAS_MBEDTLS - std::vector hash_andor_sign(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram = false); - std::vector encrypt(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, std::vector iv_salt, bool hash_value, bool sign); - void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *block, verified_t &hash_verified, verified_t &sig_verified, get_more_bin_cb more_cb = nullptr); + std::vector hash_andor_sign(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, model_t model, bool hash_value, bool sign, bool clear_sram = false, bool pin_xip_sram = false); + std::vector encrypt(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const aes_key_t aes_key, const public_t public_key, const private_t private_key, model_t model, std::vector iv_salt, bool hash_value, bool sign); + void verify_block(std::vector bin, uint32_t storage_addr, uint32_t runtime_addr, block *block, model_t model, verified_t &hash_verified, verified_t &sig_verified, get_more_bin_cb more_cb = nullptr); #endif diff --git a/main.cpp b/main.cpp index cec28af..629068a 100644 --- a/main.cpp +++ b/main.cpp @@ -549,6 +549,7 @@ struct _settings { bool hash = false; bool sign = false; bool clear_sram = false; + bool pin_xip_sram = false; bool set_tbyb = false; uint16_t major_version = 0; uint16_t minor_version = 0; @@ -918,7 +919,9 @@ struct encrypt_command : public cmd { ).force_expand_help(true) + ( option("--hash").set(settings.seal.hash) % "Hash the encrypted file" + - option("--sign").set(settings.seal.sign) % "Sign the encrypted file" + option("--sign").set(settings.seal.sign) % "Sign the encrypted file" + + option("--clear").set(settings.seal.clear_sram) % "Clear all of SRAM on load" + + option("--pin-xip-sram").set(settings.seal.pin_xip_sram) % "Pin XIP SRAM on load" ).min(0).doc_non_optional(true) % "Signing Configuration" + named_file_selection_x("infile", 0) % "File to load from" + ( @@ -950,7 +953,8 @@ struct seal_command : public cmd { ( option("--hash").set(settings.seal.hash) % "Hash the file" + option("--sign").set(settings.seal.sign) % "Sign the file" + - option("--clear").set(settings.seal.clear_sram) % "Clear all of SRAM on load" + option("--clear").set(settings.seal.clear_sram) % "Clear all of SRAM on load" + + option("--pin-xip-sram").set(settings.seal.pin_xip_sram) % "Pin XIP SRAM on load" ).min(0).doc_non_optional(true) % "Configuration" + named_file_selection_x("infile", 0) % "File to load from" + ( @@ -3327,7 +3331,7 @@ void info_guts(memory_access &raw_access, void *con) { verified_t sig_verified = none; #if HAS_MBEDTLS // Pass empty bin, which will be populated by more_cb if there is a signature/hash_value - verify_block({}, raw_access.get_binary_start(), raw_access.get_binary_start(), current_block, hash_verified, sig_verified, more_cb); + verify_block({}, raw_access.get_binary_start(), raw_access.get_binary_start(), current_block, raw_access.get_model(), hash_verified, sig_verified, more_cb); #endif // Addresses @@ -5053,7 +5057,7 @@ uint32_t __noinline otp_calculate_ecc(uint16_t x) { #if HAS_MBEDTLS -void sign_guts_elf(elf_file* elf, private_t private_key, public_t public_key) { +void sign_guts_elf(elf_file* elf, private_t private_key, public_t public_key, model_t model) { std::unique_ptr first_block = find_first_block(elf); if (!first_block) { // Throw a clearer error for RP2040 binaries with no block loop @@ -5138,8 +5142,9 @@ void sign_guts_elf(elf_file* elf, private_t private_key, public_t public_key) { hash_andor_sign( elf, &new_block, public_key, private_key, + model, settings.seal.hash, settings.seal.sign, - settings.seal.clear_sram + settings.seal.clear_sram, settings.seal.pin_xip_sram ); } @@ -5208,8 +5213,9 @@ vector sign_guts_bin(iostream_memory_access in, private_t private_key, auto sig_data = hash_andor_sign( bin, bin_start, bin_start, &new_block, public_key, private_key, + in.get_model(), settings.seal.hash, settings.seal.sign, - settings.seal.clear_sram + settings.seal.clear_sram, settings.seal.pin_xip_sram ); return sig_data; @@ -5407,11 +5413,13 @@ bool encrypt_command::execute(device_map &devices) { new_block.items.erase(std::remove(new_block.items.begin(), new_block.items.end(), load_map), new_block.items.end()); } + model_t model = get_model(0); + if (settings.encrypt.embed) { std::vector iv_data; std::vector enc_data; uint32_t data_start_address = SRAM_START; - encrypt_guts(elf, &new_block, aes_key, iv_data, enc_data); + encrypt_guts(elf, &new_block, aes_key, model, iv_data, enc_data); // Salt IV assert(iv_data.size() == iv_salt.size()); @@ -5424,7 +5432,7 @@ bool encrypt_command::execute(device_map &devices) { auto program = get_iostream_memory_access(tmp, filetype::elf, true); // todo should be determined from image_def - program.set_model(std::make_shared()); + program.set_model(model); // data_start_addr settings.config.key = "data_start_addr"; @@ -5504,14 +5512,13 @@ bool encrypt_command::execute(device_map &devices) { } // Sign the final thing - settings.seal.clear_sram = true; - sign_guts_elf(enc_elf, private_key, public_key); + sign_guts_elf(enc_elf, private_key, public_key, model); auto out = get_file_idx(ios::out|ios::binary, 1); enc_elf->write(out); out->close(); } else { - encrypt(elf, &new_block, aes_key, public_key, private_key, iv_salt, settings.seal.hash, settings.seal.sign); + encrypt(elf, &new_block, aes_key, public_key, private_key, model, iv_salt, settings.seal.hash, settings.seal.sign); auto out = get_file_idx(ios::out|ios::binary, 1); elf->write(out); out->close(); @@ -5539,7 +5546,7 @@ bool encrypt_command::execute(device_map &devices) { new_block.items.erase(std::remove(new_block.items.begin(), new_block.items.end(), load_map), new_block.items.end()); } - auto enc_data = encrypt(bin, bin_start, bin_start, &new_block, aes_key, public_key, private_key, iv_salt, settings.seal.hash, settings.seal.sign); + auto enc_data = encrypt(bin, bin_start, bin_start, &new_block, aes_key, public_key, private_key, binfile.get_model(), iv_salt, settings.seal.hash, settings.seal.sign); auto out = get_file_idx(ios::out|ios::binary, 1); out->write((const char *)enc_data.data(), enc_data.size()); @@ -5743,7 +5750,7 @@ bool seal_command::execute(device_map &devices) { elf->read_file(get_file(ios::in|ios::binary)); // Remove any holes in the ELF file, as these cause issues when signing/hashing elf->remove_sh_holes(); - sign_guts_elf(elf, private_key, public_key); + sign_guts_elf(elf, private_key, public_key, get_model(0)); auto out = get_file_idx(ios::out|ios::binary, 1); elf->write(out); @@ -8321,7 +8328,7 @@ bool otp_permissions_command::execute(device_map &devices) { elf_file source_file(settings.verbose); elf_file *elf = &source_file; elf->read_file(tmp); - sign_guts_elf(elf, private_key, public_key); + sign_guts_elf(elf, private_key, public_key, program.get_model()); auto out = std::make_shared(); elf->write(out); diff --git a/model/model.h b/model/model.h index e17e33c..17bf824 100644 --- a/model/model.h +++ b/model/model.h @@ -383,6 +383,7 @@ static address_ranges address_ranges_flash(const model_t& model) { address_ranges ranges; ranges.emplace_back(model->flash_start(), model->flash_end(), address_range::type::CONTENTS); ranges.emplace_back(model->sram_start(), model->sram_end(), address_range::type::NO_CONTENTS); + ranges.emplace_back(model->xip_sram_start(), model->xip_sram_end(), address_range::type::NO_CONTENTS); if (model->chip() == rp2040) { ranges.emplace_back(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS); }