Refactor the core's handling of firmware and BIOS images to rely less on the file system (#1826)

* Introduce firmware-related structs

* Fix some indents

* Move the generated firmware identifier to a constant

* Document the WifiAccessPoint constructors

* Add some constants

* Remove a stray comment

* Implement Firmware::UserData

* Add Firmware::Mask

* Document Firmware::Buffer

* Add a Firmware constructor that uses a FileHandle

* Set the default username in UserData

* Update the UserData checksum

* Forgot to include Platform.h

* Remove some redundant assignments in the default Firmware constructor

* const-ify CRC16

* Replace the plain Firmware buffer with a Firmware object

- Remove some functions that were reimplemented in the Firmware constructors

* Fix some crashes due to undefined behavior

* Fix the user data initialization

- Initialize both user data objects to default
- Set both user data objects to the same touch screen calibration

* Follow the DS logic in determining which user data section is current

* Remove an unneeded include

* Remove another unneeded include

* Initialize FirmwareMask in Firmware::Firmware

* Use the DEFAULT_SSID constant

* Add SPI_Firmware::InstallFirmware and SPI_Firmware::RemoveFirmware

* Move a logging call to after the file is written

* Add a SaveManager for the firmware

* Touch up the SPI_Firmware::Firmware declaration

* Move all firmware loading and customization to the frontend

* Call Platform::WriteFirmware when it's time to write the firmware back to disk

* Fix some missing stuff

* Remove the Get* functions from SPI_Firmware in favor of GetFirmware()

* Implement SPI_Firmware::DeInit in terms of RemoveFirmware

* Add Firmware::UpdateChecksums

* Fix an incorrect length

* Update all checksums in the firmware after setting touch screen calibration data

* Use the Firmware object's Position methods

* Remove register fields from the Firmware object

* Install the firmware before seeing if direct boot is necessary

* Install the firmware before calling NDS::Reset in LoadROM

* Slight cleanup in ROMManager

* Fix the default access point name

* Shorten the various getters in Firmware

* Add qualifiers for certain uses of firmware types

- GCC can get picky if -fpermissive isn't defined

* Add an InstallFirmware overload that takes a unique_ptr

* Log when firmware is added or removed

* Don't clear the firmware in SPI_Firmware::Init

- The original code didn't, it just set the pointer to nullptr

* Fix a typo

* Write back the full firmware if it's not generated

* Move the FreeBIOS to an external file

* Load wfcsettings.bin into the correct part of the generated firmware blob

* Load BIOS files in the frontend, not in the core

* Fix logging the firmware ID

* Add some utility functions

* Mark Firmware's constructors as explicit

* Remove obsolete ConfigEntry values

* Include <locale> explicitly in ROMManager

* Fix up some includes

* Add Firmware::IsBootable()

* Add a newline to a log entry

- Whoops

* Log the number of bytes written out in SaveManager

* Mark FirmwareHeader's constructor as explicit

* Clean up GenerateDefaultFirmware and LoadFirmwareFromFile

- Now they return a pair instead of two by-ref values

* Refactor SaveManager a little bit

- Manage its buffers as unique_ptrs to mitigate leaks
- Reallocate the internal buffer if SetPath is asked to reload the file (and the new length is different)

* Remove some stray parens

* Fix some firmware-related bugs I introduced

- Firmware settings are now properly saved to disk (beforehand I misunderstood when the firmware blob was written)
- Firmware is no longer overwritten by contents of wfcsettings.bin

* Slight cleanup
This commit is contained in:
Jesse Talavera-Greenberg
2023-09-18 15:09:11 -04:00
committed by GitHub
parent db963aa002
commit 5bfe51e670
20 changed files with 3259 additions and 2250 deletions

View File

