mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-27 00:00:07 -06:00
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:

committed by
GitHub

parent
db963aa002
commit
5bfe51e670
481
src/SPI.cpp
481
src/SPI.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user