From b6933013beb2c1a9e0e1ec2616ef0e751f6a3065 Mon Sep 17 00:00:00 2001 From: CTCaer Date: Thu, 30 Apr 2020 15:04:20 +0300 Subject: [PATCH] storage: Add primitive BIS support --- nyx/nyx_gui/libs/fatfs/diskio.c | 8 ++ nyx/nyx_gui/libs/fatfs/diskio.h | 2 + nyx/nyx_gui/libs/fatfs/ffconf.h | 4 +- nyx/nyx_gui/storage/nx_emmc_bis.c | 185 ++++++++++++++++++++++++++++++ nyx/nyx_gui/storage/nx_emmc_bis.h | 27 +++++ 5 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 nyx/nyx_gui/storage/nx_emmc_bis.c create mode 100644 nyx/nyx_gui/storage/nx_emmc_bis.h diff --git a/nyx/nyx_gui/libs/fatfs/diskio.c b/nyx/nyx_gui/libs/fatfs/diskio.c index 5cdfba9..4482fad 100644 --- a/nyx/nyx_gui/libs/fatfs/diskio.c +++ b/nyx/nyx_gui/libs/fatfs/diskio.c @@ -11,6 +11,7 @@ #include "diskio.h" /* FatFs lower layer API */ #include "../../../../common/memory_map.h" +#include "../../storage/nx_emmc_bis.h" #include "../../storage/nx_sd.h" #include "../../storage/ramdisk.h" #include "../../storage/sdmmc.h" @@ -51,6 +52,10 @@ DRESULT disk_read ( return sdmmc_storage_read(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; case DRIVE_RAM: return ram_disk_read(sector, count, (void *)buff); + case DRIVE_EMMC: + return sdmmc_storage_read(&emmc_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; + case DRIVE_BIS: + return nx_emmc_bis_read(sector, count, (void *)buff); } return RES_ERROR; @@ -72,6 +77,9 @@ DRESULT disk_write ( return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR; case DRIVE_RAM: return ram_disk_write(sector, count, (void *)buff); + case DRIVE_EMMC: + case DRIVE_BIS: + return RES_WRPRT; } return RES_ERROR; diff --git a/nyx/nyx_gui/libs/fatfs/diskio.h b/nyx/nyx_gui/libs/fatfs/diskio.h index 9d40b66..31b855d 100644 --- a/nyx/nyx_gui/libs/fatfs/diskio.h +++ b/nyx/nyx_gui/libs/fatfs/diskio.h @@ -26,6 +26,8 @@ typedef enum { typedef enum { DRIVE_SD = 0, DRIVE_RAM = 1, + DRIVE_EMMC = 2, + DRIVE_BIS = 3 } DDRIVE; diff --git a/nyx/nyx_gui/libs/fatfs/ffconf.h b/nyx/nyx_gui/libs/fatfs/ffconf.h index e6afb51..dc83987 100644 --- a/nyx/nyx_gui/libs/fatfs/ffconf.h +++ b/nyx/nyx_gui/libs/fatfs/ffconf.h @@ -168,13 +168,13 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 2 +#define FF_VOLUMES 4 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 1 // Order is important. Any change to order, must also be reflected to diskio drive enum. -#define FF_VOLUME_STRS "sd","ram" +#define FF_VOLUME_STRS "sd","ram","emmc","bis" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each diff --git a/nyx/nyx_gui/storage/nx_emmc_bis.c b/nyx/nyx_gui/storage/nx_emmc_bis.c new file mode 100644 index 0000000..b3a4a30 --- /dev/null +++ b/nyx/nyx_gui/storage/nx_emmc_bis.c @@ -0,0 +1,185 @@ +/* + * eMMC BIS driver for Nintendo Switch + * + * Copyright (c) 2019 shchmue + * Copyright (c) 2019 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, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "../../../common/memory_map.h" + +#include "../sec/se.h" +#include "../storage/nx_emmc.h" +#include "../storage/sdmmc.h" +#include "../utils/types.h" + +#define MAX_SEC_CACHE_ENTRIES 64 + +typedef struct _sector_cache_t +{ + u32 sector; + u32 visit_cnt; + u8 tweak[0x10]; + u8 data[0x200]; + u8 align[8]; +} sector_cache_t; + +static u32 sector_idx = 0; +static sector_cache_t *sector_cache = NULL; +static emmc_part_t *system_part = NULL; + +static void _gf256_mul_x_le(u8 *block) +{ + u8 *pdata = (u8 *)block; + u32 carry = 0; + + for (u32 i = 0; i < 0x10; i++) + { + u8 b = pdata[i]; + pdata[i] = (b << 1) | carry; + carry = b >> 7; + } + + if (carry) + pdata[0x0] ^= 0x87; +} + +static int _nx_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 sec_size) +{ + u8 *pdst = (u8 *)dst; + u8 *psrc = (u8 *)src; + + if (regen_tweak) + { + for (int i = 0xF; i >= 0; i--) + { + tweak[i] = sec & 0xFF; + sec >>= 8; + } + if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak)) + return 0; + } + + for (u32 i = 0; i < (tweak_exp << 5); i++) + _gf256_mul_x_le(tweak); + + u8 tmp_tweak[0x10]; + memcpy(tmp_tweak, tweak, 0x10); + + // We are assuming a 0x10-aligned sector size in this implementation. + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = psrc[j] ^ tweak[j]; + + _gf256_mul_x_le(tweak); + psrc += 0x10; + pdst += 0x10; + } + + se_aes_crypt_ecb(ks2, 0, dst, sec_size, src, sec_size); + + memcpy(tweak, tmp_tweak, 0x10); + + pdst = (u8 *)dst; + for (u32 i = 0; i < (sec_size >> 4); i++) + { + for (u32 j = 0; j < 0x10; j++) + pdst[j] = pdst[j] ^ tweak[j]; + + _gf256_mul_x_le(tweak); + pdst += 0x10; + } + + return 1; +} + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff) +{ + if (!system_part) + return 3; // Not ready. + + static u32 prev_cluster = -1; + static u32 prev_sector = 0; + __attribute__ ((aligned (16))) static u8 tweak[0x10]; + + u32 tweak_exp = 0; + bool regen_tweak = true, cache_sector = false; + + if (!sector_cache) + sector_cache = (sector_cache_t *)NX_BIS_CACHE_ADDR; + + u32 cache_idx = 0; + if (count == 1) + { + for ( ; cache_idx < sector_idx; cache_idx++) + { + if (sector_cache[cache_idx].sector == sector) + { + sector_cache[cache_idx].visit_cnt++; + memcpy(buff, sector_cache[cache_idx].data, 0x200); + memcpy(tweak, sector_cache[cache_idx].tweak, 0x10); + prev_sector = sector; + prev_cluster = sector >> 5; + + return 0; + } + } + // add to cache + if (cache_idx == sector_idx && cache_idx < MAX_SEC_CACHE_ENTRIES) + { + sector_cache[cache_idx].sector = sector; + sector_cache[cache_idx].visit_cnt++; + cache_sector = true; + sector_idx++; + } + } + + if (nx_emmc_part_read(&emmc_storage, system_part, sector, count, buff)) + { + if (prev_cluster != sector >> 5) // Sector in different cluster than last read. + { + prev_cluster = sector >> 5; + tweak_exp = sector % 0x20; + } + else if (sector > prev_sector) // Sector in same cluster and past last sector. + { + tweak_exp = sector - prev_sector - 1; + regen_tweak = false; + } + else // Sector in same cluster and before or same as last sector. + tweak_exp = sector % 0x20; + + // FatFS will never pull more than a cluster. + _nx_aes_xts_crypt_sec(9, 8, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, buff, count << 9); + if (cache_sector) + { + memcpy(sector_cache[cache_idx].data, buff, 0x200); + memcpy(sector_cache[cache_idx].tweak, tweak, 0x10); + } + prev_sector = sector + count - 1; + + return 0; + } + + // Error occurred. + return 1; +} + +void nx_emmc_bis_init(emmc_part_t *part) +{ + system_part = part; +} diff --git a/nyx/nyx_gui/storage/nx_emmc_bis.h b/nyx/nyx_gui/storage/nx_emmc_bis.h new file mode 100644 index 0000000..384076a --- /dev/null +++ b/nyx/nyx_gui/storage/nx_emmc_bis.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 shchmue + * Copyright (c) 2019 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, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NX_EMMC_BIS_H +#define NX_EMMC_BIS_H + +#include "../storage/nx_emmc.h" +#include "../storage/sdmmc.h" + +int nx_emmc_bis_read(u32 sector, u32 count, void *buff); +void nx_emmc_bis_init(sdmmc_storage_t *storage, emmc_part_t *part); + +#endif \ No newline at end of file