Add some structs for files that DSi_NAND reads (#1842)
* Add DSiFirmwareSystemSettings * Replace DSiFirmwareSystemSettings::TouchCalibration fields with std::arrays - So assignment can be done in one line * Make DSiFirmwareSystemSettings a union - So its bytes can be accessed * Add a comment * Use DSiFirmwareSystemSettings instead of raw byte offsets * Add definitions for DSiSerialData and DSiHardwareInfoN * Move DSiFirmwareSystemSettings's hash update logic into its own method
This commit is contained in:
parent
bb09ce7d70
commit
b2fcff97c1
10
src/DSi.cpp
10
src/DSi.cpp
|
@ -530,20 +530,20 @@ void SetupDirectBoot()
|
||||||
|
|
||||||
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
|
if (DSi_NAND::Init(&DSi::ARM7iBIOS[0x8308]))
|
||||||
{
|
{
|
||||||
u8 userdata[0x1B0];
|
DSi_NAND::DSiFirmwareSystemSettings userdata {};
|
||||||
DSi_NAND::ReadUserData(userdata);
|
DSi_NAND::ReadUserData(userdata);
|
||||||
for (u32 i = 0; i < 0x128; i+=4)
|
for (u32 i = 0; i < 0x128; i+=4)
|
||||||
ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
|
ARM9Write32(0x02000400+i, *(u32*)&userdata.Bytes[0x88+i]);
|
||||||
|
|
||||||
u8 hwinfoS[0xA4];
|
DSi_NAND::DSiSerialData hwinfoS {};
|
||||||
u8 hwinfoN[0x9C];
|
DSi_NAND::DSiHardwareInfoN hwinfoN;
|
||||||
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x14; i+=4)
|
for (u32 i = 0; i < 0x14; i+=4)
|
||||||
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x18; i+=4)
|
for (u32 i = 0; i < 0x18; i+=4)
|
||||||
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
|
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS.Bytes[0x88+i]);
|
||||||
|
|
||||||
DSi_NAND::DeInit();
|
DSi_NAND::DeInit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -486,7 +486,7 @@ bool ESDecrypt(u8* data, u32 len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ReadHardwareInfo(u8* dataS, u8* dataN)
|
void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN)
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
@ -495,20 +495,20 @@ void ReadHardwareInfo(u8* dataS, u8* dataN)
|
||||||
res = f_open(&file, "0:/sys/HWINFO_S.dat", FA_OPEN_EXISTING | FA_READ);
|
res = f_open(&file, "0:/sys/HWINFO_S.dat", FA_OPEN_EXISTING | FA_READ);
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
{
|
{
|
||||||
f_read(&file, dataS, 0xA4, &nread);
|
f_read(&file, &dataS, sizeof(DSiSerialData), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = f_open(&file, "0:/sys/HWINFO_N.dat", FA_OPEN_EXISTING | FA_READ);
|
res = f_open(&file, "0:/sys/HWINFO_N.dat", FA_OPEN_EXISTING | FA_READ);
|
||||||
if (res == FR_OK)
|
if (res == FR_OK)
|
||||||
{
|
{
|
||||||
f_read(&file, dataN, 0x9C, &nread);
|
f_read(&file, dataN.data(), sizeof(dataN), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ReadUserData(u8* data)
|
void ReadUserData(DSiFirmwareSystemSettings& data)
|
||||||
{
|
{
|
||||||
FF_FIL file;
|
FF_FIL file;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
@ -553,7 +553,7 @@ void ReadUserData(u8* data)
|
||||||
}
|
}
|
||||||
|
|
||||||
f_lseek(&file, 0);
|
f_lseek(&file, 0);
|
||||||
f_read(&file, data, 0x1B0, &nread);
|
f_read(&file, &data, sizeof(DSiFirmwareSystemSettings), &nread);
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,10 +574,10 @@ void PatchUserData()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 contents[0x1B0];
|
DSiFirmwareSystemSettings contents;
|
||||||
u32 nres;
|
u32 nres;
|
||||||
f_lseek(&file, 0);
|
f_lseek(&file, 0);
|
||||||
f_read(&file, contents, 0x1B0, &nres);
|
f_read(&file, &contents, sizeof(DSiFirmwareSystemSettings), &nres);
|
||||||
|
|
||||||
// override user settings, if needed
|
// override user settings, if needed
|
||||||
if (Platform::GetConfigBool(Platform::Firm_OverrideSettings))
|
if (Platform::GetConfigBool(Platform::Firm_OverrideSettings))
|
||||||
|
@ -586,46 +586,39 @@ void PatchUserData()
|
||||||
std::string orig_username = Platform::GetConfigString(Platform::Firm_Username);
|
std::string orig_username = Platform::GetConfigString(Platform::Firm_Username);
|
||||||
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
|
std::u16string username = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_username);
|
||||||
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
size_t usernameLength = std::min(username.length(), (size_t) 10);
|
||||||
memset(contents + 0xD0, 0, 11 * sizeof(char16_t));
|
memset(&contents.Nickname, 0, sizeof(contents.Nickname));
|
||||||
memcpy(contents + 0xD0, username.data(), usernameLength * sizeof(char16_t));
|
memcpy(&contents.Nickname, username.data(), usernameLength * sizeof(char16_t));
|
||||||
|
|
||||||
// setting language
|
// setting language
|
||||||
contents[0x8E] = Platform::GetConfigInt(Platform::Firm_Language);
|
contents.Language = static_cast<SPI_Firmware::Language>(Platform::GetConfigInt(Platform::Firm_Language));
|
||||||
|
|
||||||
// setting up color
|
// setting up color
|
||||||
contents[0xCC] = Platform::GetConfigInt(Platform::Firm_Color);
|
contents.FavoriteColor = Platform::GetConfigInt(Platform::Firm_Color);
|
||||||
|
|
||||||
// setting up birthday
|
// setting up birthday
|
||||||
contents[0xCE] = Platform::GetConfigInt(Platform::Firm_BirthdayMonth);
|
contents.BirthdayMonth = Platform::GetConfigInt(Platform::Firm_BirthdayMonth);
|
||||||
contents[0xCF] = Platform::GetConfigInt(Platform::Firm_BirthdayDay);
|
contents.BirthdayDay = Platform::GetConfigInt(Platform::Firm_BirthdayDay);
|
||||||
|
|
||||||
// setup message
|
// setup message
|
||||||
std::string orig_message = Platform::GetConfigString(Platform::Firm_Message);
|
std::string orig_message = Platform::GetConfigString(Platform::Firm_Message);
|
||||||
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
|
std::u16string message = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(orig_message);
|
||||||
size_t messageLength = std::min(message.length(), (size_t) 26);
|
size_t messageLength = std::min(message.length(), (size_t) 26);
|
||||||
memset(contents + 0xE6, 0, 27 * sizeof(char16_t));
|
memset(&contents.Message, 0, sizeof(contents.Message));
|
||||||
memcpy(contents + 0xE6, message.data(), messageLength * sizeof(char16_t));
|
memcpy(&contents.Message, message.data(), messageLength * sizeof(char16_t));
|
||||||
|
|
||||||
// TODO: make other items configurable?
|
// TODO: make other items configurable?
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix touchscreen coords
|
// fix touchscreen coords
|
||||||
*(u16*)&contents[0xB8] = 0;
|
contents.TouchCalibrationADC1 = {0, 0};
|
||||||
*(u16*)&contents[0xBA] = 0;
|
contents.TouchCalibrationPixel1 = {0, 0};
|
||||||
contents[0xBC] = 0;
|
contents.TouchCalibrationADC2 = {255 << 4, 191 << 4};
|
||||||
contents[0xBD] = 0;
|
contents.TouchCalibrationPixel2 = {255, 191};
|
||||||
*(u16*)&contents[0xBE] = 255<<4;
|
|
||||||
*(u16*)&contents[0xC0] = 191<<4;
|
|
||||||
contents[0xC2] = 255;
|
|
||||||
contents[0xC3] = 191;
|
|
||||||
|
|
||||||
SHA1_CTX sha;
|
contents.UpdateHash();
|
||||||
SHA1Init(&sha);
|
|
||||||
SHA1Update(&sha, &contents[0x88], 0x128);
|
|
||||||
SHA1Final(&contents[0], &sha);
|
|
||||||
|
|
||||||
f_lseek(&file, 0);
|
f_lseek(&file, 0);
|
||||||
f_write(&file, contents, 0x1B0, &nres);
|
f_write(&file, &contents, sizeof(DSiFirmwareSystemSettings), &nres);
|
||||||
|
|
||||||
f_close(&file);
|
f_close(&file);
|
||||||
}
|
}
|
||||||
|
@ -1318,4 +1311,12 @@ bool ExportTitleData(u32 category, u32 titleid, int type, const char* file)
|
||||||
return ExportFile(fname, file);
|
return ExportFile(fname, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DSiFirmwareSystemSettings::UpdateHash()
|
||||||
|
{
|
||||||
|
SHA1_CTX sha;
|
||||||
|
SHA1Init(&sha);
|
||||||
|
SHA1Update(&sha, &Bytes[0x88], 0x128);
|
||||||
|
SHA1Final(Hash.data(), &sha);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
112
src/DSi_NAND.h
112
src/DSi_NAND.h
|
@ -22,6 +22,8 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "NDS_Header.h"
|
#include "NDS_Header.h"
|
||||||
#include "DSi_TMD.h"
|
#include "DSi_TMD.h"
|
||||||
|
#include "SPI_Firmware.h"
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -35,6 +37,10 @@ enum
|
||||||
TitleData_BannerSav,
|
TitleData_BannerSav,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union DSiFirmwareSystemSettings;
|
||||||
|
union DSiSerialData;
|
||||||
|
using DSiHardwareInfoN = std::array<u8, 0x9C>;
|
||||||
|
|
||||||
bool Init(u8* es_keyY);
|
bool Init(u8* es_keyY);
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
|
@ -42,9 +48,9 @@ Platform::FileHandle* GetFile();
|
||||||
|
|
||||||
void GetIDs(u8* emmc_cid, u64& consoleid);
|
void GetIDs(u8* emmc_cid, u64& consoleid);
|
||||||
|
|
||||||
void ReadHardwareInfo(u8* dataS, u8* dataN);
|
void ReadHardwareInfo(DSiSerialData& dataS, DSiHardwareInfoN& dataN);
|
||||||
|
|
||||||
void ReadUserData(u8* data);
|
void ReadUserData(DSiFirmwareSystemSettings& data);
|
||||||
void PatchUserData();
|
void PatchUserData();
|
||||||
|
|
||||||
void ListTitles(u32 category, std::vector<u32>& titlelist);
|
void ListTitles(u32 category, std::vector<u32>& titlelist);
|
||||||
|
@ -58,6 +64,108 @@ u32 GetTitleDataMask(u32 category, u32 titleid);
|
||||||
bool ImportTitleData(u32 category, u32 titleid, int type, const char* file);
|
bool ImportTitleData(u32 category, u32 titleid, int type, const char* file);
|
||||||
bool ExportTitleData(u32 category, u32 titleid, int type, const char* file);
|
bool ExportTitleData(u32 category, u32 titleid, int type, const char* file);
|
||||||
|
|
||||||
|
typedef std::array<u8, 20> SHA1Hash;
|
||||||
|
typedef std::array<u8, 8> TitleID;
|
||||||
|
|
||||||
|
/// Firmware settings for the DSi, saved to the NAND as TWLCFG0.dat or TWLCFG1.dat.
|
||||||
|
/// The DSi mirrors this information to its own firmware for compatibility with NDS games.
|
||||||
|
/// @note The file is normally 16KiB, but only the first 432 bytes are used;
|
||||||
|
/// the rest is FF-padded.
|
||||||
|
/// This struct excludes the padding.
|
||||||
|
/// @see https://problemkaputt.de/gbatek.htm#dsisdmmcfirmwaresystemsettingsdatafiles
|
||||||
|
union DSiFirmwareSystemSettings
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SHA1Hash Hash;
|
||||||
|
u8 Zero00[108];
|
||||||
|
u8 Version;
|
||||||
|
u8 UpdateCounter;
|
||||||
|
u8 Zero01[2];
|
||||||
|
u32 BelowRAMAreaSize;
|
||||||
|
u32 ConfigFlags;
|
||||||
|
u8 Zero02;
|
||||||
|
u8 CountryCode;
|
||||||
|
SPI_Firmware::Language Language;
|
||||||
|
u8 RTCYear;
|
||||||
|
u32 RTCOffset;
|
||||||
|
u8 Zero3[4];
|
||||||
|
u8 EULAVersion;
|
||||||
|
u8 Zero04[9];
|
||||||
|
u8 AlarmHour;
|
||||||
|
u8 AlarmMinute;
|
||||||
|
u8 Zero05[2];
|
||||||
|
bool AlarmEnable;
|
||||||
|
u8 Zero06[2];
|
||||||
|
u8 SystemMenuUsedTitleSlots;
|
||||||
|
u8 SystemMenuFreeTitleSlots;
|
||||||
|
u8 Unknown0;
|
||||||
|
u8 Unknown1;
|
||||||
|
u8 Zero07[3];
|
||||||
|
TitleID SystemMenuMostRecentTitleID;
|
||||||
|
std::array<u16, 2> TouchCalibrationADC1;
|
||||||
|
std::array<u8, 2> TouchCalibrationPixel1;
|
||||||
|
std::array<u16, 2> TouchCalibrationADC2;
|
||||||
|
std::array<u8, 2> TouchCalibrationPixel2;
|
||||||
|
u8 Unknown2[4];
|
||||||
|
u8 Zero08[4];
|
||||||
|
u8 FavoriteColor;
|
||||||
|
u8 Zero09;
|
||||||
|
u8 BirthdayMonth;
|
||||||
|
u8 BirthdayDay;
|
||||||
|
char16_t Nickname[11];
|
||||||
|
char16_t Message[27];
|
||||||
|
u8 ParentalControlsFlags;
|
||||||
|
u8 Zero10[6];
|
||||||
|
u8 ParentalControlsRegion;
|
||||||
|
u8 ParentalControlsYearsOfAgeRating;
|
||||||
|
u8 ParentalControlsSecretQuestion;
|
||||||
|
u8 Unknown3;
|
||||||
|
u8 Zero11[2];
|
||||||
|
char ParentalControlsPIN[5];
|
||||||
|
char16_t ParentalControlsSecretAnswer[65];
|
||||||
|
};
|
||||||
|
u8 Bytes[432];
|
||||||
|
|
||||||
|
void UpdateHash();
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DSiFirmwareSystemSettings) == 432, "DSiFirmwareSystemSettings must be exactly 432 bytes");
|
||||||
|
|
||||||
|
enum class ConsoleRegion : u8
|
||||||
|
{
|
||||||
|
Japan,
|
||||||
|
USA,
|
||||||
|
Europe,
|
||||||
|
Australia,
|
||||||
|
China,
|
||||||
|
Korea,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Data file saved to 0:/sys/HWINFO_S.dat.
|
||||||
|
/// @note The file is normally 16KiB, but only the first 164 bytes are used;
|
||||||
|
/// the rest is FF-padded.
|
||||||
|
/// This struct excludes the padding.
|
||||||
|
/// @see https://problemkaputt.de/gbatek.htm#dsisdmmcfirmwaremiscfiles
|
||||||
|
union DSiSerialData
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 RsaSha1HMAC[0x80];
|
||||||
|
u32 Version;
|
||||||
|
u32 EntrySize;
|
||||||
|
u32 SupportedLanguages;
|
||||||
|
u8 Unknown0[4];
|
||||||
|
ConsoleRegion Region;
|
||||||
|
char Serial[12];
|
||||||
|
u8 Unknown1[3];
|
||||||
|
u8 TitleIDLSBs[4];
|
||||||
|
};
|
||||||
|
u8 Bytes[164];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(DSiSerialData) == 164, "DSiSerialData must be exactly 164 bytes");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DSI_NAND_H
|
#endif // DSI_NAND_H
|
||||||
|
|
Loading…
Reference in New Issue