Nyx: emuMMC Manage window, Tools UI, and misc updates
- Add gui_emu_tools: emuMMC Manage window with correct positioning (LV_PROTECT_PARENT + re-parent to win) - Tools: single SD button (tap = SD partition manager, 3s hold = eMMC) - Remove emuSD from Nyx UI (tabs, UMS, partition manager); keep bootloader emusd - Shorten Create emuMMC description text by one character - Storage/build/config and dependency updates Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -818,7 +818,8 @@
|
||||
* [30] 94 [10]: AUO A055TAN02 (59.05A30.002)
|
||||
* [30] 95 [10]: AUO A055TAN03 (59.05A30.003)
|
||||
* [40] 94 [10]: Sharp LQ055T1SW10 (Rev P)
|
||||
*
|
||||
* [E0] 01 [10]: Retro Remake SUPER5 OLED (Rev 01)
|
||||
* [E1] 01 [10]: Retro Remake SUPER5 OLED HD (Rev 01)
|
||||
*
|
||||
* 7.0" OLED panels for Aula SKU:
|
||||
* [50] 9B [20]: Samsung AMS699VC01-0 (Rev 2.5)
|
||||
@@ -836,6 +837,8 @@
|
||||
* 30h: AU Optronics
|
||||
* 40h: Sharp
|
||||
* 50h: Samsung
|
||||
* E0h: Retro Remake
|
||||
* E1h: Retro Remake
|
||||
*
|
||||
* Boards, Panel Size:
|
||||
* 0Fh: Icosa/Iowa, 6.2"
|
||||
@@ -854,6 +857,8 @@ enum
|
||||
PANEL_AUO_A055TAN01 = 0x1030,
|
||||
PANEL_SHP_LQ055T1SW10 = 0x1040,
|
||||
PANEL_SAM_AMS699VC01 = 0x2050,
|
||||
PANEL_RR_SUPER5_OLED_V1 = 0x10E0,
|
||||
PANEL_RR_SUPER5_OLED_HD_V1 = 0x10E1,
|
||||
|
||||
// Found on 6/2" clones. Unknown markings. Clone of AUO A062TAN01.
|
||||
// Quality seems JDI like. Has bad low backlight scaling. ID: [83] 94 [0F]. Sometimes reports [30] 94 [0F]. Both IDs have correct CRC16.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ianos.h"
|
||||
@@ -75,7 +76,7 @@ uintptr_t ianos_loader(char *path, elfType_t type, void *moduleConfig)
|
||||
uintptr_t epaddr = 0;
|
||||
|
||||
// Read library.
|
||||
fileBuf = sd_file_read(path, NULL);
|
||||
fileBuf = boot_storage_file_read(path, NULL);
|
||||
|
||||
if (!fileBuf)
|
||||
goto out;
|
||||
|
||||
@@ -10,6 +10,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <utils/types.h>
|
||||
#include <fatfs_cfg.h>
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
@@ -23,14 +24,6 @@ typedef enum {
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
typedef enum {
|
||||
DRIVE_SD = 0,
|
||||
DRIVE_RAM = 1,
|
||||
DRIVE_EMMC = 2,
|
||||
DRIVE_BIS = 3,
|
||||
DRIVE_EMU = 4
|
||||
} DDRIVE;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
#include <utils/util.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
//#define EFSPRINTF(...)
|
||||
// #define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||
#define EFSPRINTF(...)
|
||||
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
@@ -474,6 +474,10 @@ static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-define
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if FF_SIMPLE_GPT
|
||||
static const BYTE GUID_MS_Basic[16] = {0xA2,0xA0,0xD0,0xEB,0xE5,0xB9,0x33,0x44,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
|
||||
#endif
|
||||
|
||||
|
||||
/*--------------------------------*/
|
||||
/* LFN/Directory working buffer */
|
||||
@@ -3320,15 +3324,28 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */
|
||||
}
|
||||
#if FF_SIMPLE_GPT
|
||||
if (fmt >= 2) {
|
||||
/* If GPT Check the first partition */
|
||||
/* If GPT, iterate over all part entries and check MS Basic partitions */
|
||||
gpt_header_t *gpt_header = (gpt_header_t *)fs->win;
|
||||
if (move_window(fs, 1) != FR_OK) return FR_DISK_ERR;
|
||||
if (!mem_cmp(&gpt_header->signature, "EFI PART", 8)) {
|
||||
if (move_window(fs, gpt_header->part_ent_lba) != FR_OK) return FR_DISK_ERR;
|
||||
gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win;
|
||||
fs->part_type = 1;
|
||||
bsect = gpt_entry->lba_start;
|
||||
fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */
|
||||
DWORD cur_entry, ofs, part;
|
||||
part = LD2PT(vol);
|
||||
cur_entry = 0;
|
||||
for(i = 0; i < gpt_header->num_part_ents; i++){
|
||||
if (move_window(fs, gpt_header->part_ent_lba + i * sizeof(gpt_entry_t) / SS(fs))) return FR_DISK_ERR;
|
||||
ofs = i * sizeof(gpt_entry_t) % SS(fs);
|
||||
gpt_entry_t *gpt_entry = (gpt_entry_t *)fs->win + ofs;
|
||||
if (!mem_cmp(gpt_entry->type_guid, GUID_MS_Basic, 16)){
|
||||
cur_entry++;
|
||||
bsect = gpt_entry->lba_start;
|
||||
fmt = bsect ? check_fs(fs, bsect) : 3;
|
||||
if(part == 0 && fmt <= 1) break;
|
||||
if(part != 0 && cur_entry == part) break;
|
||||
}
|
||||
}
|
||||
if(part && part != cur_entry){
|
||||
fmt = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -75,7 +75,7 @@ typedef struct _max77620_regulator_t
|
||||
|
||||
static const max77620_regulator_t _pmic_regulators[] = {
|
||||
{ "sd0", 12500, 600000, 625000, 1400000, REGULATOR_SD, MAX77620_REG_SD0, MAX77620_REG_SD0_CFG, MAX77620_SD0_VOLT_MASK, {{ MAX77620_REG_FPS_SD0, 1, 7, 1 }} },
|
||||
{ "sd1", 12500, 600000, 1125000, 1237500, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} },
|
||||
{ "sd1", 12500, 600000, 1125000, 1250000, REGULATOR_SD, MAX77620_REG_SD1, MAX77620_REG_SD1_CFG, MAX77620_SD1_VOLT_MASK, {{ MAX77620_REG_FPS_SD1, 0, 1, 5 }} },
|
||||
{ "sd2", 12500, 600000, 1325000, 1350000, REGULATOR_SD, MAX77620_REG_SD2, MAX77620_REG_SD2_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD2, 1, 5, 2 }} },
|
||||
{ "sd3", 12500, 600000, 1800000, 1800000, REGULATOR_SD, MAX77620_REG_SD3, MAX77620_REG_SD3_CFG, MAX77620_SDX_VOLT_MASK, {{ MAX77620_REG_FPS_SD3, 0, 3, 3 }} },
|
||||
{ "ldo0", 25000, 800000, 1200000, 1200000, REGULATOR_LDO, MAX77620_REG_LDO0_CFG, MAX77620_REG_LDO0_CFG2, MAX77620_LDO_VOLT_MASK, {{ MAX77620_REG_FPS_LDO0, 3, 7, 0 }} },
|
||||
|
||||
357
bdk/sec/se.c
357
bdk/sec/se.c
@@ -91,33 +91,28 @@ static int _se_op_wait()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// WAR: Coherency flushing.
|
||||
if (ll_dst_ptr)
|
||||
// T210B01: IRAM/TZRAM/DRAM AHB coherency WAR.
|
||||
if (!tegra_t210 && ll_dst_ptr)
|
||||
{
|
||||
u32 timeout = get_tmr_us() + 1000000;
|
||||
// Ensure data is out from SE.
|
||||
if (tegra_t210)
|
||||
usleep(15); // Worst case scenario.
|
||||
else
|
||||
while (SE(SE_STATUS_REG) & SE_STATUS_MEM_IF_BUSY)
|
||||
{
|
||||
// T210B01 has a status bit for that.
|
||||
u32 retries = 500000;
|
||||
while (SE(SE_STATUS_REG) & SE_STATUS_MEM_IF_BUSY)
|
||||
{
|
||||
if (!retries)
|
||||
return 0;
|
||||
usleep(1);
|
||||
retries--;
|
||||
}
|
||||
if (get_tmr_us() > timeout)
|
||||
return 0;
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
// Ensure data is out from AHB.
|
||||
u32 retries = 500000;
|
||||
while (AHB_GIZMO(AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID) & MEM_WRQUE_SE_MST_ID)
|
||||
if (ll_dst_ptr->addr >= DRAM_START)
|
||||
{
|
||||
if (!retries)
|
||||
return 0;
|
||||
usleep(1);
|
||||
retries--;
|
||||
timeout = get_tmr_us() + 200000;
|
||||
while (AHB_GIZMO(AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID) & MEM_WRQUE_SE_MST_ID)
|
||||
{
|
||||
if (get_tmr_us() > timeout)
|
||||
return 0;
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,9 +131,6 @@ static int _se_execute_finalize()
|
||||
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size, bool is_oneshot)
|
||||
{
|
||||
if (dst_size > SE_LL_MAX_SIZE || src_size > SE_LL_MAX_SIZE)
|
||||
return 0;
|
||||
|
||||
ll_src_ptr = NULL;
|
||||
ll_dst_ptr = NULL;
|
||||
|
||||
@@ -178,41 +170,18 @@ static int _se_execute_oneshot(u32 op, void *dst, u32 dst_size, const void *src,
|
||||
return _se_execute(op, dst, dst_size, src, src_size, true);
|
||||
}
|
||||
|
||||
static int _se_execute_aes_oneshot(void *dst, const void *src, u32 size)
|
||||
static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
// Set optional memory interface.
|
||||
if (dst >= (void *)DRAM_START && src >= (void *)DRAM_START)
|
||||
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_MEMIF(MEMIF_MCCIF);
|
||||
if (!src || !dst)
|
||||
return 0;
|
||||
|
||||
u32 size_aligned = ALIGN_DOWN(size, SE_AES_BLOCK_SIZE);
|
||||
u32 size_residue = size % SE_AES_BLOCK_SIZE;
|
||||
int res = 1;
|
||||
u32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
|
||||
// Handle initial aligned message.
|
||||
if (size_aligned)
|
||||
{
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (size >> 4) - 1;
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = 1 - 1;
|
||||
|
||||
res = _se_execute_oneshot(SE_OP_START, dst, size_aligned, src, size_aligned);
|
||||
}
|
||||
|
||||
// Handle leftover partial message.
|
||||
if (res && size_residue)
|
||||
{
|
||||
// Copy message to a block sized buffer in case it's partial.
|
||||
u32 block[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
memcpy(block, src + size_aligned, size_residue);
|
||||
|
||||
// Use updated IV for CBC and OFB. Ignored on others.
|
||||
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;
|
||||
|
||||
res = _se_execute_oneshot(SE_OP_START, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE);
|
||||
|
||||
// Copy result back.
|
||||
memcpy(dst + size_aligned, block, size_residue);
|
||||
}
|
||||
memcpy(block, src, src_size);
|
||||
int res = _se_execute_oneshot(op, block, SE_AES_BLOCK_SIZE, block, SE_AES_BLOCK_SIZE);
|
||||
memcpy(dst, block, dst_size);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -262,14 +231,13 @@ void se_aes_key_set(u32 ks, const void *key, u32 size)
|
||||
}
|
||||
}
|
||||
|
||||
void se_aes_iv_set(u32 ks, const void *iv, u32 size)
|
||||
void se_aes_iv_set(u32 ks, const void *iv)
|
||||
{
|
||||
u32 data[SE_AES_MAX_KEY_SIZE / sizeof(u32)];
|
||||
memcpy(data, iv, size);
|
||||
u32 data[SE_AES_IV_SIZE / sizeof(u32)];
|
||||
memcpy(data, iv, SE_AES_IV_SIZE);
|
||||
|
||||
for (u32 i = 0; i < (size / sizeof(u32)); i++)
|
||||
for (u32 i = 0; i < (SE_AES_IV_SIZE / sizeof(u32)); i++)
|
||||
{
|
||||
// QUAD UPDATED_IV bit is automatically set by PKT macro.
|
||||
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i);
|
||||
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = data[i];
|
||||
}
|
||||
@@ -301,14 +269,22 @@ void se_aes_key_clear(u32 ks)
|
||||
|
||||
void se_aes_iv_clear(u32 ks)
|
||||
{
|
||||
for (u32 i = 0; i < (SE_AES_MAX_KEY_SIZE / sizeof(u32)); i++)
|
||||
for (u32 i = 0; i < (SE_AES_IV_SIZE / sizeof(u32)); i++)
|
||||
{
|
||||
// QUAD UPDATED_IV bit is automatically set by PKT macro.
|
||||
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(ORIGINAL_IV) | SE_KEYTABLE_PKT(i);
|
||||
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void se_aes_iv_updated_clear(u32 ks)
|
||||
{
|
||||
for (u32 i = 0; i < (SE_AES_IV_SIZE / 4); i++)
|
||||
{
|
||||
SE(SE_CRYPTO_KEYTABLE_ADDR_REG) = SE_KEYTABLE_SLOT(ks) | SE_KEYTABLE_QUAD(UPDATED_IV) | SE_KEYTABLE_PKT(i);
|
||||
SE(SE_CRYPTO_KEYTABLE_DATA_REG) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *seed)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_MODE(MODE_KEY128) | SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTABLE);
|
||||
@@ -319,7 +295,27 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *seed)
|
||||
return _se_execute_oneshot(SE_OP_START, NULL, 0, seed, SE_KEY_128_SIZE);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ecb(u32 ks, int enc, void *dst, const void *src, u32 size)
|
||||
int se_aes_crypt_hash(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) |
|
||||
SE_CRYPTO_HASH(HASH_ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM) |
|
||||
SE_CRYPTO_HASH(HASH_ENABLE);
|
||||
}
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (src_size >> 4) - 1;
|
||||
return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ecb(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
@@ -333,11 +329,11 @@ int se_aes_crypt_ecb(u32 ks, int enc, void *dst, const void *src, u32 size)
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT) |
|
||||
SE_CRYPTO_XOR_POS(XOR_BYPASS);
|
||||
}
|
||||
|
||||
return _se_execute_aes_oneshot(dst, src, size);
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (src_size >> 4) - 1;
|
||||
return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
int se_aes_crypt_cbc(u32 ks, int enc, void *dst, const void *src, u32 size)
|
||||
int se_aes_crypt_cbc(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
@@ -351,21 +347,16 @@ int se_aes_crypt_cbc(u32 ks, int enc, void *dst, const void *src, u32 size)
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVMEM) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
}
|
||||
|
||||
return _se_execute_aes_oneshot(dst, src, size);
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (src_size >> 4) - 1;
|
||||
return _se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ofb(u32 ks, void *dst, const void *src, u32 size)
|
||||
int se_aes_crypt_block_ecb(u32 ks, int enc, void *dst, const void *src)
|
||||
{
|
||||
SE(SE_SPARE_REG) = SE_INPUT_NONCE_LE;
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AESOUT) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
||||
|
||||
return _se_execute_aes_oneshot(dst, src, size);
|
||||
return se_aes_crypt_ecb(ks, enc, dst, SE_AES_BLOCK_SIZE, src, SE_AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, const void *src, u32 size, void *ctr)
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||
{
|
||||
SE(SE_SPARE_REG) = SE_INPUT_NONCE_LE;
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
@@ -375,10 +366,25 @@ int se_aes_crypt_ctr(u32 ks, void *dst, const void *src, u32 size, void *ctr)
|
||||
|
||||
_se_aes_counter_set(ctr);
|
||||
|
||||
return _se_execute_aes_oneshot(dst, src, size);
|
||||
u32 src_size_aligned = src_size & 0xFFFFFFF0;
|
||||
u32 src_size_delta = src_size & 0xF;
|
||||
|
||||
if (src_size_aligned)
|
||||
{
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (src_size >> 4) - 1;
|
||||
if (!_se_execute_oneshot(SE_OP_START, dst, dst_size, src, src_size_aligned))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (src_size - src_size_aligned && src_size_aligned < dst_size)
|
||||
return _se_execute_one_block(SE_OP_START, dst + src_size_aligned,
|
||||
MIN(src_size_delta, dst_size - src_size_aligned),
|
||||
src + src_size_aligned, src_size_delta);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize)
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize)
|
||||
{
|
||||
int res = 0;
|
||||
u32 tmp[SE_AES_BLOCK_SIZE / sizeof(u32)];
|
||||
@@ -392,7 +398,7 @@ int se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst
|
||||
tweak[i] = sec & 0xFF;
|
||||
sec >>= 8;
|
||||
}
|
||||
if (!se_aes_crypt_ecb(tweak_ks, ENCRYPT, tweak, tweak, SE_AES_BLOCK_SIZE))
|
||||
if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak))
|
||||
goto out;
|
||||
|
||||
// We are assuming a 0x10-aligned sector size in this implementation.
|
||||
@@ -400,7 +406,7 @@ int se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst
|
||||
{
|
||||
for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)
|
||||
pdst[j] = psrc[j] ^ tweak[j];
|
||||
if (!se_aes_crypt_ecb(crypt_ks, enc, pdst, pdst, SE_AES_BLOCK_SIZE))
|
||||
if (!se_aes_crypt_block_ecb(crypt_ks, enc, pdst, pdst))
|
||||
goto out;
|
||||
for (u32 j = 0; j < SE_AES_BLOCK_SIZE; j++)
|
||||
pdst[j] = pdst[j] ^ tweak[j];
|
||||
@@ -415,7 +421,7 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size)
|
||||
int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size)
|
||||
{
|
||||
u32 *pdst = (u32 *)dst;
|
||||
u32 *psrc = (u32 *)src;
|
||||
@@ -428,7 +434,7 @@ int se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tw
|
||||
tweak[i] = sec & 0xFF;
|
||||
sec >>= 8;
|
||||
}
|
||||
if (!se_aes_crypt_ecb(tweak_ks, ENCRYPT, tweak, tweak, SE_AES_BLOCK_SIZE))
|
||||
if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -450,7 +456,7 @@ int se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tw
|
||||
pdst += sizeof(u32);
|
||||
}
|
||||
|
||||
if (!se_aes_crypt_ecb(crypt_ks, enc, dst, dst, sec_size))
|
||||
if (!se_aes_crypt_ecb(crypt_ks, enc, dst, sec_size, dst, sec_size))
|
||||
return 0;
|
||||
|
||||
pdst = (u32 *)dst;
|
||||
@@ -467,20 +473,27 @@ int se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tw
|
||||
return 1;
|
||||
}
|
||||
|
||||
int se_aes_crypt_xts(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)
|
||||
{
|
||||
u8 *pdst = (u8 *)dst;
|
||||
u8 *psrc = (u8 *)src;
|
||||
|
||||
for (u32 i = 0; i < num_secs; i++)
|
||||
if (!se_aes_crypt_xts_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize))
|
||||
if (!se_aes_xts_crypt_sec(tweak_ks, crypt_ks, enc, sec + i, pdst + secsize * i, psrc + secsize * i, secsize))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _se_sha_hash_256_get_hash(void *hash)
|
||||
static void se_calc_sha256_get_hash(void *hash, u32 *msg_left)
|
||||
{
|
||||
// Backup message left.
|
||||
if (msg_left)
|
||||
{
|
||||
msg_left[0] = SE(SE_SHA_MSG_LEFT_0_REG);
|
||||
msg_left[1] = SE(SE_SHA_MSG_LEFT_1_REG);
|
||||
}
|
||||
|
||||
// Copy output hash.
|
||||
u32 hash32[SE_SHA_256_SIZE / sizeof(u32)];
|
||||
for (u32 i = 0; i < (SE_SHA_256_SIZE / sizeof(u32)); i++)
|
||||
@@ -488,8 +501,15 @@ static void _se_sha_hash_256_get_hash(void *hash)
|
||||
memcpy(hash, hash32, SE_SHA_256_SIZE);
|
||||
}
|
||||
|
||||
static int _se_sha_hash_256(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot)
|
||||
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot)
|
||||
{
|
||||
int res;
|
||||
u32 hash32[SE_SHA_256_SIZE / 4];
|
||||
|
||||
//! TODO: src_size must be 512 bit aligned if continuing and not last block for SHA256.
|
||||
if (src_size > 0xFFFFFF || !hash) // Max 16MB - 1 chunks and aligned x4 hash buffer.
|
||||
return 0;
|
||||
|
||||
// Src size of 0 is not supported, so return null string sha256.
|
||||
if (!src_size)
|
||||
{
|
||||
@@ -501,123 +521,79 @@ static int _se_sha_hash_256(void *hash, u64 total_size, const void *src, u32 src
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Increase leftover size if not last message. (Engine will always stop at src_size.)
|
||||
u32 msg_left = src_size;
|
||||
if (total_size < src_size)
|
||||
msg_left++;
|
||||
|
||||
// Setup config for SHA256.
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_SHA256) | SE_CONFIG_ENC_ALG(ALG_SHA) | SE_CONFIG_DST(DST_HASHREG);
|
||||
SE(SE_SHA_CONFIG_REG) = sha_cfg;
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = 1 - 1;
|
||||
|
||||
// Set total size: BITS(total_size), up to 2 EB.
|
||||
// Set total size to current buffer size if empty.
|
||||
if (!total_size)
|
||||
total_size = src_size;
|
||||
|
||||
// Set total size: BITS(src_size), up to 2 EB.
|
||||
SE(SE_SHA_MSG_LENGTH_0_REG) = (u32)(total_size << 3);
|
||||
SE(SE_SHA_MSG_LENGTH_1_REG) = (u32)(total_size >> 29);
|
||||
SE(SE_SHA_MSG_LENGTH_2_REG) = 0;
|
||||
SE(SE_SHA_MSG_LENGTH_3_REG) = 0;
|
||||
|
||||
// Set leftover size: BITS(src_size).
|
||||
SE(SE_SHA_MSG_LEFT_0_REG) = (u32)(msg_left << 3);
|
||||
SE(SE_SHA_MSG_LEFT_1_REG) = (u32)(msg_left >> 29);
|
||||
// Set size left to hash.
|
||||
SE(SE_SHA_MSG_LEFT_0_REG) = (u32)(total_size << 3);
|
||||
SE(SE_SHA_MSG_LEFT_1_REG) = (u32)(total_size >> 29);
|
||||
SE(SE_SHA_MSG_LEFT_2_REG) = 0;
|
||||
SE(SE_SHA_MSG_LEFT_3_REG) = 0;
|
||||
|
||||
// Set config based on init or partial continuation.
|
||||
if (total_size == src_size || !total_size)
|
||||
SE(SE_SHA_CONFIG_REG) = SHA_INIT_HASH;
|
||||
else
|
||||
SE(SE_SHA_CONFIG_REG) = SHA_CONTINUE;
|
||||
// If we hash in chunks, copy over the intermediate.
|
||||
if (sha_cfg == SHA_CONTINUE && msg_left)
|
||||
{
|
||||
// Restore message left to process.
|
||||
SE(SE_SHA_MSG_LEFT_0_REG) = msg_left[0];
|
||||
SE(SE_SHA_MSG_LEFT_1_REG) = msg_left[1];
|
||||
|
||||
// Trigger the operation. src vs total size decides if it's partial.
|
||||
int res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot);
|
||||
// Restore hash reg.
|
||||
memcpy(hash32, hash, SE_SHA_256_SIZE);
|
||||
for (u32 i = 0; i < (SE_SHA_256_SIZE / 4); i++)
|
||||
SE(SE_HASH_RESULT_REG + (i * 4)) = byte_swap_32(hash32[i]);
|
||||
}
|
||||
|
||||
if (res && is_oneshot)
|
||||
_se_sha_hash_256_get_hash(hash);
|
||||
// Trigger the operation.
|
||||
res = _se_execute(SE_OP_START, NULL, 0, src, src_size, is_oneshot);
|
||||
|
||||
if (is_oneshot)
|
||||
se_calc_sha256_get_hash(hash, msg_left);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_sha_hash_256_async(void *hash, const void *src, u32 size)
|
||||
int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size)
|
||||
{
|
||||
return _se_sha_hash_256(hash, size, src, size, false);
|
||||
return se_calc_sha256(hash, NULL, src, src_size, 0, SHA_INIT_HASH, true);
|
||||
}
|
||||
|
||||
int se_sha_hash_256_oneshot(void *hash, const void *src, u32 size)
|
||||
{
|
||||
return _se_sha_hash_256(hash, size, src, size, true);
|
||||
}
|
||||
|
||||
int se_sha_hash_256_partial_start(void *hash, const void *src, u32 size, bool is_oneshot)
|
||||
{
|
||||
// Check if aligned SHA256 block size.
|
||||
if (size % SE_SHA2_MIN_BLOCK_SIZE)
|
||||
return 0;
|
||||
|
||||
return _se_sha_hash_256(hash, 0, src, size, is_oneshot);
|
||||
}
|
||||
|
||||
int se_sha_hash_256_partial_update(void *hash, const void *src, u32 size, bool is_oneshot)
|
||||
{
|
||||
// Check if aligned to SHA256 block size.
|
||||
if (size % SE_SHA2_MIN_BLOCK_SIZE)
|
||||
return 0;
|
||||
|
||||
return _se_sha_hash_256(hash, size - 1, src, size, is_oneshot);
|
||||
}
|
||||
|
||||
int se_sha_hash_256_partial_end(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot)
|
||||
{
|
||||
return _se_sha_hash_256(hash, total_size, src, src_size, is_oneshot);
|
||||
}
|
||||
|
||||
int se_sha_hash_256_finalize(void *hash)
|
||||
int se_calc_sha256_finalize(void *hash, u32 *msg_left)
|
||||
{
|
||||
int res = _se_execute_finalize();
|
||||
|
||||
_se_sha_hash_256_get_hash(hash);
|
||||
se_calc_sha256_get_hash(hash, msg_left);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int se_rng_pseudo(void *dst, u32 size)
|
||||
int se_gen_prng128(void *dst)
|
||||
{
|
||||
// Setup config for SP 800-90 PRNG.
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
||||
SE(SE_RNG_CONFIG_REG) = SE_RNG_CONFIG_SRC(SRC_ENTROPY) | SE_RNG_CONFIG_MODE(MODE_NORMAL);
|
||||
SE(SE_RNG_SRC_CONFIG_REG) |= SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE); // DRBG. Depends on ENTROPY clock.
|
||||
SE(SE_RNG_RESEED_INTERVAL_REG) = 4096;
|
||||
//SE(SE_RNG_SRC_CONFIG_REG) |= SE_RNG_SRC_CONFIG_ENTR_SRC(RO_ENTR_ENABLE); // DRBG. Depends on ENTROPY clock.
|
||||
SE(SE_RNG_RESEED_INTERVAL_REG) = 1;
|
||||
|
||||
u32 size_aligned = ALIGN_DOWN(size, SE_RNG_BLOCK_SIZE);
|
||||
u32 size_residue = size % SE_RNG_BLOCK_SIZE;
|
||||
int res = 0;
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (16 >> 4) - 1;
|
||||
|
||||
// Handle initial aligned message.
|
||||
if (size_aligned)
|
||||
{
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (size >> 4) - 1;
|
||||
|
||||
res = _se_execute_oneshot(SE_OP_START, dst, size_aligned, NULL, 0);
|
||||
}
|
||||
|
||||
// Handle leftover partial message.
|
||||
if (res && size_residue)
|
||||
{
|
||||
// Copy message to a block sized buffer in case it's partial.
|
||||
u32 block[SE_RNG_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;
|
||||
|
||||
res = _se_execute_oneshot(SE_OP_START, block, SE_RNG_BLOCK_SIZE, NULL, 0);
|
||||
|
||||
// Copy result back.
|
||||
if (res)
|
||||
memcpy(dst + size_aligned, block, size_residue);
|
||||
}
|
||||
|
||||
return res;
|
||||
// Trigger the operation.
|
||||
return _se_execute_oneshot(SE_OP_START, dst, 16, NULL, 0);
|
||||
}
|
||||
|
||||
void se_aes_ctx_get_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
{
|
||||
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
|
||||
|
||||
@@ -668,13 +644,16 @@ void se_aes_ctx_get_keys(u8 *buf, u8 *keys, u32 keysize)
|
||||
srk[3] = PMC(APBDEV_PMC_SECURE_SCRATCH7);
|
||||
|
||||
// Decrypt context.
|
||||
se_aes_key_clear(3);
|
||||
se_aes_key_set(3, srk, SE_KEY_128_SIZE);
|
||||
se_aes_crypt_cbc(3, DECRYPT, keys, keys, SE_AES_KEYSLOT_COUNT * keysize);
|
||||
se_aes_crypt_cbc(3, DECRYPT, keys, SE_AES_KEYSLOT_COUNT * keysize, keys, SE_AES_KEYSLOT_COUNT * keysize);
|
||||
se_aes_key_clear(3);
|
||||
}
|
||||
|
||||
int se_aes_hash_cmac(u32 ks, void *hash, const void *src, u32 size)
|
||||
int se_aes_cmac_128(u32 ks, void *hash, const void *src, u32 size)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
u32 tmp1[SE_KEY_128_SIZE / sizeof(u32)] = {0};
|
||||
u32 tmp2[SE_AES_BLOCK_SIZE / sizeof(u32)] = {0};
|
||||
u8 *subkey = (u8 *)tmp1;
|
||||
@@ -682,54 +661,52 @@ int se_aes_hash_cmac(u32 ks, void *hash, const void *src, u32 size)
|
||||
|
||||
// Generate sub key (CBC with zeroed IV, basically ECB).
|
||||
se_aes_iv_clear(ks);
|
||||
if (!se_aes_crypt_cbc(ks, ENCRYPT, subkey, subkey, SE_KEY_128_SIZE))
|
||||
return 0;
|
||||
se_aes_iv_updated_clear(ks);
|
||||
if (!se_aes_crypt_hash(ks, ENCRYPT, subkey, SE_KEY_128_SIZE, subkey, SE_KEY_128_SIZE))
|
||||
goto out;
|
||||
|
||||
// Generate K1 subkey.
|
||||
_se_ls_1bit(subkey);
|
||||
if (size & 0xF)
|
||||
_se_ls_1bit(subkey); // Convert to K2.
|
||||
|
||||
// Switch to hash register. The rest of the config is already set.
|
||||
SE(SE_CONFIG_REG) |= SE_CONFIG_DST(DST_HASHREG);
|
||||
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_HASH(HASH_ENABLE);
|
||||
SE(SE_CONFIG_REG) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
|
||||
SE(SE_CRYPTO_CONFIG_REG) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_MEMORY) |
|
||||
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
|
||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
|
||||
se_aes_iv_clear(ks);
|
||||
se_aes_iv_updated_clear(ks);
|
||||
|
||||
// Initial blocks.
|
||||
u32 num_blocks = (size + 0xF) >> 4;
|
||||
if (num_blocks > 1)
|
||||
{
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = num_blocks - 2;
|
||||
|
||||
if (!_se_execute_oneshot(SE_OP_START, NULL, 0, src, size))
|
||||
return 0;
|
||||
|
||||
// Use updated IV for next OP as a continuation.
|
||||
goto out;
|
||||
SE(SE_CRYPTO_CONFIG_REG) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
|
||||
}
|
||||
|
||||
// Last block.
|
||||
if (size & 0xF)
|
||||
{
|
||||
memcpy(last_block, src + (size & (~0xF)), size & 0xF);
|
||||
memcpy(last_block, src + (size & ~0xF), size & 0xF);
|
||||
last_block[size & 0xF] = 0x80;
|
||||
}
|
||||
else if (size >= SE_AES_BLOCK_SIZE)
|
||||
{
|
||||
memcpy(last_block, src + size - SE_AES_BLOCK_SIZE, SE_AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < SE_KEY_128_SIZE; i++)
|
||||
last_block[i] ^= subkey[i];
|
||||
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = (SE_AES_BLOCK_SIZE >> 4) - 1;
|
||||
SE(SE_CRYPTO_LAST_BLOCK_REG) = 0;
|
||||
|
||||
int res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, SE_AES_BLOCK_SIZE);
|
||||
res = _se_execute_oneshot(SE_OP_START, NULL, 0, last_block, SE_AES_BLOCK_SIZE);
|
||||
|
||||
// Copy output hash.
|
||||
if (res)
|
||||
{
|
||||
u32 *hash32 = (u32 *)hash;
|
||||
for (u32 i = 0; i < (SE_AES_CMAC_DIGEST_SIZE / sizeof(u32)); i++)
|
||||
hash32[i] = SE(SE_HASH_RESULT_REG + sizeof(u32) * i);
|
||||
}
|
||||
u32 *hash32 = (u32 *)hash;
|
||||
for (u32 i = 0; i < (SE_AES_CMAC_DIGEST_SIZE / sizeof(u32)); i++)
|
||||
hash32[i] = SE(SE_HASH_RESULT_REG + sizeof(u32) * i);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
33
bdk/sec/se.h
33
bdk/sec/se.h
@@ -27,29 +27,28 @@ u32 se_key_acc_ctrl_get(u32 ks);
|
||||
|
||||
/*! AES Key Management Functions */
|
||||
void se_aes_key_set(u32 ks, const void *key, u32 size);
|
||||
void se_aes_iv_set(u32 ks, const void *iv, u32 size);
|
||||
void se_aes_iv_set(u32 ks, const void *iv);
|
||||
void se_aes_key_get(u32 ks, void *key, u32 size);
|
||||
void se_aes_key_clear(u32 ks);
|
||||
void se_aes_iv_clear(u32 ks);
|
||||
void se_aes_iv_updated_clear(u32 ks);
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *seed);
|
||||
void se_aes_ctx_get_keys(u8 *buf, u8 *keys, u32 keysize);
|
||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
|
||||
/*! Encryption Functions */
|
||||
int se_aes_crypt_ecb(u32 ks, int enc, void *dst, const void *src, u32 size);
|
||||
int se_aes_crypt_cbc(u32 ks, int enc, void *dst, const void *src, u32 size);
|
||||
int se_aes_crypt_ofb(u32 ks, void *dst, const void *src, u32 size);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, const void *src, u32 size, void *ctr);
|
||||
int se_aes_crypt_xts_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize);
|
||||
int se_aes_crypt_xts_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size);
|
||||
int se_aes_crypt_xts(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs);
|
||||
int se_aes_crypt_cbc(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_ecb(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_block_ecb(u32 ks, int enc, void *dst, const void *src);
|
||||
int se_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize);
|
||||
int se_aes_xts_crypt_sec_nx(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, u8 *tweak, bool regen_tweak, u32 tweak_exp, void *dst, void *src, u32 sec_size);
|
||||
int se_aes_xts_crypt(u32 tweak_ks, u32 crypt_ks, int enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs);
|
||||
/*! Hashing Functions */
|
||||
int se_sha_hash_256_async(void *hash, const void *src, u32 size);
|
||||
int se_sha_hash_256_oneshot(void *hash, const void *src, u32 size);
|
||||
int se_sha_hash_256_partial_start(void *hash, const void *src, u32 size, bool is_oneshot);
|
||||
int se_sha_hash_256_partial_update(void *hash, const void *src, u32 size, bool is_oneshot);
|
||||
int se_sha_hash_256_partial_end(void *hash, u64 total_size, const void *src, u32 src_size, bool is_oneshot);
|
||||
int se_sha_hash_256_finalize(void *hash);
|
||||
int se_aes_hash_cmac(u32 ks, void *hash, const void *src, u32 size);
|
||||
int se_aes_crypt_hash(u32 ks, int enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||
int se_calc_sha256(void *hash, u32 *msg_left, const void *src, u32 src_size, u64 total_size, u32 sha_cfg, bool is_oneshot);
|
||||
int se_calc_sha256_oneshot(void *hash, const void *src, u32 src_size);
|
||||
int se_calc_sha256_finalize(void *hash, u32 *msg_left);
|
||||
int se_aes_cmac_128(u32 ks, void *hash, const void *src, u32 size);
|
||||
/*! Random Functions */
|
||||
int se_rng_pseudo(void *dst, u32 size);
|
||||
int se_gen_prng128(void *dst);
|
||||
|
||||
#endif
|
||||
|
||||
275
bdk/storage/boot_storage.c
Normal file
275
bdk/storage/boot_storage.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include "boot_storage.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <fatfs_cfg.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/emmc.h>
|
||||
#include <utils/types.h>
|
||||
#include <gfx_utils.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DEV_INVALID 0xff
|
||||
|
||||
static FATFS boot_storage_fs;
|
||||
static BYTE drive_cur = -1;
|
||||
static BYTE drive = -1;
|
||||
|
||||
static const char* drive_base_paths[] = {
|
||||
[DRIVE_SD] = "sd:",
|
||||
[DRIVE_BOOT1] = "boot1_:",
|
||||
[DRIVE_BOOT1_1MB] = "boot1_1mb:",
|
||||
[DRIVE_EMMC] = "emmc:",
|
||||
};
|
||||
|
||||
static bool _is_eligible(){
|
||||
if(f_stat(".no_boot_storage", NULL) == FR_OK){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boot_storage_get_mounted(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
return sd_get_card_mounted();
|
||||
case DRIVE_EMMC:
|
||||
return emmc_get_mounted();
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return drive_cur != DEV_INVALID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool boot_storage_get_initialized(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return emmc_get_initialized();
|
||||
case DRIVE_SD:
|
||||
return sd_get_card_initialized();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _boot_storage_initialize(){
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return emmc_initialize(false);
|
||||
case DRIVE_SD:
|
||||
return sd_initialize(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _boot_storage_end(bool deinit){
|
||||
if(boot_storage_get_mounted()){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
sd_unmount();
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
emmc_unmount();
|
||||
break;
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
f_mount(NULL, drive_base_paths[drive_cur], 0);
|
||||
}
|
||||
drive_cur = DEV_INVALID;
|
||||
}
|
||||
|
||||
if(deinit){
|
||||
switch(drive_cur){
|
||||
case DRIVE_SD:
|
||||
sd_end();
|
||||
break;
|
||||
case DRIVE_EMMC:
|
||||
case DRIVE_BOOT1:
|
||||
case DRIVE_BOOT1_1MB:
|
||||
emmc_end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void boot_storage_unmount(){
|
||||
_boot_storage_end(false);
|
||||
}
|
||||
|
||||
void boot_storage_end(){
|
||||
_boot_storage_end(true);
|
||||
}
|
||||
|
||||
u8 boot_storage_get_drive(){
|
||||
return drive;
|
||||
}
|
||||
|
||||
static bool _boot_storage_mount(){
|
||||
// may want to check sd card first and prioritize it
|
||||
|
||||
FRESULT res;
|
||||
|
||||
bool prev_emmc_initialized = emmc_get_initialized();
|
||||
bool prev_sd_initialized = sd_get_card_initialized();
|
||||
|
||||
if(!prev_emmc_initialized && !emmc_initialize(false)){
|
||||
goto emmc_init_fail;
|
||||
}
|
||||
|
||||
static const BYTE emmc_drives[] = {DRIVE_BOOT1_1MB, DRIVE_BOOT1};
|
||||
|
||||
for(BYTE i = 0; i < ARRAY_SIZE(emmc_drives); i++){
|
||||
res = f_mount(&boot_storage_fs, drive_base_paths[emmc_drives[i]], true);
|
||||
if(res == FR_OK){
|
||||
res = f_chdrive(drive_base_paths[emmc_drives[i]]);
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = emmc_drives[i];
|
||||
drive = drive_cur;
|
||||
break;
|
||||
}else{
|
||||
f_mount(NULL, drive_base_paths[emmc_drives[i]],false);
|
||||
res = FR_INVALID_DRIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
if(!prev_emmc_initialized) {
|
||||
emmc_end();
|
||||
}
|
||||
}
|
||||
|
||||
if(res == FR_OK){
|
||||
return true;
|
||||
}
|
||||
|
||||
emmc_init_fail:
|
||||
if(!emmc_initialize(false)){
|
||||
goto emmc_init_fail2;
|
||||
}
|
||||
|
||||
if(!emmc_mount()){
|
||||
if(!prev_emmc_initialized) {
|
||||
emmc_end();
|
||||
}
|
||||
goto emmc_init_fail2;
|
||||
}
|
||||
|
||||
res = f_chdrive(drive_base_paths[DRIVE_EMMC]);
|
||||
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = DRIVE_EMMC;
|
||||
drive = drive_cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
emmc_init_fail2:
|
||||
if(!sd_initialize(false)){
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(!sd_mount()){
|
||||
if(!prev_sd_initialized) {
|
||||
sd_end();
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = f_chdrive(drive_base_paths[DRIVE_SD]);
|
||||
|
||||
if(res == FR_OK && _is_eligible()){
|
||||
drive_cur = DRIVE_SD;
|
||||
drive = drive_cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!prev_sd_initialized) {
|
||||
sd_end();
|
||||
}
|
||||
|
||||
out:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool boot_storage_mount(){
|
||||
bool mounted = boot_storage_get_mounted();
|
||||
bool initialized = boot_storage_get_initialized();
|
||||
bool res = mounted && initialized;
|
||||
if(!mounted){
|
||||
// not mounted. mounting will also initialize.
|
||||
res = _boot_storage_mount();
|
||||
}else if(!initialized){
|
||||
res = _boot_storage_initialize();
|
||||
}
|
||||
|
||||
if(res){
|
||||
res = f_chdrive(drive_base_paths[drive_cur]) == FR_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *boot_storage_file_read(const char *path, u32 *fsize)
|
||||
{
|
||||
FIL fp;
|
||||
if (!boot_storage_get_mounted())
|
||||
return NULL;
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
*fsize = size;
|
||||
|
||||
void *buf = malloc(size);
|
||||
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename)
|
||||
{
|
||||
FIL fp;
|
||||
u32 res = 0;
|
||||
if (!boot_storage_get_mounted())
|
||||
return FR_DISK_ERR;
|
||||
|
||||
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
f_write(&fp, buf, size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FATFS *boot_storage_get_fs() {
|
||||
switch(drive_cur){
|
||||
case DRIVE_BOOT1:
|
||||
return &boot_storage_fs;
|
||||
case DRIVE_EMMC:
|
||||
return &emmc_fs;
|
||||
case DRIVE_BOOT1_1MB:
|
||||
return &boot_storage_fs;
|
||||
case DRIVE_SD:
|
||||
return &sd_fs;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
24
bdk/storage/boot_storage.h
Normal file
24
bdk/storage/boot_storage.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _BOOT_STORAGE_H
|
||||
#define _BOOT_STORAGE_H
|
||||
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
// check if boot1 (1mb), boot1, gpp, sd (in that order) have fat32 partition,
|
||||
// mount the partition and set the current drive to it
|
||||
bool boot_storage_mount();
|
||||
|
||||
void boot_storage_unmount();
|
||||
void boot_storage_end();
|
||||
|
||||
bool boot_storage_get_mounted();
|
||||
bool boot_storage_get_initialized();
|
||||
|
||||
void *boot_storage_file_read(const char *path, u32 *fsize);
|
||||
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename);
|
||||
|
||||
FATFS *boot_storage_get_fs();
|
||||
|
||||
u8 boot_storage_get_drive();
|
||||
|
||||
#endif
|
||||
@@ -21,10 +21,14 @@
|
||||
#include <mem/heap.h>
|
||||
#include <soc/fuse.h>
|
||||
#include <storage/mbr_gpt.h>
|
||||
#include <gfx_utils.h>
|
||||
#include <utils/list.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
|
||||
static u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors.
|
||||
static u32 emmc_mode = EMMC_MMC_HS400;
|
||||
static bool emmc_init_done = false;
|
||||
static bool emmc_mounted = false;
|
||||
|
||||
sdmmc_t emmc_sdmmc;
|
||||
sdmmc_storage_t emmc_storage;
|
||||
@@ -61,7 +65,26 @@ u32 emmc_get_mode()
|
||||
return emmc_mode;
|
||||
}
|
||||
|
||||
void emmc_end() { sdmmc_storage_end(&emmc_storage); }
|
||||
static void _emmc_deinit(bool deinit){
|
||||
if(emmc_init_done){
|
||||
// TODO: Allow unmount even when not init'd?
|
||||
if(emmc_mounted){
|
||||
f_mount(NULL, "emmc:", 0);
|
||||
}
|
||||
|
||||
if(deinit){
|
||||
sdmmc_storage_end(&emmc_storage);
|
||||
emmc_init_done = false;
|
||||
}
|
||||
}
|
||||
emmc_mounted = false;
|
||||
}
|
||||
|
||||
void emmc_end() { _emmc_deinit(true); }
|
||||
|
||||
bool emmc_get_initialized(){
|
||||
return emmc_init_done;
|
||||
}
|
||||
|
||||
int emmc_init_retry(bool power_cycle)
|
||||
{
|
||||
@@ -97,7 +120,13 @@ int emmc_init_retry(bool power_cycle)
|
||||
emmc_mode = EMMC_MMC_HS400;
|
||||
}
|
||||
|
||||
return sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
|
||||
int res = sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
|
||||
if(res){
|
||||
emmc_init_done = true;
|
||||
}else{
|
||||
emmc_init_done = false;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool emmc_initialize(bool power_cycle)
|
||||
@@ -212,6 +241,14 @@ int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *bu
|
||||
#endif
|
||||
}
|
||||
|
||||
sdmmc_storage_t *emmc_part_get_storage(){
|
||||
#ifdef BDK_EMUMMC_ENABLE
|
||||
return emummc_get_storage();
|
||||
#else
|
||||
return &emmc_storage;
|
||||
#endif
|
||||
}
|
||||
|
||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
||||
{
|
||||
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
|
||||
@@ -225,3 +262,44 @@ void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
||||
*mod1 = 0x84;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool emmc_mount()
|
||||
{
|
||||
if (emmc_init_done && emmc_mounted)
|
||||
return true;
|
||||
|
||||
int res = 0;
|
||||
|
||||
if (!emmc_init_done)
|
||||
res = !emmc_initialize(false);
|
||||
|
||||
if (res)
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTF("Failed to init eMMC.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!emmc_mounted)
|
||||
res = f_mount(&emmc_fs, "emmc:", 1); // Volume 0 is SD.
|
||||
if (res == FR_OK)
|
||||
{
|
||||
emmc_mounted = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_con.mute = false;
|
||||
EPRINTFARGS("Failed to mount eMMC (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool emmc_get_mounted(){
|
||||
return emmc_mounted;
|
||||
}
|
||||
|
||||
void emmc_unmount() { _emmc_deinit(false); }
|
||||
@@ -65,12 +65,17 @@ int emmc_init_retry(bool power_cycle);
|
||||
bool emmc_initialize(bool power_cycle);
|
||||
int emmc_set_partition(u32 partition);
|
||||
void emmc_end();
|
||||
bool emmc_mount();
|
||||
void emmc_unmount();
|
||||
bool emmc_get_initialized();
|
||||
bool emmc_get_mounted();
|
||||
|
||||
void emmc_gpt_parse(link_t *gpt);
|
||||
void emmc_gpt_free(link_t *gpt);
|
||||
emmc_part_t *emmc_part_find(link_t *gpt, const char *name);
|
||||
int emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
||||
int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
||||
sdmmc_storage_t *emmc_part_get_storage();
|
||||
|
||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);
|
||||
|
||||
|
||||
233
bdk/storage/emummc_file_based.c
Normal file
233
bdk/storage/emummc_file_based.c
Normal file
@@ -0,0 +1,233 @@
|
||||
#include "emummc_file_based.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <gfx_utils.h>
|
||||
|
||||
// TODO: fast read/writes
|
||||
|
||||
static FIL active_file;
|
||||
// -0xff: none, -1: boot 0, -2: boot1, 0+: gpp
|
||||
static s32 active_file_idx;
|
||||
static char file_based_base_path[0x80];
|
||||
static u32 file_part_sz_sct;
|
||||
static u32 active_part;
|
||||
static u32 file_based_base_path_len;
|
||||
|
||||
static int _emummc_storage_file_based_read_write_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return FR_WRITE_PROTECTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
int res = f_lseek(&active_file, (u64)sector << 9);
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
if(is_write){
|
||||
res = f_write(&active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}else{
|
||||
res = f_read(&active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int _emummc_storage_file_based_change_file(const char *name, s32 idx){
|
||||
int res;
|
||||
|
||||
if(active_file_idx == idx){
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
if(active_file_idx != -0xff){
|
||||
f_close(&active_file);
|
||||
active_file_idx = -0xff;
|
||||
}
|
||||
|
||||
strcpy(file_based_base_path + file_based_base_path_len, name);
|
||||
|
||||
|
||||
#if FF_FS_READONLY == 1
|
||||
res = f_open(&active_file, file_based_base_path, FA_READ);
|
||||
#else
|
||||
res = f_open(&active_file, file_based_base_path, FA_READ | FA_WRITE);
|
||||
#endif
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
active_file_idx = idx;
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int _emummc_storage_file_based_read_write(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(file_part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res;
|
||||
|
||||
if(active_part == 1){
|
||||
// boot0
|
||||
res = _emummc_storage_file_based_change_file("BOOT0", -1);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}else if(active_part == 2){
|
||||
// boot1
|
||||
res = _emummc_storage_file_based_change_file("BOOT1", -2);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write) == FR_OK;
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}else if(active_part == 0){
|
||||
// GPP
|
||||
if(file_part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u32 scts_left = num_sectors;
|
||||
u32 cur_sct = sector;
|
||||
while(scts_left){
|
||||
// offset within file
|
||||
u32 offset = cur_sct % file_part_sz_sct;
|
||||
// read up to start of next file or sectors left, whatever is less
|
||||
u32 sct_cnt = file_part_sz_sct - offset;
|
||||
sct_cnt = MIN(sct_cnt, scts_left);
|
||||
|
||||
u32 file_idx = cur_sct / file_part_sz_sct;
|
||||
|
||||
if((s32)file_idx != active_file_idx){
|
||||
char name[3] = "";
|
||||
if(file_idx < 10){
|
||||
strcpy(name, "0");
|
||||
}
|
||||
itoa(file_idx, name + strlen(name), 10);
|
||||
|
||||
|
||||
res = _emummc_storage_file_based_change_file(name, file_idx);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = _emummc_storage_file_based_read_write_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
|
||||
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_sct += sct_cnt;
|
||||
scts_left -= sct_cnt;
|
||||
}
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
f_sync(&active_file);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int emummc_storage_file_base_set_partition(u32 partition){
|
||||
active_part = partition;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int emummc_storage_file_based_init(const char *path){
|
||||
strcpy(file_based_base_path, path);
|
||||
file_based_base_path_len = strlen(file_based_base_path);
|
||||
strcat(file_based_base_path + file_based_base_path_len, "00");
|
||||
|
||||
active_part = 0;
|
||||
|
||||
FILINFO fi;
|
||||
if(f_stat(file_based_base_path, &fi) != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
file_part_sz_sct = 0;
|
||||
if(fi.fsize){
|
||||
file_part_sz_sct = fi.fsize >> 9;
|
||||
}
|
||||
|
||||
active_file_idx = -0xff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void emummc_storage_file_based_end(){
|
||||
if(active_file_idx != -0xff){
|
||||
f_close(&active_file);
|
||||
}
|
||||
active_file_idx = -0xff;
|
||||
file_based_base_path[0] = '\0';
|
||||
file_part_sz_sct = 0;
|
||||
}
|
||||
|
||||
#if FF_FS_READONLY == 0
|
||||
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf){
|
||||
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf){
|
||||
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, false);
|
||||
}
|
||||
|
||||
u32 emummc_storage_file_based_get_total_gpp_size(const char *path){
|
||||
u32 path_len = strlen(path);
|
||||
u32 total_size_sct = 0;
|
||||
char file_path[0x80];
|
||||
u32 cur_idx = 0;
|
||||
int res;
|
||||
|
||||
strcpy(file_path, path);
|
||||
strcpy(file_path + path_len, "00");
|
||||
|
||||
FILINFO fi;
|
||||
res = f_stat(file_path, &fi);
|
||||
|
||||
while(res == FR_OK){
|
||||
cur_idx++;
|
||||
total_size_sct += fi.fsize >> 9;
|
||||
|
||||
char name[3] = "0";
|
||||
if(cur_idx >= 10){
|
||||
name[0] = '\0';
|
||||
}
|
||||
itoa(cur_idx, name + strlen(name), 10);
|
||||
|
||||
strcpy(file_path + path_len, name);
|
||||
|
||||
res = f_stat(file_path, &fi);
|
||||
}
|
||||
|
||||
return total_size_sct;
|
||||
}
|
||||
14
bdk/storage/emummc_file_based.h
Normal file
14
bdk/storage/emummc_file_based.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _EMUMMC_FILE_BASED_H
|
||||
#define _EMUMMC_FILE_BASED_H
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
int emummc_storage_file_base_set_partition(u32 partition);
|
||||
int emummc_storage_file_based_init(const char *path);
|
||||
void emummc_storage_file_based_end();
|
||||
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf);
|
||||
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf);
|
||||
u32 emummc_storage_file_based_get_total_gpp_size(const char *path);
|
||||
sdmmc_storage_t *emummc_get_storage();
|
||||
|
||||
#endif
|
||||
184
bdk/storage/file_based_storage.c
Normal file
184
bdk/storage/file_based_storage.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "file_based_storage.h"
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct{
|
||||
FIL active_file;
|
||||
s32 active_file_idx;
|
||||
char base_path[0x80];
|
||||
u32 part_sz_sct;
|
||||
u32 base_path_len;
|
||||
}file_based_storage_ctxt_t;
|
||||
|
||||
static file_based_storage_ctxt_t ctx;
|
||||
|
||||
int file_based_storage_init(const char *base_path) {
|
||||
ctx.active_file_idx = -0xff;
|
||||
ctx.base_path_len = strlen(base_path);
|
||||
|
||||
strcpy(ctx.base_path, base_path);
|
||||
strcat(ctx.base_path, "00");
|
||||
|
||||
FILINFO fi;
|
||||
if(f_stat(ctx.base_path, &fi) != FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fi.fsize) {
|
||||
ctx.part_sz_sct = fi.fsize >> 9;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
ctx.part_sz_sct = fi.fsize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void file_based_storage_end() {
|
||||
if(ctx.active_file_idx != -0xff) {
|
||||
f_close(&ctx.active_file);
|
||||
}
|
||||
ctx.active_file_idx = -0xff;
|
||||
ctx.part_sz_sct = 0;
|
||||
}
|
||||
|
||||
static int file_based_storage_change_file(const char *name, s32 idx) {
|
||||
int res;
|
||||
|
||||
if(ctx.active_file_idx == idx){
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
if(ctx.active_file_idx != -0xff){
|
||||
f_close(&ctx.active_file);
|
||||
ctx.active_file_idx = -0xff;
|
||||
}
|
||||
|
||||
strcpy(ctx.base_path + ctx.base_path_len, name);
|
||||
|
||||
#if FF_FS_READONLY == 1
|
||||
res = f_open(&ctx.active_file, ctx.base_path, FA_READ);
|
||||
#else
|
||||
res = f_open(&ctx.active_file, ctx.base_path, FA_READ | FA_WRITE);
|
||||
#endif
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
ctx.active_file_idx = idx;
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
static int file_based_storage_readwrite_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return FR_WRITE_PROTECTED;
|
||||
}
|
||||
#endif
|
||||
|
||||
int res = f_lseek(&ctx.active_file, (u64)sector << 9);
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
if(is_write){
|
||||
res = f_write(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}else{
|
||||
res = f_read(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
|
||||
}
|
||||
|
||||
if(res != FR_OK){
|
||||
return res;
|
||||
}
|
||||
|
||||
return FR_OK;
|
||||
}
|
||||
|
||||
int file_based_storage_readwrite(u32 sector, u32 num_sectors, void *buf, bool is_write) {
|
||||
#if FF_FS_READONLY == 1
|
||||
if(is_write){
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ctx.part_sz_sct == 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res;
|
||||
|
||||
u32 scts_left = num_sectors;
|
||||
u32 cur_sct = sector;
|
||||
|
||||
while(scts_left){
|
||||
u32 offset = cur_sct % ctx.part_sz_sct;
|
||||
u32 sct_cnt = ctx.part_sz_sct - offset;
|
||||
sct_cnt = MIN(scts_left, sct_cnt);
|
||||
|
||||
u32 file_idx = cur_sct / ctx.part_sz_sct;
|
||||
|
||||
if((s32) file_idx != ctx.active_file_idx) {
|
||||
char name[3];
|
||||
if(file_idx < 10){
|
||||
strcpy(name, "0");
|
||||
}
|
||||
itoa(file_idx, name + strlen(name), 10);
|
||||
|
||||
res = file_based_storage_change_file(name, file_idx);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = file_based_storage_readwrite_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
|
||||
if(res != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_sct += sct_cnt;
|
||||
scts_left -= sct_cnt;
|
||||
}
|
||||
|
||||
f_sync(&ctx.active_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf) {
|
||||
return file_based_storage_readwrite(sector, num_sectors, buf, false);
|
||||
}
|
||||
|
||||
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf) {
|
||||
return file_based_storage_readwrite(sector, num_sectors, buf, true);
|
||||
}
|
||||
|
||||
u32 file_based_storage_get_total_size() {
|
||||
u32 total_size_sct = 0;
|
||||
char file_path[0x80];
|
||||
u32 cur_idx = 0;
|
||||
int res;
|
||||
|
||||
strcpy(file_path, ctx.base_path);
|
||||
strcpy(file_path + ctx.base_path_len, "00");
|
||||
|
||||
FILINFO fi;
|
||||
res = f_stat(file_path, &fi);
|
||||
|
||||
while(res == FR_OK){
|
||||
cur_idx++;
|
||||
total_size_sct += fi.fsize >> 9;
|
||||
|
||||
char name[3] = "0";
|
||||
if(cur_idx >= 10){
|
||||
name[0] = '\0';
|
||||
}
|
||||
itoa(cur_idx, name + strlen(name), 10);
|
||||
|
||||
strcpy(file_path + ctx.base_path_len, name);
|
||||
|
||||
res = f_stat(file_path, &fi);
|
||||
}
|
||||
|
||||
return total_size_sct;
|
||||
}
|
||||
15
bdk/storage/file_based_storage.h
Normal file
15
bdk/storage/file_based_storage.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef _FILE_BASED_STORAGE_H
|
||||
#define _FILE_BASED_STORAGE_H
|
||||
|
||||
#include <bdk.h>
|
||||
|
||||
|
||||
int file_based_storage_init(const char *base_path);
|
||||
void file_based_storage_end();
|
||||
|
||||
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf);
|
||||
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf);
|
||||
|
||||
u32 file_based_storage_get_total_size();
|
||||
|
||||
#endif
|
||||
39
bdk/storage/mbr_gpt.c
Normal file
39
bdk/storage/mbr_gpt.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "mbr_gpt.h"
|
||||
#include <utils/types.h>
|
||||
#include <string.h>
|
||||
|
||||
bool mbr_has_gpt(const mbr_t *mbr){
|
||||
for(u32 i = 0; i < 4; i++){
|
||||
if(mbr->partitions[i].type == 0xee){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void wctombs(const u16 *src, char *dest, u32 len_max){
|
||||
const u16 *cur = src;
|
||||
do{
|
||||
*dest++ = *cur & 0xff;
|
||||
len_max--;
|
||||
}while(*cur++ && len_max);
|
||||
}
|
||||
|
||||
void ctowcs(const char *src, u16 *dest, u32 len_max){
|
||||
const char *cur = src;
|
||||
do{
|
||||
*dest++ = *cur;
|
||||
len_max--;
|
||||
}while(*cur++ && len_max);
|
||||
}
|
||||
|
||||
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev){
|
||||
u16 wc_name[36];
|
||||
ctowcs(name, wc_name, 36);
|
||||
for(s32 i = prev + 1; i < (s32)gpt->header.num_part_ents && i < 128; i++){
|
||||
if(!memcmp(wc_name, gpt->entries[i].name, strlen(name) * 2)){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -81,4 +81,10 @@ typedef struct _gpt_t
|
||||
gpt_entry_t entries[128];
|
||||
} gpt_t;
|
||||
|
||||
bool mbr_has_gpt(const mbr_t *mbr);
|
||||
void wctombs(const u16 *src, char *dest, u32 len_max);
|
||||
void ctowcs(const char *src, u16 *dest, u32 len_max);
|
||||
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libs/fatfs/ff.h>
|
||||
#include <stdlib.h>
|
||||
#include <storage/nx_emmc_bis.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory_map.h>
|
||||
@@ -26,6 +29,7 @@
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/sd.h>
|
||||
#include <storage/sdmmc.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
#define BIS_CLUSTER_SECTORS 32
|
||||
@@ -56,6 +60,8 @@ static u32 emu_offset = 0;
|
||||
static emmc_part_t *system_part = NULL;
|
||||
static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;
|
||||
static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;
|
||||
static sdmmc_storage_t *emu_storage = NULL;
|
||||
static bool file_based = false;
|
||||
|
||||
static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)
|
||||
{
|
||||
@@ -91,14 +97,18 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush
|
||||
}
|
||||
|
||||
// Encrypt cluster.
|
||||
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))
|
||||
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))
|
||||
return 1; // Encryption error.
|
||||
|
||||
// If not reading from cache, do a regular read and decrypt.
|
||||
if (!emu_offset)
|
||||
if(emu_storage){
|
||||
res = sdmmc_storage_write(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_write(system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_write(system_part, sector, count, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
@@ -155,10 +165,13 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
|
||||
u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS;
|
||||
|
||||
// If not reading from cache, do a regular read and decrypt.
|
||||
if (!emu_offset)
|
||||
if(emu_storage){
|
||||
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_read(system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_read(system_part, sector, count, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||
}
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
@@ -177,7 +190,7 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
|
||||
tweak_exp = sector_in_cluster;
|
||||
|
||||
// Maximum one cluster (1 XTS crypto block 16KB).
|
||||
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))
|
||||
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))
|
||||
return 1; // R/W error.
|
||||
|
||||
prev_sector = sector + count - 1;
|
||||
@@ -212,15 +225,19 @@ static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)
|
||||
cache_lookup_tbl[cluster] = bis_cache->top_idx;
|
||||
|
||||
// Read the whole cluster the sector resides in.
|
||||
if (!emu_offset)
|
||||
if (emu_storage){
|
||||
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}else if(file_based){
|
||||
res = emummc_storage_file_based_read(system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}else{
|
||||
res = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
else
|
||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
return 1; // R/W error.
|
||||
|
||||
// Decrypt cluster.
|
||||
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
|
||||
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
|
||||
return 1; // Decryption error.
|
||||
|
||||
// Copy to cluster cache.
|
||||
@@ -292,10 +309,11 @@ int nx_emmc_bis_write(u32 sector, u32 count, void *buff)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset)
|
||||
{
|
||||
system_part = part;
|
||||
emu_offset = emummc_offset;
|
||||
emu_storage = storage;
|
||||
|
||||
_nx_emmc_bis_cluster_cache_init(enable_cache);
|
||||
|
||||
@@ -318,8 +336,31 @@ void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
|
||||
system_part = NULL;
|
||||
}
|
||||
|
||||
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path){
|
||||
emummc_storage_file_based_init(base_path);
|
||||
file_based = true;
|
||||
|
||||
nx_emmc_bis_init(part, enable_cache, NULL, 0);
|
||||
}
|
||||
|
||||
void nx_emmc_bis_end()
|
||||
{
|
||||
_nx_emmc_bis_flush_cache();
|
||||
|
||||
if(file_based){
|
||||
emummc_storage_file_based_end();
|
||||
}
|
||||
|
||||
system_part = NULL;
|
||||
emu_storage = NULL;
|
||||
emu_offset = 0;
|
||||
file_based = false;
|
||||
}
|
||||
|
||||
sdmmc_storage_t *nx_emmc_bis_get_storage(){
|
||||
if(emu_storage == &emmc_storage){
|
||||
return &emmc_storage;
|
||||
}else{
|
||||
return emmc_part_get_storage();
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,10 @@ typedef struct _nx_emmc_cal0_t
|
||||
|
||||
int nx_emmc_bis_read(u32 sector, u32 count, void *buff);
|
||||
int nx_emmc_bis_write(u32 sector, u32 count, void *buff);
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset);
|
||||
// when storage == NULL, use active emummc config, otherwise, access storage at offset
|
||||
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset);
|
||||
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path);
|
||||
void nx_emmc_bis_end();
|
||||
sdmmc_storage_t *nx_emmc_bis_get_storage();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,7 +44,7 @@ int ram_disk_init(void *ram_fs, u32 ramdisk_size)
|
||||
disk_set_info(DRIVE_RAM, SET_SECTOR_COUNT, &ramdisk_size);
|
||||
|
||||
// Unmount ramdisk.
|
||||
f_unmount("ram:");
|
||||
f_mount(NULL, "ram:", 1);
|
||||
|
||||
// Format as exFAT w/ 32KB cluster with no MBR.
|
||||
res = f_mkfs("ram:", FM_EXFAT | FM_SFD, RAMDISK_CLUSTER_SZ, buf, 0x400000);
|
||||
|
||||
@@ -199,7 +199,7 @@ bool sd_mount()
|
||||
else
|
||||
{
|
||||
if (!sd_mounted)
|
||||
res = f_mount(&sd_fs, "0:", 1); // Volume 0 is SD.
|
||||
res = f_mount(&sd_fs, "sd:", 1); // Volume 0 is SD.
|
||||
if (res == FR_OK)
|
||||
{
|
||||
sd_mounted = true;
|
||||
@@ -227,7 +227,7 @@ static void _sd_deinit(bool deinit)
|
||||
if (sd_init_done)
|
||||
{
|
||||
if (sd_mounted)
|
||||
f_unmount("0:"); // Volume 0 is SD.
|
||||
f_mount(NULL, "sd:", 1); // Volume 0 is SD.
|
||||
|
||||
if (deinit)
|
||||
{
|
||||
@@ -246,14 +246,30 @@ bool sd_is_gpt()
|
||||
return sd_fs.part_type;
|
||||
}
|
||||
|
||||
|
||||
void *sd_file_read(const char *path, u32 *fsize)
|
||||
{
|
||||
FIL fp;
|
||||
if (!sd_get_card_mounted())
|
||||
return NULL;
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
char *cwd = (char*)malloc(0x200);
|
||||
|
||||
if(f_getcwd(cwd, 0x200) != FR_OK){
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(f_chdrive("sd:") != FR_OK){
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK){
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
if (fsize)
|
||||
@@ -263,13 +279,17 @@ void *sd_file_read(const char *path, u32 *fsize)
|
||||
|
||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||
{
|
||||
f_chdrive(cwd);
|
||||
free(buf);
|
||||
free(cwd);
|
||||
f_close(&fp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f_chdrive(cwd);
|
||||
f_close(&fp);
|
||||
free(cwd);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -281,13 +301,33 @@ int sd_save_to_file(const void *buf, u32 size, const char *filename)
|
||||
if (!sd_get_card_mounted())
|
||||
return FR_DISK_ERR;
|
||||
|
||||
char *cwd = malloc(0x200);
|
||||
|
||||
res = f_getcwd(cwd, 0x200);
|
||||
|
||||
if(res != FR_OK){
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = f_chdrive("sd:");
|
||||
|
||||
if(res != FR_OK){
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
|
||||
if (res)
|
||||
{
|
||||
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
return res;
|
||||
}
|
||||
|
||||
f_chdrive(cwd);
|
||||
free(cwd);
|
||||
f_write(&fp, buf, size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
|
||||
@@ -31,8 +31,13 @@ extern u32 sd_power_cycle_time_start;
|
||||
|
||||
typedef enum _sdmmc_type
|
||||
{
|
||||
MMC_SD = 0,
|
||||
MMC_EMMC = 1,
|
||||
MMC_SD = 0,
|
||||
MMC_EMMC = 1,
|
||||
MMC_EMUMMC_FILE = 2,
|
||||
MMC_EMUMMC_RAW_SD = 3,
|
||||
MMC_EMUMMC_RAW_EMMC = 4,
|
||||
MMC_EMUMMC_FILE_EMMC = 5,
|
||||
MMC_FILE_BASED = 6,
|
||||
|
||||
EMMC_GPP = 0,
|
||||
EMMC_BOOT0 = 1,
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/emmc.h>
|
||||
#include <storage/emummc_file_based.h>
|
||||
#include <storage/file_based_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <usb/usbd.h>
|
||||
@@ -495,8 +498,18 @@ static int _scsi_read(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
}
|
||||
|
||||
// Do the SDMMC read.
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, sdmmc_buf))
|
||||
amount = 0;
|
||||
}else if (ums->lun.type == MMC_FILE_BASED) {
|
||||
if(!file_based_storage_read(ums->lun.offset + lba_offset, amount, sdmmc_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_read(ums->lun.offset + lba_offset, amount, sdmmc_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the async USB transfer to finish.
|
||||
if (!first_read)
|
||||
@@ -650,9 +663,19 @@ static int _scsi_write(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
goto empty_write;
|
||||
|
||||
// Perform the write.
|
||||
if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset,
|
||||
amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_write(ums->lun.storage, ums->lun.offset + lba_offset,
|
||||
amount >> UMS_DISK_LBA_SHIFT, (u8 *)bulk_ctxt->bulk_out_buf))
|
||||
amount = 0;
|
||||
}else if(ums->lun.type == MMC_FILE_BASED){
|
||||
if(!file_based_storage_write(ums->lun.offset + lba_offset, amount >> UMS_DISK_LBA_SHIFT, (u8*)bulk_ctxt->bulk_out_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_write(ums->lun.offset + lba_offset, amount >> UMS_DISK_LBA_SHIFT, (u8*)bulk_ctxt->bulk_out_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("file write %X @ %X\n", amount, lba_offset);
|
||||
|
||||
@@ -722,8 +745,18 @@ static int _scsi_verify(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf))
|
||||
amount = 0;
|
||||
if(ums->lun.storage){
|
||||
if (!sdmmc_storage_read(ums->lun.storage, ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf))
|
||||
amount = 0;
|
||||
}else if(ums->lun.type == MMC_FILE_BASED){
|
||||
if(!file_based_storage_read(ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}else{
|
||||
if(!emummc_storage_file_based_read(ums->lun.offset + lba_offset, amount, bulk_ctxt->bulk_in_buf)){
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTF("File read %X @ %X\n", amount, lba_offset);
|
||||
|
||||
@@ -756,8 +789,12 @@ static int _scsi_inquiry(usbd_gadget_ums_t *ums, bulk_ctxt_t *bulk_ctxt)
|
||||
buf[3] = 20; // Additional length.
|
||||
|
||||
buf += 4;
|
||||
s_printf((char *)buf, "%04X%s",
|
||||
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
|
||||
if(ums->lun.storage){
|
||||
s_printf((char *)buf, "%04X%s",
|
||||
ums->lun.storage->cid.serial, ums->lun.type == MMC_SD ? " SD " : " eMMC ");
|
||||
}else{
|
||||
strcpy((char*)buf, "0000 emuMMC");
|
||||
}
|
||||
|
||||
switch (ums->lun.partition)
|
||||
{
|
||||
@@ -1861,7 +1898,7 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
if (usbs->type == MMC_SD)
|
||||
{
|
||||
sd_end();
|
||||
if (!sd_mount())
|
||||
if (!sd_mount() && !sd_get_card_initialized())
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
@@ -1871,9 +1908,50 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
|
||||
ums.lun.sdmmc = &sd_sdmmc;
|
||||
ums.lun.storage = &sd_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_FILE){
|
||||
// sd must be already mounted and emummc file based initialized
|
||||
if(!sd_get_card_mounted()){
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
else if(usbs->type == MMC_EMUMMC_RAW_EMMC){
|
||||
if (!emmc_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
emmc_set_partition(EMMC_GPP);
|
||||
|
||||
ums.lun.sdmmc = &emmc_sdmmc;
|
||||
ums.lun.storage = &emmc_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_RAW_SD){
|
||||
if (!sd_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init SD!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
ums.lun.sdmmc = &emmc_sdmmc;
|
||||
ums.lun.storage = &emmc_storage;
|
||||
}else if(usbs->type == MMC_EMUMMC_FILE_EMMC){
|
||||
if(!emmc_get_mounted()){
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
res = 1;
|
||||
goto init_fail;
|
||||
}
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
}else if(usbs->type == MMC_FILE_BASED){
|
||||
// file based must be initialized at this point
|
||||
ums.lun.storage = NULL;
|
||||
ums.lun.sdmmc = NULL;
|
||||
} else{
|
||||
if (!emmc_initialize(false))
|
||||
{
|
||||
ums.set_text(ums.label, "#FFDD00 Failed to init eMMC!#");
|
||||
@@ -1902,10 +1980,27 @@ int usb_device_gadget_ums(usb_ctxt_t *usbs)
|
||||
// If partition sectors are not set get them from hardware.
|
||||
if (!ums.lun.num_sectors)
|
||||
{
|
||||
if (usbs->type == MMC_EMMC && (ums.lun.partition - 1)) // eMMC BOOT0/1.
|
||||
ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;
|
||||
else
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt; // eMMC GPP or SD.
|
||||
switch(usbs->type){
|
||||
case MMC_EMMC:
|
||||
if(ums.lun.partition - 1){
|
||||
ums.lun.num_sectors = emmc_storage.ext_csd.boot_mult << 8;
|
||||
}else{
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt;
|
||||
}
|
||||
break;
|
||||
case MMC_SD:
|
||||
ums.lun.num_sectors = ums.lun.storage->sec_cnt;
|
||||
break;
|
||||
case MMC_EMUMMC_FILE:
|
||||
case MMC_EMUMMC_FILE_EMMC:
|
||||
case MMC_EMUMMC_RAW_SD:
|
||||
case MMC_EMUMMC_RAW_EMMC:
|
||||
ums.set_text(ums.label, "#FFDD00 No sector count set for emuMMC!#");
|
||||
break;
|
||||
case MMC_FILE_BASED:
|
||||
ums.set_text(ums.label, "#FFDD00 No sector count set for emuSD!#");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
|
||||
@@ -22,15 +22,12 @@
|
||||
#include <mem/heap.h>
|
||||
#include <utils/types.h>
|
||||
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, u32 flags)
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs)
|
||||
{
|
||||
int res = 0;
|
||||
u32 k = 0;
|
||||
DIR dir;
|
||||
FILINFO fno;
|
||||
bool show_hidden = !!(flags & DIR_SHOW_HIDDEN);
|
||||
bool show_dirs = !!(flags & DIR_SHOW_DIRS);
|
||||
bool ascii_order = !!(flags & DIR_ASCII_ORDER);
|
||||
|
||||
dirlist_t *dir_entries = (dirlist_t *)malloc(sizeof(dirlist_t));
|
||||
|
||||
@@ -46,11 +43,11 @@ dirlist_t *dirlist(const char *directory, const char *pattern, u32 flags)
|
||||
if (res || !fno.fname[0])
|
||||
break;
|
||||
|
||||
bool curr_parse = show_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR);
|
||||
bool curr_parse = parse_dirs ? (fno.fattrib & AM_DIR) : !(fno.fattrib & AM_DIR);
|
||||
|
||||
if (curr_parse)
|
||||
{
|
||||
if ((fno.fname[0] != '.') && (show_hidden || !(fno.fattrib & AM_HID)))
|
||||
if ((fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
strcpy(&dir_entries->data[k * 256], fno.fname);
|
||||
if (++k >= DIR_MAX_ENTRIES)
|
||||
@@ -64,7 +61,7 @@ dirlist_t *dirlist(const char *directory, const char *pattern, u32 flags)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (show_hidden || !(fno.fattrib & AM_HID)))
|
||||
if (!(fno.fattrib & AM_DIR) && (fno.fname[0] != '.') && (includeHiddenFiles || !(fno.fattrib & AM_HID)))
|
||||
{
|
||||
strcpy(&dir_entries->data[k * 256], fno.fname);
|
||||
if (++k >= DIR_MAX_ENTRIES)
|
||||
@@ -85,15 +82,12 @@ dirlist_t *dirlist(const char *directory, const char *pattern, u32 flags)
|
||||
// Terminate name list.
|
||||
dir_entries->name[k] = NULL;
|
||||
|
||||
// Choose list ordering.
|
||||
int (*strcmpex)(const char* str1, const char* str2) = ascii_order ? strcmp : strcasecmp;
|
||||
|
||||
// Reorder ini files Alphabetically.
|
||||
for (u32 i = 0; i < k - 1 ; i++)
|
||||
{
|
||||
for (u32 j = i + 1; j < k; j++)
|
||||
{
|
||||
if (strcmpex(dir_entries->name[i], dir_entries->name[j]) > 0)
|
||||
if (strcasecmp(dir_entries->name[i], dir_entries->name[j]) > 0)
|
||||
{
|
||||
char *tmp = dir_entries->name[i];
|
||||
dir_entries->name[i] = dir_entries->name[j];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2025 CTCaer
|
||||
* Copyright (c) 2018-2024 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@@ -18,14 +18,10 @@
|
||||
|
||||
#define DIR_MAX_ENTRIES 64
|
||||
|
||||
#define DIR_SHOW_HIDDEN BIT(0)
|
||||
#define DIR_SHOW_DIRS BIT(1)
|
||||
#define DIR_ASCII_ORDER BIT(2)
|
||||
|
||||
typedef struct _dirlist_t
|
||||
{
|
||||
char *name[DIR_MAX_ENTRIES];
|
||||
char data[DIR_MAX_ENTRIES * 256];
|
||||
} dirlist_t;
|
||||
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, u32 flags);
|
||||
dirlist_t *dirlist(const char *directory, const char *pattern, bool includeHiddenFiles, bool parse_dirs);
|
||||
|
||||
@@ -70,7 +70,7 @@ int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
|
||||
// Get all ini filenames.
|
||||
if (is_dir)
|
||||
{
|
||||
filelist = dirlist(filename, "*.ini", DIR_ASCII_ORDER);
|
||||
filelist = dirlist(filename, "*.ini", false, false);
|
||||
if (!filelist)
|
||||
{
|
||||
free(filename);
|
||||
|
||||
@@ -105,6 +105,9 @@ typedef unsigned long uptr;
|
||||
#define likely(x) (__builtin_expect((x) != 0, 1))
|
||||
#define unlikely(x) (__builtin_expect((x) != 0, 0))
|
||||
|
||||
#define XSTR(a) STR(a)
|
||||
#define STR(a) #a
|
||||
|
||||
/* Bootloader/Nyx */
|
||||
#define BOOT_CFG_AUTOBOOT_EN BIT(0)
|
||||
#define BOOT_CFG_FROM_LAUNCH BIT(1)
|
||||
@@ -126,7 +129,11 @@ typedef enum _nyx_ums_type
|
||||
NYX_UMS_EMMC_GPP,
|
||||
NYX_UMS_EMUMMC_BOOT0,
|
||||
NYX_UMS_EMUMMC_BOOT1,
|
||||
NYX_UMS_EMUMMC_GPP
|
||||
NYX_UMS_EMUMMC_GPP,
|
||||
NYX_UMS_BOOT_STRG_SD,
|
||||
NYX_UMS_BOOT_STRG_BOOT1,
|
||||
NYX_UMS_BOOT_STRG_BOOT1_1MB,
|
||||
NYX_UMS_BOOT_STRG_GPP,
|
||||
} nyx_ums_type;
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <storage/boot_storage.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mem/heap.h>
|
||||
@@ -273,6 +274,7 @@ void power_set_state(power_state_t state)
|
||||
u8 reg;
|
||||
|
||||
// Unmount and power down sd card.
|
||||
boot_storage_end();
|
||||
sd_end();
|
||||
|
||||
// De-initialize and power down various hardware.
|
||||
|
||||
Reference in New Issue
Block a user