/* Changes the encryption level of the drive. If encrypt is true: encrypt drive, else decrypt */ uint8_t sd_change_encryption(uint8_t slot, bool encrypt, bool change_key, uint8_t *old_passwd, uint8_t *new_passwd) { sd_mmc_err_t err; uint32_t i, nb_blocks; encrypt_config_t *config_ptr = NULL; security_get_config(&config_ptr); if ((encrypt == config_ptr->encryption_level) && !change_key) return CTRL_GOOD; if (change_key) { sha2(old_passwd, MAX_PASS_LENGTH, old_hash_cipher_key, 0); sha2(new_passwd, MAX_PASS_LENGTH, new_hash_cipher_key, 0); } if (old_hash_cipher_key == new_hash_cipher_key) return CTRL_GOOD; do { err = sd_mmc_check(slot); if ((SD_MMC_ERR_NO_CARD != err) && (SD_MMC_INIT_ONGOING != err) && (SD_MMC_OK != err)) { while (SD_MMC_ERR_NO_CARD != sd_mmc_check(slot)) { } } } while (SD_MMC_OK != err); nb_blocks = sd_mmc_get_capacity(slot) * (1024 / SD_MMC_BLOCK_SIZE); for (i = 0; i < nb_blocks / SD_BLOCKS_PER_ACCESS; ++i) { if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, i, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_start_read_blocks(src_buf, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks()) return CTRL_FAIL; aes_set_key(&AVR32_AES, (unsigned int *)old_hash_cipher_key); ram_aes_ram(change_key ? false : encrypt, SD_MMC_BLOCK_SIZE * SD_BLOCKS_PER_ACCESS / sizeof(unsigned int), (unsigned int *)src_buf, (unsigned int *)dest_buf); if (change_key) { aes_set_key(&AVR32_AES, (unsigned int *)new_hash_cipher_key); ram_aes_ram(true, SD_MMC_BLOCK_SIZE * SD_BLOCKS_PER_ACCESS / sizeof(unsigned int), (unsigned int *)dest_buf, (unsigned int *)src_buf); } if (SD_MMC_OK != sd_mmc_init_write_blocks(slot, i, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_start_write_blocks(src_buf, SD_BLOCKS_PER_ACCESS)) return CTRL_FAIL; if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks()) return CTRL_FAIL; } return CTRL_GOOD; }
Ctrl_status sd_mmc_usb_read_10(uint8_t slot, uint32_t addr, uint16_t nb_sector) { bool b_first_step = true; uint16_t nb_step; switch (sd_mmc_init_read_blocks(slot, addr, nb_sector)) { case SD_MMC_OK: break; case SD_MMC_ERR_NO_CARD: return CTRL_NO_PRESENT; default: return CTRL_FAIL; } // Pipeline the 2 transfer in order to speed-up the performances nb_step = nb_sector + 1; while (nb_step--) { if (nb_step) { // Skip last step // MCI -> RAM if (SD_MMC_OK != sd_mmc_start_read_blocks(((nb_step % 2) == 0) ? sector_buf_0 : sector_buf_1, 1)) { return CTRL_FAIL; } } if (!b_first_step) { // Skip first step // RAM -> USB if (!udi_msc_trans_block(true, ((nb_step % 2) == 0) ? sector_buf_1 : sector_buf_0, SD_MMC_BLOCK_SIZE, NULL)) { if (!b_first_step) { sd_mmc_wait_end_of_read_blocks(true); } return CTRL_FAIL; } } else { b_first_step = false; } if (nb_step) { // Skip last step if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { return CTRL_FAIL; } } b_first_step = false; } return CTRL_GOOD; }
/** * \name MEM <-> RAM Interface * @{ */ Ctrl_status sd_mmc_mem_2_ram(uint8_t slot, uint32_t addr, void *ram) { switch (sd_mmc_init_read_blocks(slot, addr, 1)) { case SD_MMC_OK: break; case SD_MMC_ERR_NO_CARD: return CTRL_NO_PRESENT; default: return CTRL_FAIL; } if (SD_MMC_OK != sd_mmc_start_read_blocks(ram, 1)) { return CTRL_FAIL; } if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { return CTRL_FAIL; } return CTRL_GOOD; }
/** * \brief Card R/W tests * * \param slot SD/MMC slot to test */ static void main_test_memory(uint8_t slot) { uint32_t last_blocks_addr, i, nb_trans; REDTIMESTAMP tick_start; uint32_t time_ms; // Compute the last address last_blocks_addr = sd_mmc_get_capacity(slot) * (1024 / SD_MMC_BLOCK_SIZE); if (last_blocks_addr < (TEST_MEM_START_OFFSET / 512lu)) { printf("[Memory is too small.]\n\r"); return; } last_blocks_addr -= (TEST_MEM_START_OFFSET / SD_MMC_BLOCK_SIZE); printf("Card R/W test:\n\r"); // Read the last block printf(" Read... "); tick_start = RedOsTimestamp(); if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { if (SD_MMC_OK != sd_mmc_start_read_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { printf("[FAIL]\n\r"); return; } } time_ms = RedOsTimePassed(tick_start) / 1000U; if (time_ms) { // Valid time_ms printf(" %d KBps ", (int)(((TEST_MEM_AREA_SIZE * 1000lu) / 1024lu) / time_ms)); } printf("[OK]\n\r"); if (sd_mmc_is_write_protected(slot)) { printf("Card is write protected [WRITE TEST SKIPPED]\n\r"); return; } // Fill buffer with a pattern for (i = 0; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = TEST_FILL_VALUE_U32; } printf(" Write pattern... "); if (SD_MMC_OK != sd_mmc_init_write_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } tick_start = RedOsTimestamp(); for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { ((uint32_t*)buf_test)[0] = nb_trans; // Unique value for each area if (SD_MMC_OK != sd_mmc_start_write_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("[FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_write_blocks(false)) { printf("[FAIL]\n\r"); return; } } time_ms = RedOsTimePassed(tick_start) / 1000U; if (time_ms) { // Valid time_ms printf(" %d KBps ", (int)(((TEST_MEM_AREA_SIZE * 1000lu) / 1024lu) / time_ms)); } printf("[OK]\n\r"); printf(" Read and check pattern... "); if (SD_MMC_OK != sd_mmc_init_read_blocks(slot, last_blocks_addr, TEST_MEM_AREA_SIZE / SD_MMC_BLOCK_SIZE)) { printf("Read [FAIL]\n\r"); return; } for (nb_trans = 0; nb_trans < (TEST_MEM_AREA_SIZE / TEST_MEM_ACCESS_SIZE); nb_trans++) { // Clear buffer for (i = 0; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = 0xFFFFFFFF; } // Fill buffer if (SD_MMC_OK != sd_mmc_start_read_blocks(buf_test, TEST_MEM_ACCESS_SIZE / SD_MMC_BLOCK_SIZE)) { printf("Read [FAIL]\n\r"); return; } if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks(false)) { printf("Read [FAIL]\n\r"); return; } // Check the unique value of the area if (((uint32_t*)buf_test)[0] != nb_trans) { printf("Check [FAIL]\n\r"); return; } // Check buffer for (i = 1; i < (TEST_MEM_ACCESS_SIZE / sizeof(uint32_t)); i++) { if (((uint32_t*)buf_test)[i] != TEST_FILL_VALUE_U32) { printf("Check [FAIL]\n\r"); return; } } } printf("[OK]\n\r"); }
/** * \brief SD/MMC card read and write test. * * \param test Current test case. */ static void run_sd_mmc_rw_test(const struct test_case *test) { uint32_t i; uint32_t last_blocks_addr; uint16_t nb_block, nb_trans; bool split_tansfer = false; /* Compute the last address */ last_blocks_addr = sd_mmc_get_capacity(0) * (1024/SD_MMC_BLOCK_SIZE) - 50; test_assert_true(test, last_blocks_addr > NB_MULTI_BLOCKS, "Error: SD/MMC capacity."); last_blocks_addr -= NB_MULTI_BLOCKS; nb_block = 1; run_sd_mmc_rw_test_next: /* Read (save blocks) the last blocks */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_save[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } test_assert_true(test, !sd_mmc_is_write_protected(0), "Error: SD/MMC is write protected."); /* Fill buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = TEST_FILL_VALUE_U32; } /* Write the last blocks */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_write_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize write sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_write_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start write sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_write_blocks(false), "Error: SD/MMC wait end of write sector(s)."); } /* Clean buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { ((uint32_t*)buf_test)[i] = 0xFFFFFFFF; } /* Read the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } /* Check buffer */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { test_assert_true(test, ((uint32_t*)buf_test)[i] == TEST_FILL_VALUE_U32, "Error: SD/MMC verify write operation."); } /* Write (restore) the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_write_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize write restore sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_write_blocks( &buf_save[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start write restore sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_write_blocks(false), "Error: SD/MMC wait end of write restore sector(s)."); } /* Read (check restore) the last block */ test_assert_true(test, SD_MMC_OK == sd_mmc_init_read_blocks(0, last_blocks_addr, nb_block), "Error: SD/MMC initialize read sector(s)."); for (nb_trans = 0; nb_trans < (split_tansfer? nb_block : 1); nb_trans++) { test_assert_true(test, SD_MMC_OK == sd_mmc_start_read_blocks( &buf_test[nb_trans * SD_MMC_BLOCK_SIZE], split_tansfer? 1 : nb_block), "Error: SD/MMC start read sector(s)."); test_assert_true(test, SD_MMC_OK == sd_mmc_wait_end_of_read_blocks(false), "Error: SD/MMC wait end of read sector(s)."); } /* Check buffer restored */ for (i = 0; i < (SD_MMC_BLOCK_SIZE * nb_block / sizeof(uint32_t)); i++) { test_assert_true(test, ((uint32_t*)buf_test)[i] == ((uint32_t*)buf_save)[i], "Error: SD/MMC verify restore operation."); } if (nb_block == 1) { /* Launch second test */ nb_block = NB_MULTI_BLOCKS; goto run_sd_mmc_rw_test_next; } if (!split_tansfer) { /* Launch third test */ split_tansfer = true; goto run_sd_mmc_rw_test_next; } }
Ctrl_status sd_mmc_usb_read_10(uint8_t slot, uint32_t addr, uint16_t nb_sector) { bool b_first_step = true; uint16_t nb_step; #ifdef USE_ENCRYPTION aes_decrypt_ctx aes_ctx[1]; MD5_CTX md5_ctx; unsigned char IV[16]; #endif // USE_ENCRYPTION #ifdef CLEAR_ON_READ if (!sd_mmc_usb_check_sector(addr, nb_sector)) return CTRL_FAIL; #endif // Try to avoid reading if the beginning is "written" #ifdef FAKE_RW for (uint32_t sector = 0; sector < nb_sector; sector++) { bool cached = false; for (uint8_t i = 0; i < NUM_CACHED_SECTORS && i < cached_sector_count; i++) { if (cached_sectors[i].sector == sector) { if (!udi_msc_trans_block(true, cached_sectors[i].contents, SD_MMC_BLOCK_SIZE, NULL)) return CTRL_FAIL; cached = true; addr++; break; } } if (!cached) break; } #endif // FAKE_RW switch (sd_mmc_init_read_blocks(slot, addr, nb_sector)) { case SD_MMC_OK: break; case SD_MMC_ERR_NO_CARD: return CTRL_NO_PRESENT; default: return CTRL_FAIL; } // Pipeline the 2 transfer in order to speed-up the performances nb_step = nb_sector + 1; bool last_cached = false; uint8_t *cached_sector = NULL, *last_cached_sector = NULL; while (nb_step--) { bool cached = false; if (nb_step) { // Skip last step // MCI -> RAM #ifdef FAKE_RW for (uint8_t i = 0; i < NUM_CACHED_SECTORS && i < cached_sector_count; i++) { if (cached_sectors[i].sector == addr + nb_sector - nb_step) { cached_sector = cached_sectors[i].contents; cached = true; //ui_set_errorflag(); break; } } #endif // FAKE_RW if (SD_MMC_OK != sd_mmc_start_read_blocks(((nb_step % 2) == 0) ? sector_buf_0 : sector_buf_1, 1)) { return CTRL_FAIL; } } if (!b_first_step) { // Skip first step #ifdef USE_ENCRYPTION uint32_t sector = addr + nb_sector - nb_step - 1; if (!last_cached) { // Decrypt if (use_user_page_values() && sector >= CRYPT_START) { // We use md5(sector) for the IV, ie a known-constant // Though this is generally a bad idea (see, eg, Google: cryptsetup aes-cbc-plain), // it (luckily) works finehere as we don't enable write. // We work under the assumption that data will either fall in the form // a) public-knowledge (eg a boot partition) or // b) encrypted random data (eg your key and surrounding random crap to mask it). // In the first case, we don't care what you can glean from the ciphertext+plaintext+IV, // in the second, you can't glean anything because its all random data anyway. MD5_Init (&md5_ctx); MD5_Update (&md5_ctx, §or, sizeof(uint32_t)); MD5_Final (IV, &md5_ctx); aes_decrypt_key128(AES_KEY, aes_ctx); aes_cbc_decrypt(((nb_step % 2) == 0) ? sector_buf_1 : sector_buf_0, aes_buf, SD_MMC_BLOCK_SIZE, IV, aes_ctx); } } #endif // USE_ENCRYPTION // RAM -> USB if (!udi_msc_trans_block(true, last_cached ? last_cached_sector : #ifdef USE_ENCRYPTION (use_user_page_values() && sector >= CRYPT_START ? aes_buf : #endif // USE_ENCRYPTION (((nb_step % 2) == 0) ? sector_buf_1 : sector_buf_0)), SD_MMC_BLOCK_SIZE, NULL)) { return CTRL_FAIL; } } else { b_first_step = false; } if (nb_step) { // Skip last step if (SD_MMC_OK != sd_mmc_wait_end_of_read_blocks()) { return CTRL_FAIL; } } b_first_step = false; last_cached = cached; last_cached_sector = cached_sector; } return CTRL_GOOD; }