@ -19,10 +19,8 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
#include <codecvt>
#include <locale>
#include <memory>
#include <utility>
#include "NDS.h"
#include "DSi.h"
#include "SPI.h"
@ -34,12 +32,7 @@ using namespace Platform;
namespace SPI_Firmware
{
std::string FirmwarePath;
u8* Firmware;
u32 FirmwareLength;
u32 FirmwareMask;
u32 UserSettings;
std::unique_ptr<Firmware> Firmware;
u32 Hold;
u8 CurCmd;
@ -49,10 +42,9 @@ u8 Data;
u8 StatusReg;
u32 Addr;
u16 CRC16(u8* data, u32 len, u32 start)
u16 CRC16(const u8* data, u32 len, u32 start)
{
u16 blarg[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001};
constexpr u16 blarg[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001};
for (u32 i = 0; i < len; i++)
{
@ -75,23 +67,20 @@ u16 CRC16(u8* data, u32 len, u32 start)
bool VerifyCRC16(u32 start, u32 offset, u32 len, u32 crcoffset)
{
u16 crc_stored = *(u16*)&Firmware[crcoffset];
u16 crc_calced = CRC16(&Firmware[offset], len, start);
u16 crc_stored = *(u16*)&Firmware->Buffer()[crcoffset];
u16 crc_calced = CRC16(&Firmware->Buffer()[offset], len, start);
return (crc_stored == crc_calced);
}
bool Init()
{
FirmwarePath = "";
Firmware = nullptr;
return true;
}
void DeInit()
{
if (Firmware) delete[] Firmware;
Firmware = nullptr;
RemoveFirmware();
}
u32 FixFirmwareLength(u32 originalLength)
@ -117,335 +106,43 @@ u32 FixFirmwareLength(u32 originalLength)
return originalLength;
}
void LoadDefaultFirmware()
{
Log(LogLevel::Debug, "Using default firmware image...\n");
FirmwareLength = 0x20000;
Firmware = new u8[FirmwareLength];
memset(Firmware, 0xFF, FirmwareLength);
FirmwareMask = FirmwareLength - 1;
memset(Firmware, 0, 0x1D);
if (NDS::ConsoleType == 1)
{
Firmware[0x1D] = 0x57; // DSi
Firmware[0x2F] = 0x0F;
Firmware[0x1FD] = 0x01;
Firmware[0x1FE] = 0x20;
Firmware[0x2FF] = 0x80; // boot0: use NAND as stage2 medium
// these need to be zero (part of the stage2 firmware signature!)
memset(&Firmware[0x22], 0, 8);
}
else
{
Firmware[0x1D] = 0x20; // DS Lite (TODO: make configurable?)
Firmware[0x2F] = 0x06;
}
// wifi calibration
const u8 defaultmac[6] = {0x00, 0x09, 0xBF, 0x11, 0x22, 0x33};
const u8 bbinit[0x69] =
{
0x03, 0x17, 0x40, 0x00, 0x1B, 0x6C, 0x48, 0x80, 0x38, 0x00, 0x35, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0xBB, 0x01, 0x24, 0x7F,
0x5A, 0x01, 0x3F, 0x01, 0x3F, 0x36, 0x1D, 0x00, 0x78, 0x35, 0x55, 0x12, 0x34, 0x1C, 0x00, 0x01,
0x0E, 0x38, 0x03, 0x70, 0xC5, 0x2A, 0x0A, 0x08, 0x04, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE,
0xFE, 0xFE, 0xFE, 0xFC, 0xFC, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xF8, 0xF8, 0xF6, 0x00, 0x12, 0x14,
0x12, 0x41, 0x23, 0x03, 0x04, 0x70, 0x35, 0x0E, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x12, 0x28, 0x1C
};
const u8 rfinit[0x29] =
{
0x31, 0x4C, 0x4F, 0x21, 0x00, 0x10, 0xB0, 0x08, 0xFA, 0x15, 0x26, 0xE6, 0xC1, 0x01, 0x0E, 0x50,
0x05, 0x00, 0x6D, 0x12, 0x00, 0x00, 0x01, 0xFF, 0x0E, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x06,
0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00
};
const u8 chandata[0x3C] =
{
0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x16,
0x26, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1E, 0x1F, 0x18,
0x01, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D,
0x02, 0x6C, 0x71, 0x76, 0x5B, 0x40, 0x45, 0x4A, 0x2F, 0x34, 0x39, 0x3E, 0x03, 0x08, 0x14
};
*(u16*)&Firmware[0x2C] = 0x138;
Firmware[0x2E] = 0;
*(u32*)&Firmware[0x30] = 0xFFFFFFFF;
*(u16*)&Firmware[0x34] = 0x00FF;
memcpy(&Firmware[0x36], defaultmac, 6);
*(u16*)&Firmware[0x3C] = 0x3FFE;
*(u16*)&Firmware[0x3E] = 0xFFFF;
Firmware[0x40] = 0x03;
Firmware[0x41] = 0x94;
Firmware[0x42] = 0x29;
Firmware[0x43] = 0x02;
*(u16*)&Firmware[0x44] = 0x0002;
*(u16*)&Firmware[0x46] = 0x0017;
*(u16*)&Firmware[0x48] = 0x0026;
*(u16*)&Firmware[0x4A] = 0x1818;
*(u16*)&Firmware[0x4C] = 0x0048;
*(u16*)&Firmware[0x4E] = 0x4840;
*(u16*)&Firmware[0x50] = 0x0058;
*(u16*)&Firmware[0x52] = 0x0042;
*(u16*)&Firmware[0x54] = 0x0146;
*(u16*)&Firmware[0x56] = 0x8064;
*(u16*)&Firmware[0x58] = 0xE6E6;
*(u16*)&Firmware[0x5A] = 0x2443;
*(u16*)&Firmware[0x5C] = 0x000E;
*(u16*)&Firmware[0x5E] = 0x0001;
*(u16*)&Firmware[0x60] = 0x0001;
*(u16*)&Firmware[0x62] = 0x0402;
memcpy(&Firmware[0x64], bbinit, 0x69);
Firmware[0xCD] = 0;
memcpy(&Firmware[0xCE], rfinit, 0x29);
Firmware[0xF7] = 0x02;
memcpy(&Firmware[0xF8], chandata, 0x3C);
*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
// user data
u32 userdata = 0x7FE00 & FirmwareMask;
*(u16*)&Firmware[0x20] = userdata >> 3;
memset(Firmware + userdata, 0, 0x74);
Firmware[userdata+0x00] = 5; // version
Firmware[userdata+0x03] = 1;
Firmware[userdata+0x04] = 1;
*(u16*)&Firmware[userdata+0x64] = 0x0031;
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
// wifi access points
// TODO: WFC ID??
std::string wfcsettings = Platform::GetConfigString(ConfigEntry::WifiSettingsPath);
FileHandle* f = Platform::OpenLocalFile(wfcsettings + Platform::InstanceFileSuffix(), FileMode::Read);
if (!f) f = Platform::OpenLocalFile(wfcsettings, FileMode::Read);
if (f)
{
u32 apdata = userdata - 0xA00;
FileRead(&Firmware[apdata], 0x900, 1, f);
CloseFile(f);
}
else
{
u32 apdata = userdata - 0x400;
memset(&Firmware[apdata], 0, 0x300);
strcpy((char*)&Firmware[apdata+0x40], "melonAP");
if (NDS::ConsoleType == 1) *(u16*)&Firmware[apdata+0xEA] = 1400;
Firmware[apdata+0xEF] = 0x01;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
apdata += 0x100;
Firmware[apdata+0xE7] = 0xFF;
Firmware[apdata+0xEF] = 0x01;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
apdata += 0x100;
Firmware[apdata+0xE7] = 0xFF;
Firmware[apdata+0xEF] = 0x01;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
if (NDS::ConsoleType == 1)
{
apdata = userdata - 0xA00;
Firmware[apdata+0xE7] = 0xFF;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
apdata += 0x200;
Firmware[apdata+0xE7] = 0xFF;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
apdata += 0x200;
Firmware[apdata+0xE7] = 0xFF;
*(u16*)&Firmware[apdata+0xFE] = CRC16(&Firmware[apdata], 0xFE, 0x0000);
}
}
}
void LoadFirmwareFromFile(FileHandle* f, bool makecopy)
{
FirmwareLength = FixFirmwareLength(FileLength(f));
Firmware = new u8[FirmwareLength];
FileRewind(f);
FileRead(Firmware, 1, FirmwareLength, f);
// take a backup
std::string fwBackupPath;
if (!makecopy) fwBackupPath = FirmwarePath + ".bak";
else fwBackupPath = FirmwarePath;
FileHandle* bf = Platform::OpenLocalFile(fwBackupPath, FileMode::Read);
if (!bf)
{
bf = Platform::OpenLocalFile(fwBackupPath, FileMode::Write);
if (bf)
{
FileWrite(Firmware, 1, FirmwareLength, bf);
CloseFile(bf);
}
else
{
Log(LogLevel::Error, "Could not write firmware backup!\n");
}
}
else
{
CloseFile(bf);
}
}
void LoadUserSettingsFromConfig()
{
// setting up 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);
size_t usernameLength = std::min(username.length(), (size_t) 10);
memcpy(Firmware + UserSettings + 0x06, username.data(), usernameLength * sizeof(char16_t));
Firmware[UserSettings+0x1A] = usernameLength;
// setting language
Firmware[UserSettings+0x64] = Platform::GetConfigInt(Platform::Firm_Language);
// setting up color
Firmware[UserSettings+0x02] = Platform::GetConfigInt(Platform::Firm_Color);
// setting up birthday
Firmware[UserSettings+0x03] = Platform::GetConfigInt(Platform::Firm_BirthdayMonth);
Firmware[UserSettings+0x04] = Platform::GetConfigInt(Platform::Firm_BirthdayDay);
// setup 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);
size_t messageLength = std::min(message.length(), (size_t) 26);
memcpy(Firmware + UserSettings + 0x1C, message.data(), messageLength * sizeof(char16_t));
Firmware[UserSettings+0x50] = messageLength;
}
void Reset()
{
if (Firmware) delete[] Firmware;
Firmware = nullptr;
FirmwarePath = "";
bool firmoverride = false;
if (Platform::GetConfigBool(Platform::ExternalBIOSEnable))
if (!Firmware)
{
if (NDS::ConsoleType == 1)
FirmwarePath = Platform::GetConfigString(Platform::DSi_FirmwarePath);
else
FirmwarePath = Platform::GetConfigString(Platform::FirmwarePath);
Log(LogLevel::Debug, "SPI firmware: loading from file %s\n", FirmwarePath.c_str());
bool makecopy = false;
std::string origpath = FirmwarePath;
FirmwarePath += Platform::InstanceFileSuffix();
FileHandle* f = Platform::OpenLocalFile(FirmwarePath, FileMode::Read);
if (!f)
{
f = Platform::OpenLocalFile(origpath, FileMode::Read);
makecopy = true;
}
if (!f)
{
Log(LogLevel::Warn,"Firmware not found! Generating default firmware.\n");
FirmwarePath = "";
}
else
{
LoadFirmwareFromFile(f, makecopy);
CloseFile(f);
}
Log(LogLevel::Warn, "SPI firmware: no firmware loaded! Using default\n");
Firmware = std::make_unique<class Firmware>(NDS::ConsoleType);
}
if (FirmwarePath.empty())
{
LoadDefaultFirmware();
firmoverride = true;
}
else
{
firmoverride = Platform::GetConfigBool(Platform::Firm_OverrideSettings);
}
FirmwareMask = FirmwareLength - 1;
u32 userdata = 0x7FE00 & FirmwareMask;
if (*(u16*)&Firmware[userdata+0x170] == ((*(u16*)&Firmware[userdata+0x70] + 1) & 0x7F))
{
if (VerifyCRC16(0xFFFF, userdata+0x100, 0x70, userdata+0x172))
userdata += 0x100;
}
UserSettings = userdata;
if (firmoverride)
LoadUserSettingsFromConfig();
// fix touchscreen coords
*(u16*)&Firmware[userdata+0x58] = 0;
*(u16*)&Firmware[userdata+0x5A] = 0;
Firmware[userdata+0x5C] = 0;
Firmware[userdata+0x5D] = 0;
*(u16*)&Firmware[userdata+0x5E] = 255<<4;
*(u16*)&Firmware[userdata+0x60] = 191<<4;
Firmware[userdata+0x62] = 255;
Firmware[userdata+0x63] = 191;
for (UserData& u : Firmware->UserData())
{
u.TouchCalibrationADC1[0] = 0;
u.TouchCalibrationADC1[1] = 0;
u.TouchCalibrationPixel1[0] = 0;
u.TouchCalibrationPixel1[1] = 0;
u.TouchCalibrationADC2[0] = 255<<4;
u.TouchCalibrationADC2[1] = 191<<4;
u.TouchCalibrationPixel2[0] = 255;
u.TouchCalibrationPixel2[1] = 191;
}
Firmware->UpdateChecksums();
// disable autoboot
//Firmware[userdata+0x64] &= 0xBF;
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
//if (firmoverride)
{
u8 mac[6];
bool rep = false;
memcpy(mac, &Firmware[0x36], 6);
if (firmoverride)
rep = Platform::GetConfigArray(Platform::Firm_MAC, mac);
int inst = Platform::InstanceID();
if (inst > 0)
{
rep = true;
mac[3] += inst;
mac[4] += inst*0x44;
mac[5] += inst*0x10;
}
if (rep)
{
mac[0] &= 0xFC; // ensure the MAC isn't a broadcast MAC
memcpy(&Firmware[0x36], mac, 6);
*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
}
}
Log(LogLevel::Info, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
Firmware[0x36], Firmware[0x37], Firmware[0x38],
Firmware[0x39], Firmware[0x3A], Firmware[0x3B]);
MacAddress mac = Firmware->Header().MacAddress;
Log(LogLevel::Info, "MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
// verify shit
Log(LogLevel::Debug, "FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware[0x2C], 0x2A)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP1 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FA00&FirmwareMask, 0xFE, 0x7FAFE&FirmwareMask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP2 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FB00&FirmwareMask, 0xFE, 0x7FBFE&FirmwareMask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP3 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FC00&FirmwareMask, 0xFE, 0x7FCFE&FirmwareMask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: USER0 CRC16 = %s\n", VerifyCRC16(0xFFFF, 0x7FE00&FirmwareMask, 0x70, 0x7FE72&FirmwareMask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: USER1 CRC16 = %s\n", VerifyCRC16(0xFFFF, 0x7FF00&FirmwareMask, 0x70, 0x7FF72&FirmwareMask)?"GOOD":"BAD");
u32 mask = Firmware->Mask();
Log(LogLevel::Debug, "FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware->Buffer()[0x2C], 0x2A)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP1 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FA00&mask, 0xFE, 0x7FAFE&mask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP2 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FB00&mask, 0xFE, 0x7FBFE&mask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: AP3 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FC00&mask, 0xFE, 0x7FCFE&mask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: USER0 CRC16 = %s\n", VerifyCRC16(0xFFFF, 0x7FE00&mask, 0x70, 0x7FE72&mask)?"GOOD":"BAD");
Log(LogLevel::Debug, "FW: USER1 CRC16 = %s\n", VerifyCRC16(0xFFFF, 0x7FF00&mask, 0x70, 0x7FF72&mask)?"GOOD":"BAD");
Hold = 0;
CurCmd = 0;
@ -471,36 +168,85 @@ void DoSavestate(Savestate* file)
void SetupDirectBoot(bool dsi)
{
const FirmwareHeader& header = Firmware->Header();
const UserData& userdata = Firmware->EffectiveUserData();
if (dsi)
{
for (u32 i = 0; i < 6; i += 2)
DSi::ARM9Write16(0x02FFFCF4, *(u16*)&Firmware[0x36+i]); // MAC address
DSi::ARM9Write16(0x02FFFCF4, *(u16*)&header.MacAddress[i]); // MAC address
// checkme
DSi::ARM9Write16(0x02FFFCFA, *(u16*)&Firmware[0x3C]); // enabled channels
DSi::ARM9Write16(0x02FFFCFA, header.EnabledChannels); // enabled channels
for (u32 i = 0; i < 0x70; i += 4)
DSi::ARM9Write32(0x02FFFC80+i, *(u32*)&Firmware[UserSettings+i]);
DSi::ARM9Write32(0x02FFFC80+i, *(u32*)&userdata.Bytes[i]);
}
else
{
NDS::ARM9Write32(0x027FF864, 0);
NDS::ARM9Write32(0x027FF868, *(u16*)&Firmware[0x20] << 3); // user settings offset
NDS::ARM9Write32(0x027FF868, header.UserSettingsOffset << 3); // user settings offset
NDS::ARM9Write16(0x027FF874, *(u16*)&Firmware[0x26]); // CRC16 for data/gfx
NDS::ARM9Write16(0x027FF876, *(u16*)&Firmware[0x04]); // CRC16 for GUI/wifi code
NDS::ARM9Write16(0x027FF874, header.DataGfxChecksum); // CRC16 for data/gfx
NDS::ARM9Write16(0x027FF876, header.GUIWifiCodeChecksum); // CRC16 for GUI/wifi code
for (u32 i = 0; i < 0x70; i += 4)
NDS::ARM9Write32(0x027FFC80+i, *(u32*)&Firmware[UserSettings+i]);
NDS::ARM9Write32(0x027FFC80+i, *(u32*)&userdata.Bytes[i]);
}
}
u32 GetFirmwareLength() { return FirmwareLength; }
u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; }
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
u8 GetRFVersion() { return Firmware[0x40]; }
u8* GetWifiMAC() { return &Firmware[0x36]; }
const class Firmware* GetFirmware()
{
return Firmware.get();
}
bool IsLoadedFirmwareBuiltIn()
{
return Firmware->Header().Identifier == GENERATED_FIRMWARE_IDENTIFIER;
}
bool InstallFirmware(class Firmware&& firmware)
{
if (!firmware.Buffer())
{
Log(LogLevel::Error, "SPI firmware: firmware buffer is null!\n");
return false;
}
Firmware = std::make_unique<class Firmware>(std::move(firmware));
FirmwareIdentifier id = Firmware->Header().Identifier;
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
return true;
}
bool InstallFirmware(std::unique_ptr<class Firmware>&& firmware)
{
if (!firmware)
{
Log(LogLevel::Error, "SPI firmware: firmware is null!\n");
return false;
}
if (!firmware->Buffer())
{
Log(LogLevel::Error, "SPI firmware: firmware buffer is null!\n");
return false;
}
Firmware = std::move(firmware);
FirmwareIdentifier id = Firmware->Header().Identifier;
Log(LogLevel::Debug, "Installed firmware (Identifier: %c%c%c%c)\n", id[0], id[1], id[2], id[3]);
return true;
}
void RemoveFirmware()
{
Firmware.reset();
Log(LogLevel::Debug, "Removed installed firmware (if any)\n");
}
u8 Read()
{
@ -539,7 +285,7 @@ void Write(u8 val, u32 hold)
}
else
{
Data = Firmware[Addr & FirmwareMask];
Data = Firmware->Buffer()[Addr & Firmware->Mask()];
Addr++;
}
@ -565,14 +311,14 @@ void Write(u8 val, u32 hold)
{
// TODO: what happens if you write too many bytes? (max 256, they say)
if (DataPos < 4)
{
{ // If we're in the middle of writing the address...
Addr <<= 8;
Addr |= val;
Data = 0;
}
else
{
Firmware[Addr & FirmwareMask] = val;
Firmware->Buffer()[Addr & Firmware->Mask()] = val;
Data = val;
Addr++;
}
@ -601,31 +347,14 @@ void Write(u8 val, u32 hold)
}
if (!hold && (CurCmd == 0x02 || CurCmd == 0x0A))
{
if (!FirmwarePath.empty())
{
FileHandle* f = Platform::OpenLocalFile(FirmwarePath, FileMode::ReadWriteExisting);
if (f)
{
u32 cutoff = ((NDS::ConsoleType==1) ? 0x7F400 : 0x7FA00) & FirmwareMask;
FileSeek(f, cutoff, FileSeekOrigin::Start);
FileWrite(&Firmware[cutoff], FirmwareLength-cutoff, 1, f);
CloseFile(f);
}
}
else
{
std::string wfcfile = Platform::GetConfigString(ConfigEntry::WifiSettingsPath);
if (Platform::InstanceID() > 0) wfcfile += Platform::InstanceFileSuffix();
{ // If the SPI firmware chip just finished a write...
// We only notify the frontend of changes to the Wi-fi/userdata settings region
// (although it might still decide to flush the whole thing)
u32 wifioffset = Firmware->WifiAccessPointOffset();
FileHandle* f = Platform::OpenLocalFile(wfcfile, FileMode::Write);
if (f)
{
u32 cutoff = 0x7F400 & FirmwareMask;
FileWrite(&Firmware[cutoff], 0x900, 1, f);
CloseFile(f);
}
}
// Request that the start of the Wi-fi/userdata settings region
// through the end of the firmware blob be flushed to disk
Platform::WriteFirmware(*Firmware, wifioffset, Firmware->Length() - wifioffset);
}
}