NANDImporter: Add support for dumps that don't include keys

This adds support for NAND images that only include the NAND
(i.e. without the OTP/SEEPROM dump appended at the end of the file).
This commit is contained in:
Léo Lam 2017-10-26 21:22:16 +02:00
parent 5d449c00e6
commit 96d7c39891
4 changed files with 56 additions and 20 deletions

View File

@ -27,11 +27,12 @@ NANDImporter::NANDImporter() = default;
NANDImporter::~NANDImporter() = default;
void NANDImporter::ImportNANDBin(const std::string& path_to_bin,
std::function<void()> update_callback)
std::function<void()> update_callback,
std::function<std::string()> get_otp_dump_path)
{
m_update_callback = std::move(update_callback);
if (!ReadNANDBin(path_to_bin))
if (!ReadNANDBin(path_to_bin, get_otp_dump_path))
return;
const std::string nand_root = File::GetUserPath(D_WIIROOT_IDX);
@ -45,20 +46,20 @@ void NANDImporter::ImportNANDBin(const std::string& path_to_bin,
ExtractCertificates(nand_root);
}
bool NANDImporter::ReadNANDBin(const std::string& path_to_bin)
bool NANDImporter::ReadNANDBin(const std::string& path_to_bin,
std::function<std::string()> get_otp_dump_path)
{
constexpr size_t NAND_TOTAL_BLOCKS = 0x40000;
constexpr size_t NAND_BLOCK_SIZE = 0x800;
constexpr size_t NAND_ECC_BLOCK_SIZE = 0x40;
constexpr size_t NAND_BIN_SIZE =
(NAND_BLOCK_SIZE + NAND_ECC_BLOCK_SIZE) * NAND_TOTAL_BLOCKS + NAND_KEYS_SIZE; // 0x21000400
(NAND_BLOCK_SIZE + NAND_ECC_BLOCK_SIZE) * NAND_TOTAL_BLOCKS; // 0x21000000
File::IOFile file(path_to_bin, "rb");
if (file.GetSize() != NAND_BIN_SIZE)
const u64 image_size = file.GetSize();
if (image_size != NAND_BIN_SIZE + NAND_KEYS_SIZE && image_size != NAND_BIN_SIZE)
{
PanicAlertT("This file does not look like a BootMii NAND backup. (0x%" PRIx64
" does not equal 0x%zx)",
file.GetSize(), NAND_BIN_SIZE);
PanicAlertT("This file does not look like a BootMii NAND backup.");
return false;
}
@ -76,8 +77,20 @@ bool NANDImporter::ReadNANDBin(const std::string& path_to_bin)
}
m_nand_keys.resize(NAND_KEYS_SIZE);
file.ReadBytes(m_nand_keys.data(), NAND_KEYS_SIZE);
return true;
// Read the OTP/SEEPROM dump.
// If it is not included in the NAND image, get a path to the dump and read key data from it.
if (image_size == NAND_BIN_SIZE)
{
const std::string otp_dump_path = get_otp_dump_path();
if (otp_dump_path.empty())
return false;
File::IOFile keys_file{otp_dump_path, "rb"};
return keys_file.ReadBytes(m_nand_keys.data(), NAND_KEYS_SIZE);
}
// Otherwise, just read the key data from the NAND image.
return file.ReadBytes(m_nand_keys.data(), NAND_KEYS_SIZE);
}
void NANDImporter::FindSuperblock()

View File

@ -18,7 +18,11 @@ public:
NANDImporter();
~NANDImporter();
void ImportNANDBin(const std::string& path_to_bin, std::function<void()> update_callback);
// Extract a NAND image to the configured NAND root.
// If the associated OTP/SEEPROM dump (keys.bin) is not included in the image,
// get_otp_dump_path will be called to get a path to it.
void ImportNANDBin(const std::string& path_to_bin, std::function<void()> update_callback,
std::function<std::string()> get_otp_dump_path);
bool ExtractCertificates(const std::string& nand_root);
private:
@ -38,7 +42,7 @@ private:
};
#pragma pack(pop)
bool ReadNANDBin(const std::string& path_to_bin);
bool ReadNANDBin(const std::string& path_to_bin, std::function<std::string()> get_otp_dump_path);
void FindSuperblock();
std::string GetPath(const NANDFSTEntry& entry, const std::string& parent_path);
std::string FormatDebugString(const NANDFSTEntry& entry);

View File

@ -51,6 +51,7 @@
#include "DolphinQt2/NetPlay/NetPlayDialog.h"
#include "DolphinQt2/NetPlay/NetPlaySetupDialog.h"
#include "DolphinQt2/QtUtils/QueueOnObject.h"
#include "DolphinQt2/QtUtils/RunOnObject.h"
#include "DolphinQt2/QtUtils/WindowActivationEventFilter.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/Settings.h"
@ -879,13 +880,24 @@ void MainWindow::OnImportNANDBackup()
auto beginning = QDateTime::currentDateTime().toMSecsSinceEpoch();
auto result = std::async(std::launch::async, [&] {
DiscIO::NANDImporter().ImportNANDBin(file.toStdString(), [&dialog, beginning] {
QueueOnObject(dialog, [&dialog, beginning] {
dialog->setLabelText(
tr("Importing NAND backup\n Time elapsed: %1s")
.arg((QDateTime::currentDateTime().toMSecsSinceEpoch() - beginning) / 1000));
});
});
DiscIO::NANDImporter().ImportNANDBin(
file.toStdString(),
[&dialog, beginning] {
QueueOnObject(dialog, [&dialog, beginning] {
dialog->setLabelText(
tr("Importing NAND backup\n Time elapsed: %1s")
.arg((QDateTime::currentDateTime().toMSecsSinceEpoch() - beginning) / 1000));
});
},
[this] {
return RunOnObject(this, [this] {
return QFileDialog::getOpenFileName(this, tr("Select the OTP/SEEPROM dump"),
QDir::currentPath(),
tr("BootMii OTP/SEEPROM dump (*.bin);;"
"All Files (*)"))
.toStdString();
});
});
QueueOnObject(dialog, &QProgressDialog::close);
});

View File

@ -1301,7 +1301,14 @@ void CFrame::OnImportBootMiiBackup(wxCommandEvent& WXUNUSED(event))
wxProgressDialog dialog(_("Importing NAND backup"), _("Working..."), 100, this,
wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH);
DiscIO::NANDImporter().ImportNANDBin(file_name, [&dialog] { dialog.Pulse(); });
DiscIO::NANDImporter().ImportNANDBin(
file_name, [&dialog] { dialog.Pulse(); },
[this] {
return WxStrToStr(wxFileSelector(
_("Select the OTP/SEEPROM dump"), wxEmptyString, wxEmptyString, wxEmptyString,
_("BootMii OTP/SEEPROM dump (*.bin)") + "|*.bin|" + wxGetTranslation(wxALL_FILES),
wxFD_OPEN | wxFD_PREVIEW | wxFD_FILE_MUST_EXIST, this));
});
wxPostEvent(GetMenuBar(), wxCommandEvent{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM});
}