Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
5a38c5f190 | |||
80033b84cb | |||
cf9bb90ae3 |
@ -67,7 +67,7 @@ JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_model_GameInfo_initialize(JNIE
|
|||||||
Loader::SMDH* smdh = nullptr;
|
Loader::SMDH* smdh = nullptr;
|
||||||
if (Loader::IsValidSMDH(smdh_data)) {
|
if (Loader::IsValidSMDH(smdh_data)) {
|
||||||
smdh = new Loader::SMDH;
|
smdh = new Loader::SMDH;
|
||||||
memcpy(smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
std::memcpy(smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
||||||
}
|
}
|
||||||
return reinterpret_cast<jlong>(smdh);
|
return reinterpret_cast<jlong>(smdh);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <span>
|
||||||
#include <boost/serialization/access.hpp>
|
#include <boost/serialization/access.hpp>
|
||||||
#include "audio_core/audio_types.h"
|
#include "audio_core/audio_types.h"
|
||||||
#include "audio_core/time_stretch.h"
|
#include "audio_core/time_stretch.h"
|
||||||
@ -80,7 +80,7 @@ public:
|
|||||||
* @param pipe_number The Pipe ID
|
* @param pipe_number The Pipe ID
|
||||||
* @param buffer The data to write to the pipe.
|
* @param buffer The data to write to the pipe.
|
||||||
*/
|
*/
|
||||||
virtual void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) = 0;
|
virtual void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) = 0;
|
||||||
|
|
||||||
/// Returns a reference to the array backing DSP memory
|
/// Returns a reference to the array backing DSP memory
|
||||||
virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
|
virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0;
|
||||||
@ -89,7 +89,7 @@ public:
|
|||||||
virtual void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) = 0;
|
virtual void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) = 0;
|
||||||
|
|
||||||
/// Loads the DSP program
|
/// Loads the DSP program
|
||||||
virtual void LoadComponent(const std::vector<u8>& buffer) = 0;
|
virtual void LoadComponent(std::span<const u8> buffer) = 0;
|
||||||
|
|
||||||
/// Unloads the DSP program
|
/// Unloads the DSP program
|
||||||
virtual void UnloadComponent() = 0;
|
virtual void UnloadComponent() = 0;
|
||||||
|
@ -66,7 +66,7 @@ public:
|
|||||||
bool RecvDataIsReady(u32 register_number) const;
|
bool RecvDataIsReady(u32 register_number) const;
|
||||||
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length);
|
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length);
|
||||||
std::size_t GetPipeReadableSize(DspPipe pipe_number) const;
|
std::size_t GetPipeReadableSize(DspPipe pipe_number) const;
|
||||||
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer);
|
void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer);
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory();
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory();
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ size_t DspHle::Impl::GetPipeReadableSize(DspPipe pipe_number) const {
|
|||||||
return pipe_data[pipe_index].size();
|
return pipe_data[pipe_index].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::Impl::PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
|
void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
||||||
switch (pipe_number) {
|
switch (pipe_number) {
|
||||||
case DspPipe::Audio: {
|
case DspPipe::Audio: {
|
||||||
if (buffer.size() != 4) {
|
if (buffer.size() != 4) {
|
||||||
@ -494,7 +494,7 @@ size_t DspHle::GetPipeReadableSize(DspPipe pipe_number) const {
|
|||||||
return impl->GetPipeReadableSize(pipe_number);
|
return impl->GetPipeReadableSize(pipe_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
|
void DspHle::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
||||||
impl->PipeWrite(pipe_number, buffer);
|
impl->PipeWrite(pipe_number, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +506,7 @@ void DspHle::SetServiceToInterrupt(std::weak_ptr<DSP_DSP> dsp) {
|
|||||||
impl->SetServiceToInterrupt(std::move(dsp));
|
impl->SetServiceToInterrupt(std::move(dsp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspHle::LoadComponent(const std::vector<u8>& component_data) {
|
void DspHle::LoadComponent(std::span<const u8> component_data) {
|
||||||
// HLE doesn't need DSP program. Only log some info here
|
// HLE doesn't need DSP program. Only log some info here
|
||||||
LOG_INFO(Service_DSP, "Firmware hash: {:#018x}",
|
LOG_INFO(Service_DSP, "Firmware hash: {:#018x}",
|
||||||
Common::ComputeHash64(component_data.data(), component_data.size()));
|
Common::ComputeHash64(component_data.data(), component_data.size()));
|
||||||
|
@ -30,13 +30,13 @@ public:
|
|||||||
void SetSemaphore(u16 semaphore_value) override;
|
void SetSemaphore(u16 semaphore_value) override;
|
||||||
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length) override;
|
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length) override;
|
||||||
std::size_t GetPipeReadableSize(DspPipe pipe_number) const override;
|
std::size_t GetPipeReadableSize(DspPipe pipe_number) const override;
|
||||||
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) override;
|
void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override;
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
||||||
|
|
||||||
void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) override;
|
void SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) override;
|
||||||
|
|
||||||
void LoadComponent(const std::vector<u8>& buffer) override;
|
void LoadComponent(std::span<const u8> buffer) override;
|
||||||
void UnloadComponent() override;
|
void UnloadComponent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -26,7 +26,7 @@ enum class SegmentType : u8 {
|
|||||||
|
|
||||||
class Dsp1 {
|
class Dsp1 {
|
||||||
public:
|
public:
|
||||||
explicit Dsp1(const std::vector<u8>& raw);
|
explicit Dsp1(std::span<const u8> raw);
|
||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
std::array<u8, 0x100> signature;
|
std::array<u8, 0x100> signature;
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
bool recv_data_on_start;
|
bool recv_data_on_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
Dsp1::Dsp1(const std::vector<u8>& raw) {
|
Dsp1::Dsp1(std::span<const u8> raw) {
|
||||||
Header header;
|
Header header;
|
||||||
std::memcpy(&header, raw.data(), sizeof(header));
|
std::memcpy(&header, raw.data(), sizeof(header));
|
||||||
recv_data_on_start = header.recv_data_on_start != 0;
|
recv_data_on_start = header.recv_data_on_start != 0;
|
||||||
@ -220,7 +220,7 @@ struct DspLle::Impl final {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WritePipe(u8 pipe_index, const std::vector<u8>& data) {
|
void WritePipe(u8 pipe_index, std::span<const u8> data) {
|
||||||
PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::CPUtoDSP);
|
PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::CPUtoDSP);
|
||||||
bool need_update = false;
|
bool need_update = false;
|
||||||
const u8* buffer_ptr = data.data();
|
const u8* buffer_ptr = data.data();
|
||||||
@ -304,7 +304,7 @@ struct DspLle::Impl final {
|
|||||||
return size & PipeStatus::PtrMask;
|
return size & PipeStatus::PtrMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadComponent(const std::vector<u8>& buffer) {
|
void LoadComponent(std::span<const u8> buffer) {
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
LOG_ERROR(Audio_DSP, "Component already loaded!");
|
LOG_ERROR(Audio_DSP, "Component already loaded!");
|
||||||
return;
|
return;
|
||||||
@ -400,7 +400,7 @@ std::size_t DspLle::GetPipeReadableSize(DspPipe pipe_number) const {
|
|||||||
return impl->GetPipeReadableSize(static_cast<u8>(pipe_number));
|
return impl->GetPipeReadableSize(static_cast<u8>(pipe_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspLle::PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
|
void DspLle::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) {
|
||||||
impl->WritePipe(static_cast<u8>(pipe_number), buffer);
|
impl->WritePipe(static_cast<u8>(pipe_number), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +476,7 @@ void DspLle::SetRecvDataHandler(u8 index, std::function<void()> handler) {
|
|||||||
impl->teakra.SetRecvDataHandler(index, handler);
|
impl->teakra.SetRecvDataHandler(index, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DspLle::LoadComponent(const std::vector<u8>& buffer) {
|
void DspLle::LoadComponent(std::span<const u8> buffer) {
|
||||||
impl->LoadComponent(buffer);
|
impl->LoadComponent(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include "audio_core/dsp_interface.h"
|
#include "audio_core/dsp_interface.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -22,7 +23,7 @@ public:
|
|||||||
void SetSemaphore(u16 semaphore_value) override;
|
void SetSemaphore(u16 semaphore_value) override;
|
||||||
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length) override;
|
std::vector<u8> PipeRead(DspPipe pipe_number, std::size_t length) override;
|
||||||
std::size_t GetPipeReadableSize(DspPipe pipe_number) const override;
|
std::size_t GetPipeReadableSize(DspPipe pipe_number) const override;
|
||||||
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) override;
|
void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override;
|
||||||
|
|
||||||
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override;
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ public:
|
|||||||
void SetSemaphoreHandler(std::function<void()> handler);
|
void SetSemaphoreHandler(std::function<void()> handler);
|
||||||
void SetRecvDataHandler(u8 index, std::function<void()> handler);
|
void SetRecvDataHandler(u8 index, std::function<void()> handler);
|
||||||
|
|
||||||
void LoadComponent(const std::vector<u8>& buffer) override;
|
void LoadComponent(const std::span<const u8> buffer) override;
|
||||||
void UnloadComponent() override;
|
void UnloadComponent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -9,12 +9,12 @@
|
|||||||
#include "core/cheats/cheat_base.h"
|
#include "core/cheats/cheat_base.h"
|
||||||
#include "core/cheats/cheats.h"
|
#include "core/cheats/cheats.h"
|
||||||
#include "core/cheats/gateway_cheat.h"
|
#include "core/cheats/gateway_cheat.h"
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
|
||||||
#include "ui_configure_cheats.h"
|
#include "ui_configure_cheats.h"
|
||||||
|
|
||||||
ConfigureCheats::ConfigureCheats(u64 title_id_, QWidget* parent)
|
ConfigureCheats::ConfigureCheats(Cheats::CheatEngine& cheat_engine_, u64 title_id_, QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureCheats>()), title_id{title_id_} {
|
: QWidget(parent),
|
||||||
|
ui(std::make_unique<Ui::ConfigureCheats>()), cheat_engine{cheat_engine_}, title_id{
|
||||||
|
title_id_} {
|
||||||
// Setup gui control settings
|
// Setup gui control settings
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->tableCheats->setColumnWidth(0, 30);
|
ui->tableCheats->setColumnWidth(0, 30);
|
||||||
@ -36,15 +36,14 @@ ConfigureCheats::ConfigureCheats(u64 title_id_, QWidget* parent)
|
|||||||
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
[this] { SaveCheat(ui->tableCheats->currentRow()); });
|
||||||
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
connect(ui->buttonDelete, &QPushButton::clicked, this, &ConfigureCheats::OnDeleteCheat);
|
||||||
|
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, Core::System::GetInstance());
|
cheat_engine.LoadCheatFile(title_id);
|
||||||
|
|
||||||
LoadCheats();
|
LoadCheats();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureCheats::~ConfigureCheats() = default;
|
ConfigureCheats::~ConfigureCheats() = default;
|
||||||
|
|
||||||
void ConfigureCheats::LoadCheats() {
|
void ConfigureCheats::LoadCheats() {
|
||||||
cheats = cheat_engine->GetCheats();
|
cheats = cheat_engine.GetCheats();
|
||||||
const int cheats_count = static_cast<int>(cheats.size());
|
const int cheats_count = static_cast<int>(cheats.size());
|
||||||
|
|
||||||
ui->tableCheats->setRowCount(cheats_count);
|
ui->tableCheats->setRowCount(cheats_count);
|
||||||
@ -108,12 +107,12 @@ bool ConfigureCheats::SaveCheat(int row) {
|
|||||||
ui->textNotes->toPlainText().toStdString());
|
ui->textNotes->toPlainText().toStdString());
|
||||||
|
|
||||||
if (newly_created) {
|
if (newly_created) {
|
||||||
cheat_engine->AddCheat(cheat);
|
cheat_engine.AddCheat(std::move(cheat));
|
||||||
newly_created = false;
|
newly_created = false;
|
||||||
} else {
|
} else {
|
||||||
cheat_engine->UpdateCheat(row, cheat);
|
cheat_engine.UpdateCheat(row, std::move(cheat));
|
||||||
}
|
}
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
|
|
||||||
int previous_row = ui->tableCheats->currentRow();
|
int previous_row = ui->tableCheats->currentRow();
|
||||||
int previous_col = ui->tableCheats->currentColumn();
|
int previous_col = ui->tableCheats->currentColumn();
|
||||||
@ -163,7 +162,7 @@ void ConfigureCheats::OnCheckChanged(int state) {
|
|||||||
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
|
const QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
|
||||||
int row = static_cast<int>(checkbox->property("row").toInt());
|
int row = static_cast<int>(checkbox->property("row").toInt());
|
||||||
cheats[row]->SetEnabled(state);
|
cheats[row]->SetEnabled(state);
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCheats::OnTextEdited() {
|
void ConfigureCheats::OnTextEdited() {
|
||||||
@ -175,8 +174,8 @@ void ConfigureCheats::OnDeleteCheat() {
|
|||||||
if (newly_created) {
|
if (newly_created) {
|
||||||
newly_created = false;
|
newly_created = false;
|
||||||
} else {
|
} else {
|
||||||
cheat_engine->RemoveCheat(ui->tableCheats->currentRow());
|
cheat_engine.RemoveCheat(ui->tableCheats->currentRow());
|
||||||
cheat_engine->SaveCheatFile();
|
cheat_engine.SaveCheatFile(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadCheats();
|
LoadCheats();
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <QWidget>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Cheats {
|
namespace Cheats {
|
||||||
@ -20,7 +22,8 @@ class ConfigureCheats : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureCheats(u64 title_id_, QWidget* parent = nullptr);
|
explicit ConfigureCheats(Cheats::CheatEngine& cheat_engine, u64 title_id_,
|
||||||
|
QWidget* parent = nullptr);
|
||||||
~ConfigureCheats();
|
~ConfigureCheats();
|
||||||
bool ApplyConfiguration();
|
bool ApplyConfiguration();
|
||||||
|
|
||||||
@ -53,9 +56,9 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ConfigureCheats> ui;
|
std::unique_ptr<Ui::ConfigureCheats> ui;
|
||||||
std::vector<std::shared_ptr<Cheats::CheatBase>> cheats;
|
Cheats::CheatEngine& cheat_engine;
|
||||||
|
std::span<const std::shared_ptr<Cheats::CheatBase>> cheats;
|
||||||
bool edited = false, newly_created = false;
|
bool edited = false, newly_created = false;
|
||||||
int last_row = -1, last_col = -1;
|
int last_row = -1, last_col = -1;
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
|
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const QString
|
|||||||
graphics_tab = std::make_unique<ConfigureGraphics>(this);
|
graphics_tab = std::make_unique<ConfigureGraphics>(this);
|
||||||
system_tab = std::make_unique<ConfigureSystem>(this);
|
system_tab = std::make_unique<ConfigureSystem>(this);
|
||||||
debug_tab = std::make_unique<ConfigureDebug>(this);
|
debug_tab = std::make_unique<ConfigureDebug>(this);
|
||||||
cheat_tab = std::make_unique<ConfigureCheats>(title_id, this);
|
cheat_tab = std::make_unique<ConfigureCheats>(system.CheatEngine(), title_id, this);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ void ConfigurePerGame::HandleApplyButtonClicked() {
|
|||||||
|
|
||||||
static QPixmap GetQPixmapFromSMDH(std::vector<u8>& smdh_data) {
|
static QPixmap GetQPixmapFromSMDH(std::vector<u8>& smdh_data) {
|
||||||
Loader::SMDH smdh;
|
Loader::SMDH smdh;
|
||||||
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
std::memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
||||||
|
|
||||||
bool large = true;
|
bool large = true;
|
||||||
std::vector<u16> icon_data = smdh.GetIcon(large);
|
std::vector<u16> icon_data = smdh.GetIcon(large);
|
||||||
|
@ -487,7 +487,7 @@ void GraphicsVertexShaderWidget::Reload(bool replace_vertex_data, void* vertex_d
|
|||||||
|
|
||||||
if (replace_vertex_data) {
|
if (replace_vertex_data) {
|
||||||
if (vertex_data) {
|
if (vertex_data) {
|
||||||
memcpy(&input_vertex, vertex_data, sizeof(input_vertex));
|
std::memcpy(&input_vertex, vertex_data, sizeof(input_vertex));
|
||||||
for (unsigned attr = 0; attr < 16; ++attr) {
|
for (unsigned attr = 0; attr < 16; ++attr) {
|
||||||
for (unsigned comp = 0; comp < 4; ++comp) {
|
for (unsigned comp = 0; comp < 4; ++comp) {
|
||||||
input_data[4 * attr + comp]->setText(
|
input_data[4 * attr + comp]->setText(
|
||||||
|
@ -18,7 +18,7 @@ QString RecordDialog::FormatObject(const IPCDebugger::ObjectInfo& object) const
|
|||||||
.arg(object.id, 8, 16, QLatin1Char('0'));
|
.arg(object.id, 8, 16, QLatin1Char('0'));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RecordDialog::FormatCmdbuf(const std::vector<u32>& cmdbuf) const {
|
QString RecordDialog::FormatCmdbuf(std::span<const u32> cmdbuf) const {
|
||||||
QString result;
|
QString result;
|
||||||
for (std::size_t i = 0; i < cmdbuf.size(); ++i) {
|
for (std::size_t i = 0; i < cmdbuf.size(); ++i) {
|
||||||
result.append(
|
result.append(
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
@ -28,7 +29,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QString FormatObject(const IPCDebugger::ObjectInfo& object) const;
|
QString FormatObject(const IPCDebugger::ObjectInfo& object) const;
|
||||||
QString FormatCmdbuf(const std::vector<u32>& cmdbuf) const;
|
QString FormatCmdbuf(std::span<const u32> cmdbuf) const;
|
||||||
void UpdateCmdbufDisplay();
|
void UpdateCmdbufDisplay();
|
||||||
|
|
||||||
std::unique_ptr<Ui::RecordDialog> ui;
|
std::unique_ptr<Ui::RecordDialog> ui;
|
||||||
|
@ -64,7 +64,7 @@ WaitTreeItem* WaitTreeItem::Parent() const {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::unique_ptr<WaitTreeItem>>& WaitTreeItem::Children() const {
|
std::span<const std::unique_ptr<WaitTreeItem>> WaitTreeItem::Children() const {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
@ -36,7 +37,7 @@ public:
|
|||||||
|
|
||||||
void Expand();
|
void Expand();
|
||||||
WaitTreeItem* Parent() const;
|
WaitTreeItem* Parent() const;
|
||||||
const std::vector<std::unique_ptr<WaitTreeItem>>& Children() const;
|
std::span<const std::unique_ptr<WaitTreeItem>> Children() const;
|
||||||
std::size_t Row() const;
|
std::size_t Row() const;
|
||||||
static std::vector<std::unique_ptr<WaitTreeThread>> MakeThreadItemList();
|
static std::vector<std::unique_ptr<WaitTreeThread>> MakeThreadItemList();
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include "core/dumping/ffmpeg_backend.h"
|
#include "core/dumping/ffmpeg_backend.h"
|
||||||
|
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <span>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@ -153,7 +155,7 @@ public:
|
|||||||
static constexpr int LongTitleRole = SortRole + 5;
|
static constexpr int LongTitleRole = SortRole + 5;
|
||||||
|
|
||||||
GameListItemPath() = default;
|
GameListItemPath() = default;
|
||||||
GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id,
|
GameListItemPath(const QString& game_path, std::span<const u8> smdh_data, u64 program_id,
|
||||||
u64 extdata_id) {
|
u64 extdata_id) {
|
||||||
setData(type(), TypeRole);
|
setData(type(), TypeRole);
|
||||||
setData(game_path, FullPathRole);
|
setData(game_path, FullPathRole);
|
||||||
@ -178,7 +180,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader::SMDH smdh;
|
Loader::SMDH smdh;
|
||||||
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
std::memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
||||||
|
|
||||||
// Get icon from SMDH
|
// Get icon from SMDH
|
||||||
if (UISettings::values.game_list_icon_size.GetValue() !=
|
if (UISettings::values.game_list_icon_size.GetValue() !=
|
||||||
@ -286,7 +288,7 @@ public:
|
|||||||
class GameListItemRegion : public GameListItem {
|
class GameListItemRegion : public GameListItem {
|
||||||
public:
|
public:
|
||||||
GameListItemRegion() = default;
|
GameListItemRegion() = default;
|
||||||
explicit GameListItemRegion(const std::vector<u8>& smdh_data) {
|
explicit GameListItemRegion(std::span<const u8> smdh_data) {
|
||||||
setData(type(), TypeRole);
|
setData(type(), TypeRole);
|
||||||
|
|
||||||
if (!Loader::IsValidSMDH(smdh_data)) {
|
if (!Loader::IsValidSMDH(smdh_data)) {
|
||||||
@ -295,7 +297,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader::SMDH smdh;
|
Loader::SMDH smdh;
|
||||||
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
std::memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
||||||
|
|
||||||
setText(GetRegionFromSMDH(smdh));
|
setText(GetRegionFromSMDH(smdh));
|
||||||
setData(GetRegionFromSMDH(smdh), SortRole);
|
setData(GetRegionFromSMDH(smdh), SortRole);
|
||||||
|
@ -80,7 +80,7 @@ const static std::unordered_map<VideoCore::LoadCallbackStage, const char*> progr
|
|||||||
|
|
||||||
static QPixmap GetQPixmapFromSMDH(std::vector<u8>& smdh_data) {
|
static QPixmap GetQPixmapFromSMDH(std::vector<u8>& smdh_data) {
|
||||||
Loader::SMDH smdh;
|
Loader::SMDH smdh;
|
||||||
memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
std::memcpy(&smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
||||||
|
|
||||||
bool large = true;
|
bool large = true;
|
||||||
std::vector<u16> icon_data = smdh.GetIcon(large);
|
std::vector<u16> icon_data = smdh.GetIcon(large);
|
||||||
|
@ -53,7 +53,8 @@ add_library(citra_common STATIC
|
|||||||
archives.h
|
archives.h
|
||||||
assert.h
|
assert.h
|
||||||
atomic_ops.h
|
atomic_ops.h
|
||||||
bit_cast.h
|
detached_tasks.cpp
|
||||||
|
detached_tasks.h
|
||||||
bit_field.h
|
bit_field.h
|
||||||
bit_set.h
|
bit_set.h
|
||||||
bounded_threadsafe_queue.h
|
bounded_threadsafe_queue.h
|
||||||
@ -65,8 +66,6 @@ add_library(citra_common STATIC
|
|||||||
common_precompiled_headers.h
|
common_precompiled_headers.h
|
||||||
common_types.h
|
common_types.h
|
||||||
construct.h
|
construct.h
|
||||||
detached_tasks.cpp
|
|
||||||
detached_tasks.h
|
|
||||||
dynamic_library/dynamic_library.cpp
|
dynamic_library/dynamic_library.cpp
|
||||||
dynamic_library/dynamic_library.h
|
dynamic_library/dynamic_library.h
|
||||||
dynamic_library/fdk-aac.cpp
|
dynamic_library/fdk-aac.cpp
|
||||||
@ -112,7 +111,6 @@ add_library(citra_common STATIC
|
|||||||
settings.cpp
|
settings.cpp
|
||||||
settings.h
|
settings.h
|
||||||
slot_vector.h
|
slot_vector.h
|
||||||
socket_types.h
|
|
||||||
serialization/atomic.h
|
serialization/atomic.h
|
||||||
serialization/boost_discrete_interval.hpp
|
serialization/boost_discrete_interval.hpp
|
||||||
serialization/boost_flat_set.h
|
serialization/boost_flat_set.h
|
||||||
|
@ -13,20 +13,26 @@
|
|||||||
// lambda and force the compiler to not inline it.
|
// lambda and force the compiler to not inline it.
|
||||||
|
|
||||||
#define ASSERT(_a_) \
|
#define ASSERT(_a_) \
|
||||||
([&]() CITRA_NO_INLINE { \
|
do \
|
||||||
if (!(_a_)) [[unlikely]] { \
|
if (!(_a_)) [[unlikely]] { \
|
||||||
|
[]() CITRA_NO_INLINE CITRA_NO_RETURN { \
|
||||||
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
||||||
Crash(); \
|
Crash(); \
|
||||||
|
exit(1); \
|
||||||
|
}(); \
|
||||||
} \
|
} \
|
||||||
}())
|
while (0)
|
||||||
|
|
||||||
#define ASSERT_MSG(_a_, ...) \
|
#define ASSERT_MSG(_a_, ...) \
|
||||||
([&]() CITRA_NO_INLINE { \
|
do \
|
||||||
if (!(_a_)) [[unlikely]] { \
|
if (!(_a_)) [[unlikely]] { \
|
||||||
|
[&]() CITRA_NO_INLINE CITRA_NO_RETURN { \
|
||||||
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
||||||
Crash(); \
|
Crash(); \
|
||||||
|
exit(1); \
|
||||||
|
}(); \
|
||||||
} \
|
} \
|
||||||
}())
|
while (0)
|
||||||
|
|
||||||
#define UNREACHABLE() \
|
#define UNREACHABLE() \
|
||||||
([]() CITRA_NO_INLINE CITRA_NO_RETURN { \
|
([]() CITRA_NO_INLINE CITRA_NO_RETURN { \
|
||||||
@ -52,6 +58,3 @@
|
|||||||
|
|
||||||
#define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!")
|
#define UNIMPLEMENTED() LOG_CRITICAL(Debug, "Unimplemented code!")
|
||||||
#define UNIMPLEMENTED_MSG(_a_, ...) LOG_CRITICAL(Debug, _a_, __VA_ARGS__)
|
#define UNIMPLEMENTED_MSG(_a_, ...) LOG_CRITICAL(Debug, _a_, __VA_ARGS__)
|
||||||
|
|
||||||
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
|
||||||
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <version>
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_bit_cast
|
|
||||||
#include <bit>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Common {
|
|
||||||
|
|
||||||
template <typename To, typename From>
|
|
||||||
constexpr inline To BitCast(const From& from) {
|
|
||||||
#ifdef __cpp_lib_bit_cast
|
|
||||||
return std::bit_cast<To>(from);
|
|
||||||
#else
|
|
||||||
return __builtin_bit_cast(To, from);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common
|
|
@ -110,15 +110,6 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
|||||||
return static_cast<T>(key) == 0; \
|
return static_cast<T>(key) == 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CITRA_NON_COPYABLE(cls) \
|
|
||||||
cls(const cls&) = delete; \
|
|
||||||
cls& operator=(const cls&) = delete
|
|
||||||
|
|
||||||
#define CITRA_NON_MOVEABLE(cls) \
|
|
||||||
cls(cls&&) = delete; \
|
|
||||||
cls& operator=(cls&&) = delete
|
|
||||||
|
|
||||||
|
|
||||||
// Generic function to get last error message.
|
// Generic function to get last error message.
|
||||||
// Call directly after the command or use the error num.
|
// Call directly after the command or use the error num.
|
||||||
// This function might change the error code.
|
// This function might change the error code.
|
||||||
|
@ -855,7 +855,7 @@ const std::string& GetDefaultUserPath(UserPath path) {
|
|||||||
return g_default_paths[path];
|
return g_default_paths[path];
|
||||||
}
|
}
|
||||||
|
|
||||||
const void UpdateUserPath(UserPath path, const std::string& filename) {
|
void UpdateUserPath(UserPath path, const std::string& filename) {
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ void SetCurrentRomPath(const std::string& path);
|
|||||||
[[nodiscard]] const std::string& GetDefaultUserPath(UserPath path);
|
[[nodiscard]] const std::string& GetDefaultUserPath(UserPath path);
|
||||||
|
|
||||||
// Update the Global Path with the new value
|
// Update the Global Path with the new value
|
||||||
const void UpdateUserPath(UserPath path, const std::string& filename);
|
void UpdateUserPath(UserPath path, const std::string& filename);
|
||||||
|
|
||||||
// Returns the path to where the sys file are
|
// Returns the path to where the sys file are
|
||||||
[[nodiscard]] std::string GetSysDirectory();
|
[[nodiscard]] std::string GetSysDirectory();
|
||||||
|
@ -154,7 +154,7 @@ private:
|
|||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
||||||
memcpy(ver, scm_rev_git_str, 40);
|
std::memcpy(ver, scm_rev_git_str, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 id;
|
const u32 id;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <span>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@ -57,7 +58,7 @@ public:
|
|||||||
return push_count;
|
return push_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Push(const std::vector<T>& input) {
|
std::size_t Push(std::span<const T> input) {
|
||||||
return Push(input.data(), input.size() / granularity);
|
return Push(input.data(), input.size() / granularity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,9 +505,6 @@ struct Values {
|
|||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
Setting<std::string> log_filter{"*:Info", "log_filter"};
|
Setting<std::string> log_filter{"*:Info", "log_filter"};
|
||||||
|
|
||||||
// Network
|
|
||||||
Setting<std::string> network_interface{std::string(), "network_interface"};
|
|
||||||
|
|
||||||
// Video Dumping
|
// Video Dumping
|
||||||
std::string output_format;
|
std::string output_format;
|
||||||
std::string format_options;
|
std::string format_options;
|
||||||
|
@ -1,143 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/swap.h"
|
|
||||||
|
|
||||||
namespace Network {
|
|
||||||
|
|
||||||
/// Address families
|
|
||||||
enum class Domain : u32 {
|
|
||||||
UNSPEC = 0,
|
|
||||||
INET = 2, ///< Address family for IPv4
|
|
||||||
INET6 = 23,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Socket types
|
|
||||||
enum class Type : u32 {
|
|
||||||
STREAM = 1,
|
|
||||||
DGRAM = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Shutdown mode
|
|
||||||
enum class ShutdownHow {
|
|
||||||
RD,
|
|
||||||
WR,
|
|
||||||
RDWR,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FcntlCmd : u32 {
|
|
||||||
GETFL = 3,
|
|
||||||
SETFL = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class SendFlags : u32 {
|
|
||||||
OOB = 1,
|
|
||||||
PEEK = 2,
|
|
||||||
DONTWAIT = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(SendFlags)
|
|
||||||
|
|
||||||
/// Array of IPv4 address
|
|
||||||
using IPv4Address = std::array<u8, 4>;
|
|
||||||
|
|
||||||
/// Union to represent the 3DS sockaddr structure
|
|
||||||
union CTRSockAddr {
|
|
||||||
/// Structure to represent a raw sockaddr
|
|
||||||
struct {
|
|
||||||
u8 len; ///< The length of the entire structure, only the set fields count
|
|
||||||
u8 sa_family; ///< The address family of the sockaddr
|
|
||||||
u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family
|
|
||||||
} raw;
|
|
||||||
|
|
||||||
/// Structure to represent the 3ds' sockaddr_in structure
|
|
||||||
struct CTRSockAddrIn {
|
|
||||||
u8 len; ///< The length of the entire structure
|
|
||||||
u8 sin_family; ///< The address family of the sockaddr_in
|
|
||||||
u16 sin_port; ///< The port associated with this sockaddr_in
|
|
||||||
u32 sin_addr; ///< The actual address of the sockaddr_in
|
|
||||||
} in;
|
|
||||||
static_assert(sizeof(CTRSockAddrIn) == 8, "Invalid CTRSockAddrIn size");
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CTRAddrInfo {
|
|
||||||
s32_le ai_flags;
|
|
||||||
s32_le ai_family;
|
|
||||||
s32_le ai_socktype;
|
|
||||||
s32_le ai_protocol;
|
|
||||||
s32_le ai_addrlen;
|
|
||||||
char ai_canonname[256];
|
|
||||||
CTRSockAddr ai_addr;
|
|
||||||
|
|
||||||
static u32 AddressInfoFlagsToPlatform(u32 flags) {
|
|
||||||
u32 ret = 0;
|
|
||||||
if (flags & 1) {
|
|
||||||
ret |= AI_PASSIVE;
|
|
||||||
}
|
|
||||||
if (flags & 2) {
|
|
||||||
ret |= AI_CANONNAME;
|
|
||||||
}
|
|
||||||
if (flags & 4) {
|
|
||||||
ret |= AI_NUMERICHOST;
|
|
||||||
}
|
|
||||||
if (flags & 8) {
|
|
||||||
ret |= AI_NUMERICSERV;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 AddressInfoFlagsFromPlatform(u32 flags) {
|
|
||||||
u32 ret = 0;
|
|
||||||
if (flags & AI_PASSIVE) {
|
|
||||||
ret |= 1;
|
|
||||||
}
|
|
||||||
if (flags & AI_CANONNAME) {
|
|
||||||
ret |= 2;
|
|
||||||
}
|
|
||||||
if (flags & AI_NUMERICHOST) {
|
|
||||||
ret |= 4;
|
|
||||||
}
|
|
||||||
if (flags & AI_NUMERICSERV) {
|
|
||||||
ret |= 8;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a platform-specific addrinfo to a 3ds addrinfo.
|
|
||||||
static CTRAddrInfo FromPlatform(const addrinfo& addr) {
|
|
||||||
CTRAddrInfo ctr_addr{
|
|
||||||
.ai_flags = static_cast<s32_le>(AddressInfoFlagsFromPlatform(addr.ai_flags)),
|
|
||||||
.ai_family = static_cast<s32_le>(SocketDomainFromPlatform(addr.ai_family)),
|
|
||||||
.ai_socktype = static_cast<s32_le>(SocketTypeFromPlatform(addr.ai_socktype)),
|
|
||||||
.ai_protocol = static_cast<s32_le>(SocketProtocolFromPlatform(addr.ai_protocol)),
|
|
||||||
.ai_addr = CTRSockAddr::FromPlatform(*addr.ai_addr),
|
|
||||||
};
|
|
||||||
ctr_addr.ai_addrlen = static_cast<s32_le>(ctr_addr.ai_addr.raw.len);
|
|
||||||
if (addr.ai_canonname)
|
|
||||||
std::strncpy(ctr_addr.ai_canonname, addr.ai_canonname,
|
|
||||||
sizeof(ctr_addr.ai_canonname) - 1);
|
|
||||||
return ctr_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts a platform-specific addrinfo to a 3ds addrinfo.
|
|
||||||
static addrinfo ToPlatform(const CTRAddrInfo& ctr_addr) {
|
|
||||||
// Only certain fields are meaningful in hints, copy them manually
|
|
||||||
addrinfo addr = {
|
|
||||||
.ai_flags = static_cast<int>(AddressInfoFlagsToPlatform(ctr_addr.ai_flags)),
|
|
||||||
.ai_family = static_cast<int>(SocketDomainToPlatform(ctr_addr.ai_family)),
|
|
||||||
.ai_socktype = static_cast<int>(SocketTypeToPlatform(ctr_addr.ai_socktype)),
|
|
||||||
.ai_protocol = static_cast<int>(SocketProtocolToPlatform(ctr_addr.ai_protocol)),
|
|
||||||
};
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(CTRAddrInfo) == 0x130, "Size of CTRAddrInfo is not correct");
|
|
||||||
|
|
||||||
constexpr u32 FLAG_MSG_PEEK = 0x2;
|
|
||||||
constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
|
|
||||||
constexpr u32 FLAG_O_NONBLOCK = 0x800;
|
|
||||||
|
|
||||||
} // namespace Network
|
|
@ -56,7 +56,7 @@ static CPUCaps Detect() {
|
|||||||
// Citra at all anyway
|
// Citra at all anyway
|
||||||
|
|
||||||
int cpu_id[4];
|
int cpu_id[4];
|
||||||
memset(caps.brand_string, 0, sizeof(caps.brand_string));
|
std::memset(caps.brand_string, 0, sizeof(caps.brand_string));
|
||||||
|
|
||||||
// Detect CPU's CPUID capabilities and grab CPU string
|
// Detect CPU's CPUID capabilities and grab CPU string
|
||||||
__cpuid(cpu_id, 0x00000000);
|
__cpuid(cpu_id, 0x00000000);
|
||||||
|
@ -5,19 +5,18 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/zstd_compression.h"
|
#include "common/zstd_compression.h"
|
||||||
|
|
||||||
namespace Common::Compression {
|
namespace Common::Compression {
|
||||||
|
|
||||||
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) {
|
std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level) {
|
||||||
compression_level = std::clamp(compression_level, ZSTD_minCLevel(), ZSTD_maxCLevel());
|
compression_level = std::clamp(compression_level, ZSTD_minCLevel(), ZSTD_maxCLevel());
|
||||||
|
|
||||||
const std::size_t max_compressed_size = ZSTD_compressBound(source_size);
|
const std::size_t max_compressed_size = ZSTD_compressBound(source.size());
|
||||||
std::vector<u8> compressed(max_compressed_size);
|
std::vector<u8> compressed(max_compressed_size);
|
||||||
|
|
||||||
const std::size_t compressed_size =
|
const std::size_t compressed_size = ZSTD_compress(
|
||||||
ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level);
|
compressed.data(), compressed.size(), source.data(), source.size(), compression_level);
|
||||||
|
|
||||||
if (ZSTD_isError(compressed_size)) {
|
if (ZSTD_isError(compressed_size)) {
|
||||||
// Compression failed
|
// Compression failed
|
||||||
@ -29,11 +28,11 @@ std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32
|
|||||||
return compressed;
|
return compressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
|
std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source) {
|
||||||
return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
|
return CompressDataZSTD(source, ZSTD_CLEVEL_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
|
std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) {
|
||||||
const std::size_t decompressed_size =
|
const std::size_t decompressed_size =
|
||||||
ZSTD_getFrameContentSize(compressed.data(), compressed.size());
|
ZSTD_getFrameContentSize(compressed.data(), compressed.size());
|
||||||
std::vector<u8> decompressed(decompressed_size);
|
std::vector<u8> decompressed(decompressed_size);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@ -14,24 +15,21 @@ namespace Common::Compression {
|
|||||||
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
|
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
|
||||||
*
|
*
|
||||||
* @param source the uncompressed source memory region.
|
* @param source the uncompressed source memory region.
|
||||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
|
||||||
* @param compression_level the used compression level. Should be between 1 and 22.
|
* @param compression_level the used compression level. Should be between 1 and 22.
|
||||||
*
|
*
|
||||||
* @return the compressed data.
|
* @return the compressed data.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size,
|
[[nodiscard]] std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level);
|
||||||
s32 compression_level);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses a source memory region with Zstandard with the default compression level and returns
|
* Compresses a source memory region with Zstandard with the default compression level and returns
|
||||||
* the compressed data in a vector.
|
* the compressed data in a vector.
|
||||||
*
|
*
|
||||||
* @param source the uncompressed source memory region.
|
* @param source the uncompressed source memory region.
|
||||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
|
||||||
*
|
*
|
||||||
* @return the compressed data.
|
* @return the compressed data.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
|
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
|
||||||
@ -40,6 +38,6 @@ namespace Common::Compression {
|
|||||||
*
|
*
|
||||||
* @return the decompressed data.
|
* @return the decompressed data.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
[[nodiscard]] std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed);
|
||||||
|
|
||||||
} // namespace Common::Compression
|
} // namespace Common::Compression
|
||||||
|
@ -439,11 +439,6 @@ add_library(citra_core STATIC
|
|||||||
hw/rsa/rsa.h
|
hw/rsa/rsa.h
|
||||||
hw/y2r.cpp
|
hw/y2r.cpp
|
||||||
hw/y2r.h
|
hw/y2r.h
|
||||||
network/network.cpp
|
|
||||||
network/network.h
|
|
||||||
network/network_interface.cpp
|
|
||||||
network/network_interface.h
|
|
||||||
network/sockets.h
|
|
||||||
loader/3dsx.cpp
|
loader/3dsx.cpp
|
||||||
loader/3dsx.h
|
loader/3dsx.h
|
||||||
loader/elf.cpp
|
loader/elf.cpp
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
#include "core/cheats/gateway_cheat.h"
|
#include "core/cheats/gateway_cheat.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/process.h"
|
|
||||||
#include "core/hw/gpu.h"
|
|
||||||
|
|
||||||
namespace Cheats {
|
namespace Cheats {
|
||||||
|
|
||||||
@ -19,11 +17,11 @@ namespace Cheats {
|
|||||||
// we use the same value
|
// we use the same value
|
||||||
constexpr u64 run_interval_ticks = 50'000'000;
|
constexpr u64 run_interval_ticks = 50'000'000;
|
||||||
|
|
||||||
CheatEngine::CheatEngine(u64 title_id_, Core::System& system_)
|
CheatEngine::CheatEngine(Core::System& system_) : system{system_} {}
|
||||||
: system(system_), title_id{title_id_} {
|
|
||||||
LoadCheatFile();
|
CheatEngine::~CheatEngine() {
|
||||||
if (system.IsPoweredOn()) {
|
if (system.IsPoweredOn()) {
|
||||||
Connect();
|
system.CoreTiming().UnscheduleEvent(event, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,24 +32,18 @@ void CheatEngine::Connect() {
|
|||||||
system.CoreTiming().ScheduleEvent(run_interval_ticks, event);
|
system.CoreTiming().ScheduleEvent(run_interval_ticks, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
CheatEngine::~CheatEngine() {
|
std::span<const std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
|
||||||
if (system.IsPoweredOn()) {
|
std::shared_lock lock{cheats_list_mutex};
|
||||||
system.CoreTiming().UnscheduleEvent(event, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<CheatBase>> CheatEngine::GetCheats() const {
|
|
||||||
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
|
|
||||||
return cheats_list;
|
return cheats_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::AddCheat(const std::shared_ptr<CheatBase>& cheat) {
|
void CheatEngine::AddCheat(std::shared_ptr<CheatBase>&& cheat) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
cheats_list.push_back(cheat);
|
cheats_list.push_back(std::move(cheat));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::RemoveCheat(std::size_t index) {
|
void CheatEngine::RemoveCheat(std::size_t index) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
if (index < 0 || index >= cheats_list.size()) {
|
if (index < 0 || index >= cheats_list.size()) {
|
||||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||||
return;
|
return;
|
||||||
@ -59,16 +51,16 @@ void CheatEngine::RemoveCheat(std::size_t index) {
|
|||||||
cheats_list.erase(cheats_list.begin() + index);
|
cheats_list.erase(cheats_list.begin() + index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat) {
|
void CheatEngine::UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat) {
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
if (index < 0 || index >= cheats_list.size()) {
|
if (index < 0 || index >= cheats_list.size()) {
|
||||||
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
LOG_ERROR(Core_Cheats, "Invalid index {}", index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cheats_list[index] = new_cheat;
|
cheats_list[index] = std::move(new_cheat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::SaveCheatFile() const {
|
void CheatEngine::SaveCheatFile(u64 title_id) const {
|
||||||
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
||||||
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
||||||
|
|
||||||
@ -83,7 +75,7 @@ void CheatEngine::SaveCheatFile() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::LoadCheatFile() {
|
void CheatEngine::LoadCheatFile(u64 title_id) {
|
||||||
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
const std::string cheat_dir = FileUtil::GetUserPath(FileUtil::UserPath::CheatsDir);
|
||||||
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
const std::string filepath = fmt::format("{}{:016X}.txt", cheat_dir, title_id);
|
||||||
|
|
||||||
@ -96,15 +88,15 @@ void CheatEngine::LoadCheatFile() {
|
|||||||
|
|
||||||
auto gateway_cheats = GatewayCheat::LoadFile(filepath);
|
auto gateway_cheats = GatewayCheat::LoadFile(filepath);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::unique_lock lock{cheats_list_mutex};
|
||||||
std::move(gateway_cheats.begin(), gateway_cheats.end(), std::back_inserter(cheats_list));
|
cheats_list = std::move(gateway_cheats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) {
|
void CheatEngine::RunCallback([[maybe_unused]] std::uintptr_t user_data, s64 cycles_late) {
|
||||||
{
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(cheats_list_mutex);
|
std::shared_lock lock{cheats_list_mutex};
|
||||||
for (auto& cheat : cheats_list) {
|
for (const auto& cheat : cheats_list) {
|
||||||
if (cheat->IsEnabled()) {
|
if (cheat->IsEnabled()) {
|
||||||
cheat->Execute(system);
|
cheat->Execute(system);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@ -24,22 +25,38 @@ class CheatBase;
|
|||||||
|
|
||||||
class CheatEngine {
|
class CheatEngine {
|
||||||
public:
|
public:
|
||||||
explicit CheatEngine(u64 title_id_, Core::System& system);
|
explicit CheatEngine(Core::System& system);
|
||||||
~CheatEngine();
|
~CheatEngine();
|
||||||
|
|
||||||
|
/// Registers the cheat execution callback.
|
||||||
void Connect();
|
void Connect();
|
||||||
std::vector<std::shared_ptr<CheatBase>> GetCheats() const;
|
|
||||||
void AddCheat(const std::shared_ptr<CheatBase>& cheat);
|
/// Returns a span of the currently active cheats.
|
||||||
|
std::span<const std::shared_ptr<CheatBase>> GetCheats() const;
|
||||||
|
|
||||||
|
/// Adds a cheat to the cheat engine.
|
||||||
|
void AddCheat(std::shared_ptr<CheatBase>&& cheat);
|
||||||
|
|
||||||
|
/// Removes a cheat at the specified index in the cheats list.
|
||||||
void RemoveCheat(std::size_t index);
|
void RemoveCheat(std::size_t index);
|
||||||
void UpdateCheat(std::size_t index, const std::shared_ptr<CheatBase>& new_cheat);
|
|
||||||
void SaveCheatFile() const;
|
/// Updates a cheat at the specified index in the cheats list.
|
||||||
|
void UpdateCheat(std::size_t index, std::shared_ptr<CheatBase>&& new_cheat);
|
||||||
|
|
||||||
|
/// Loads the cheat file from disk for the specified title id.
|
||||||
|
void LoadCheatFile(u64 title_id);
|
||||||
|
|
||||||
|
/// Saves currently active cheats to file for the specified title id.
|
||||||
|
void SaveCheatFile(u64 title_id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadCheatFile();
|
/// The cheat execution callback.
|
||||||
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
|
void RunCallback(std::uintptr_t user_data, s64 cycles_late);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::System& system;
|
||||||
|
Core::TimingEventType* event;
|
||||||
std::vector<std::shared_ptr<CheatBase>> cheats_list;
|
std::vector<std::shared_ptr<CheatBase>> cheats_list;
|
||||||
mutable std::shared_mutex cheats_list_mutex;
|
mutable std::shared_mutex cheats_list_mutex;
|
||||||
Core::TimingEventType* event;
|
|
||||||
Core::System& system;
|
|
||||||
u64 title_id;
|
|
||||||
};
|
};
|
||||||
} // namespace Cheats
|
} // namespace Cheats
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/iostreams/device/file_descriptor.hpp>
|
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||||
@ -144,7 +145,7 @@ static inline void JokerOp(const GatewayCheat::CheatLine& line, State& state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Core::System& system,
|
static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Core::System& system,
|
||||||
const std::vector<GatewayCheat::CheatLine>& cheat_lines) {
|
std::span<const GatewayCheat::CheatLine> cheat_lines) {
|
||||||
if (state.if_flag > 0) {
|
if (state.if_flag > 0) {
|
||||||
// Skip over the additional patch lines
|
// Skip over the additional patch lines
|
||||||
state.current_line_nr += static_cast<int>(std::ceil(line.value / 8.0));
|
state.current_line_nr += static_cast<int>(std::ceil(line.value / 8.0));
|
||||||
@ -471,8 +472,8 @@ std::string GatewayCheat::ToString() const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
|
std::vector<std::shared_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string& filepath) {
|
||||||
std::vector<std::unique_ptr<CheatBase>> cheats;
|
std::vector<std::shared_ptr<CheatBase>> cheats;
|
||||||
|
|
||||||
boost::iostreams::stream<boost::iostreams::file_descriptor_source> file;
|
boost::iostreams::stream<boost::iostreams::file_descriptor_source> file;
|
||||||
FileUtil::OpenFStream<std::ios_base::in>(file, filepath);
|
FileUtil::OpenFStream<std::ios_base::in>(file, filepath);
|
||||||
@ -492,7 +493,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
|
|||||||
line = Common::StripSpaces(line); // remove spaces at front and end
|
line = Common::StripSpaces(line); // remove spaces at front and end
|
||||||
if (line.length() >= 2 && line.front() == '[') {
|
if (line.length() >= 2 && line.front() == '[') {
|
||||||
if (!cheat_lines.empty()) {
|
if (!cheat_lines.empty()) {
|
||||||
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
|
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
|
||||||
cheats.back()->SetEnabled(enabled);
|
cheats.back()->SetEnabled(enabled);
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
@ -510,7 +511,7 @@ std::vector<std::unique_ptr<CheatBase>> GatewayCheat::LoadFile(const std::string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cheat_lines.empty()) {
|
if (!cheat_lines.empty()) {
|
||||||
cheats.push_back(std::make_unique<GatewayCheat>(name, cheat_lines, comments));
|
cheats.push_back(std::make_shared<GatewayCheat>(name, cheat_lines, comments));
|
||||||
cheats.back()->SetEnabled(enabled);
|
cheats.back()->SetEnabled(enabled);
|
||||||
}
|
}
|
||||||
return cheats;
|
return cheats;
|
||||||
|
@ -77,7 +77,7 @@ public:
|
|||||||
/// (there might be multiple lines of those hex numbers)
|
/// (there might be multiple lines of those hex numbers)
|
||||||
/// Comment lines start with a '*'
|
/// Comment lines start with a '*'
|
||||||
/// This function will pares the file for such structures
|
/// This function will pares the file for such structures
|
||||||
static std::vector<std::unique_ptr<CheatBase>> LoadFile(const std::string& filepath);
|
static std::vector<std::shared_ptr<CheatBase>> LoadFile(const std::string& filepath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> enabled = false;
|
std::atomic<bool> enabled = false;
|
||||||
|
@ -72,6 +72,8 @@ Core::Timing& Global() {
|
|||||||
return System::GetInstance().CoreTiming();
|
return System::GetInstance().CoreTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System::System() : cheat_engine{*this} {}
|
||||||
|
|
||||||
System::~System() = default;
|
System::~System() = default;
|
||||||
|
|
||||||
System::ResultStatus System::RunLoop(bool tight_loop) {
|
System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||||
@ -318,7 +320,10 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
||||||
static_cast<u32>(load_result));
|
static_cast<u32>(load_result));
|
||||||
}
|
}
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this);
|
|
||||||
|
cheat_engine.LoadCheatFile(title_id);
|
||||||
|
cheat_engine.Connect();
|
||||||
|
|
||||||
perf_stats = std::make_unique<PerfStats>(title_id);
|
perf_stats = std::make_unique<PerfStats>(title_id);
|
||||||
|
|
||||||
if (Settings::values.custom_textures) {
|
if (Settings::values.custom_textures) {
|
||||||
@ -489,11 +494,11 @@ const Memory::MemorySystem& System::Memory() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Cheats::CheatEngine& System::CheatEngine() {
|
Cheats::CheatEngine& System::CheatEngine() {
|
||||||
return *cheat_engine;
|
return cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cheats::CheatEngine& System::CheatEngine() const {
|
const Cheats::CheatEngine& System::CheatEngine() const {
|
||||||
return *cheat_engine;
|
return cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> dumper) {
|
void System::RegisterVideoDumper(std::shared_ptr<VideoDumper::Backend> dumper) {
|
||||||
@ -540,7 +545,6 @@ void System::Shutdown(bool is_deserializing) {
|
|||||||
if (!is_deserializing) {
|
if (!is_deserializing) {
|
||||||
GDBStub::Shutdown();
|
GDBStub::Shutdown();
|
||||||
perf_stats.reset();
|
perf_stats.reset();
|
||||||
cheat_engine.reset();
|
|
||||||
app_loader.reset();
|
app_loader.reset();
|
||||||
}
|
}
|
||||||
custom_tex_manager.reset();
|
custom_tex_manager.reset();
|
||||||
@ -712,7 +716,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
|
|||||||
timing->UnlockEventQueue();
|
timing->UnlockEventQueue();
|
||||||
Service::GSP::SetGlobalModule(*this);
|
Service::GSP::SetGlobalModule(*this);
|
||||||
memory->SetDSP(*dsp_core);
|
memory->SetDSP(*dsp_core);
|
||||||
cheat_engine->Connect();
|
cheat_engine.Connect();
|
||||||
VideoCore::g_renderer->Sync();
|
VideoCore::g_renderer->Sync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/serialization/version.hpp>
|
#include <boost/serialization/version.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/cheats/cheats.h"
|
||||||
#include "core/frontend/applets/mii_selector.h"
|
#include "core/frontend/applets/mii_selector.h"
|
||||||
#include "core/frontend/applets/swkbd.h"
|
#include "core/frontend/applets/swkbd.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
@ -49,10 +50,6 @@ namespace Kernel {
|
|||||||
class KernelSystem;
|
class KernelSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Cheats {
|
|
||||||
class CheatEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace VideoDumper {
|
namespace VideoDumper {
|
||||||
class Backend;
|
class Backend;
|
||||||
}
|
}
|
||||||
@ -95,6 +92,7 @@ public:
|
|||||||
ErrorUnknown ///< Any other error
|
ErrorUnknown ///< Any other error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
System();
|
||||||
~System();
|
~System();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -372,7 +370,7 @@ private:
|
|||||||
std::shared_ptr<Frontend::SoftwareKeyboard> registered_swkbd;
|
std::shared_ptr<Frontend::SoftwareKeyboard> registered_swkbd;
|
||||||
|
|
||||||
/// Cheats manager
|
/// Cheats manager
|
||||||
std::unique_ptr<Cheats::CheatEngine> cheat_engine;
|
Cheats::CheatEngine cheat_engine;
|
||||||
|
|
||||||
/// Video dumper backend
|
/// Video dumper backend
|
||||||
std::shared_ptr<VideoDumper::Backend> video_dumper;
|
std::shared_ptr<VideoDumper::Backend> video_dumper;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
@ -892,7 +893,7 @@ std::string FormatDuration(s64 duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatDefaultValue(const AVOption* option,
|
std::string FormatDefaultValue(const AVOption* option,
|
||||||
const std::vector<OptionInfo::NamedConstant>& named_constants) {
|
std::span<const OptionInfo::NamedConstant> named_constants) {
|
||||||
// The following is taken and modified from libavutil code (opt.c)
|
// The following is taken and modified from libavutil code (opt.c)
|
||||||
switch (option->type) {
|
switch (option->type) {
|
||||||
case AV_OPT_TYPE_BOOL: {
|
case AV_OPT_TYPE_BOOL: {
|
||||||
|
@ -296,11 +296,10 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Pat
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data,
|
void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, std::span<const u8> icon) {
|
||||||
std::size_t icon_size) {
|
|
||||||
std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
|
std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
|
||||||
FileUtil::IOFile icon_file(game_path + "icon", "wb");
|
FileUtil::IOFile icon_file(game_path + "icon", "wb");
|
||||||
icon_file.WriteBytes(icon_data, icon_size);
|
icon_file.WriteBytes(icon.data(), icon.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/serialization/export.hpp>
|
#include <boost/serialization/export.hpp>
|
||||||
#include <boost/serialization/string.hpp>
|
#include <boost/serialization/string.hpp>
|
||||||
@ -38,7 +39,7 @@ public:
|
|||||||
* @param icon_data Binary data of the icon
|
* @param icon_data Binary data of the icon
|
||||||
* @param icon_size Size of the icon data
|
* @param icon_size Size of the icon data
|
||||||
*/
|
*/
|
||||||
void WriteIcon(const Path& path, const u8* icon_data, std::size_t icon_size);
|
void WriteIcon(const Path& path, std::span<const u8> icon);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData
|
bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData
|
||||||
|
@ -249,7 +249,7 @@ ResultVal<std::size_t> NCCHFile::Read(const u64 offset, const std::size_t length
|
|||||||
|
|
||||||
std::size_t available_size = static_cast<std::size_t>(file_buffer.size() - offset);
|
std::size_t available_size = static_cast<std::size_t>(file_buffer.size() - offset);
|
||||||
std::size_t copy_size = std::min(length, available_size);
|
std::size_t copy_size = std::min(length, available_size);
|
||||||
memcpy(buffer, file_buffer.data() + offset, copy_size);
|
std::memcpy(buffer, file_buffer.data() + offset, copy_size);
|
||||||
|
|
||||||
return copy_size;
|
return copy_size;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ Loader::ResultStatus CIAContainer::Load(const std::string& filepath) {
|
|||||||
return Loader::ResultStatus::Success;
|
return Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::Load(const std::vector<u8>& file_data) {
|
Loader::ResultStatus CIAContainer::Load(std::span<const u8> file_data) {
|
||||||
Loader::ResultStatus result = LoadHeader(file_data);
|
Loader::ResultStatus result = LoadHeader(file_data);
|
||||||
if (result != Loader::ResultStatus::Success)
|
if (result != Loader::ResultStatus::Success)
|
||||||
return result;
|
return result;
|
||||||
@ -133,30 +133,29 @@ Loader::ResultStatus CIAContainer::Load(const std::vector<u8>& file_data) {
|
|||||||
return Loader::ResultStatus::Success;
|
return Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::LoadHeader(const std::vector<u8>& header_data,
|
Loader::ResultStatus CIAContainer::LoadHeader(std::span<const u8> header_data, std::size_t offset) {
|
||||||
std::size_t offset) {
|
if (header_data.size() - offset < sizeof(Header)) {
|
||||||
if (header_data.size() - offset < sizeof(Header))
|
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(&cia_header, header_data.data(), sizeof(Header));
|
std::memcpy(&cia_header, header_data.data(), sizeof(Header));
|
||||||
|
|
||||||
return Loader::ResultStatus::Success;
|
return Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::LoadTicket(const std::vector<u8>& ticket_data,
|
Loader::ResultStatus CIAContainer::LoadTicket(std::span<const u8> ticket_data, std::size_t offset) {
|
||||||
std::size_t offset) {
|
|
||||||
return cia_ticket.Load(ticket_data, offset);
|
return cia_ticket.Load(ticket_data, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::LoadTitleMetadata(const std::vector<u8>& tmd_data,
|
Loader::ResultStatus CIAContainer::LoadTitleMetadata(std::span<const u8> tmd_data,
|
||||||
std::size_t offset) {
|
std::size_t offset) {
|
||||||
return cia_tmd.Load(tmd_data, offset);
|
return cia_tmd.Load(tmd_data, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus CIAContainer::LoadMetadata(const std::vector<u8>& meta_data,
|
Loader::ResultStatus CIAContainer::LoadMetadata(std::span<const u8> meta_data, std::size_t offset) {
|
||||||
std::size_t offset) {
|
if (meta_data.size() - offset < sizeof(Metadata)) {
|
||||||
if (meta_data.size() - offset < sizeof(Metadata))
|
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
std::memcpy(&cia_metadata, meta_data.data(), sizeof(Metadata));
|
std::memcpy(&cia_metadata, meta_data.data(), sizeof(Metadata));
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/file_sys/ticket.h"
|
#include "core/file_sys/ticket.h"
|
||||||
@ -39,13 +39,13 @@ public:
|
|||||||
// Load whole CIAs outright
|
// Load whole CIAs outright
|
||||||
Loader::ResultStatus Load(const FileBackend& backend);
|
Loader::ResultStatus Load(const FileBackend& backend);
|
||||||
Loader::ResultStatus Load(const std::string& filepath);
|
Loader::ResultStatus Load(const std::string& filepath);
|
||||||
Loader::ResultStatus Load(const std::vector<u8>& header_data);
|
Loader::ResultStatus Load(std::span<const u8> header_data);
|
||||||
|
|
||||||
// Load parts of CIAs (for CIAs streamed in)
|
// Load parts of CIAs (for CIAs streamed in)
|
||||||
Loader::ResultStatus LoadHeader(const std::vector<u8>& header_data, std::size_t offset = 0);
|
Loader::ResultStatus LoadHeader(std::span<const u8> header_data, std::size_t offset = 0);
|
||||||
Loader::ResultStatus LoadTicket(const std::vector<u8>& ticket_data, std::size_t offset = 0);
|
Loader::ResultStatus LoadTicket(std::span<const u8> ticket_data, std::size_t offset = 0);
|
||||||
Loader::ResultStatus LoadTitleMetadata(const std::vector<u8>& tmd_data, std::size_t offset = 0);
|
Loader::ResultStatus LoadTitleMetadata(std::span<const u8> tmd_data, std::size_t offset = 0);
|
||||||
Loader::ResultStatus LoadMetadata(const std::vector<u8>& meta_data, std::size_t offset = 0);
|
Loader::ResultStatus LoadMetadata(std::span<const u8> meta_data, std::size_t offset = 0);
|
||||||
|
|
||||||
const Ticket& GetTicket() const;
|
const Ticket& GetTicket() const;
|
||||||
const TitleMetadata& GetTitleMetadata() const;
|
const TitleMetadata& GetTitleMetadata() const;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <cryptopp/aes.h>
|
#include <cryptopp/aes.h>
|
||||||
#include <cryptopp/modes.h>
|
#include <cryptopp/modes.h>
|
||||||
#include <cryptopp/sha.h>
|
#include <cryptopp/sha.h>
|
||||||
@ -36,10 +37,10 @@ u64 GetModId(u64 program_id) {
|
|||||||
* @param size Size of compressed buffer
|
* @param size Size of compressed buffer
|
||||||
* @return Size of decompressed buffer
|
* @return Size of decompressed buffer
|
||||||
*/
|
*/
|
||||||
static u32 LZSS_GetDecompressedSize(const u8* buffer, u32 size) {
|
static std::size_t LZSS_GetDecompressedSize(std::span<const u8> buffer) {
|
||||||
u32 offset_size;
|
u32 offset_size;
|
||||||
std::memcpy(&offset_size, buffer + size - sizeof(u32), sizeof(u32));
|
std::memcpy(&offset_size, buffer.data() + buffer.size() - sizeof(u32), sizeof(u32));
|
||||||
return offset_size + size;
|
return offset_size + buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,19 +51,18 @@ static u32 LZSS_GetDecompressedSize(const u8* buffer, u32 size) {
|
|||||||
* @param decompressed_size Size of decompressed buffer
|
* @param decompressed_size Size of decompressed buffer
|
||||||
* @return True on success, otherwise false
|
* @return True on success, otherwise false
|
||||||
*/
|
*/
|
||||||
static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decompressed,
|
static bool LZSS_Decompress(std::span<const u8> compressed, std::span<u8> decompressed) {
|
||||||
u32 decompressed_size) {
|
const u8* footer = compressed.data() + compressed.size() - 8;
|
||||||
const u8* footer = compressed + compressed_size - 8;
|
|
||||||
|
|
||||||
u32 buffer_top_and_bottom;
|
u32 buffer_top_and_bottom;
|
||||||
std::memcpy(&buffer_top_and_bottom, footer, sizeof(u32));
|
std::memcpy(&buffer_top_and_bottom, footer, sizeof(u32));
|
||||||
|
|
||||||
u32 out = decompressed_size;
|
size_t out = decompressed.size();
|
||||||
u32 index = compressed_size - ((buffer_top_and_bottom >> 24) & 0xFF);
|
size_t index = compressed.size() - ((buffer_top_and_bottom >> 24) & 0xFF);
|
||||||
u32 stop_index = compressed_size - (buffer_top_and_bottom & 0xFFFFFF);
|
size_t stop_index = compressed.size() - (buffer_top_and_bottom & 0xFFFFFF);
|
||||||
|
|
||||||
memset(decompressed, 0, decompressed_size);
|
std::memset(decompressed.data(), 0, decompressed.size());
|
||||||
memcpy(decompressed, compressed, compressed_size);
|
std::memcpy(decompressed.data(), compressed.data(), compressed.size());
|
||||||
|
|
||||||
while (index > stop_index) {
|
while (index > stop_index) {
|
||||||
u8 control = compressed[--index];
|
u8 control = compressed[--index];
|
||||||
@ -92,7 +92,7 @@ static bool LZSS_Decompress(const u8* compressed, u32 compressed_size, u8* decom
|
|||||||
|
|
||||||
for (unsigned j = 0; j < segment_size; j++) {
|
for (unsigned j = 0; j < segment_size; j++) {
|
||||||
// Check if compression is out of bounds
|
// Check if compression is out of bounds
|
||||||
if (out + segment_offset >= decompressed_size)
|
if (out + segment_offset >= decompressed.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
u8 data = decompressed[out + segment_offset];
|
u8 data = decompressed[out + segment_offset];
|
||||||
@ -538,14 +538,9 @@ Loader::ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vect
|
|||||||
|
|
||||||
if (strcmp(section.name, ".code") == 0 && is_compressed) {
|
if (strcmp(section.name, ".code") == 0 && is_compressed) {
|
||||||
// Section is compressed, read compressed .code section...
|
// Section is compressed, read compressed .code section...
|
||||||
std::unique_ptr<u8[]> temp_buffer;
|
std::vector<u8> temp_buffer(section.size);
|
||||||
try {
|
if (exefs_file.ReadBytes(temp_buffer.data(), temp_buffer.size()) !=
|
||||||
temp_buffer.reset(new u8[section.size]);
|
temp_buffer.size())
|
||||||
} catch (std::bad_alloc&) {
|
|
||||||
return Loader::ResultStatus::ErrorMemoryAllocationFailed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exefs_file.ReadBytes(&temp_buffer[0], section.size) != section.size)
|
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted) {
|
||||||
@ -553,11 +548,10 @@ Loader::ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vect
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decompress .code section...
|
// Decompress .code section...
|
||||||
u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0], section.size);
|
buffer.resize(LZSS_GetDecompressedSize(temp_buffer));
|
||||||
buffer.resize(decompressed_size);
|
if (!LZSS_Decompress(temp_buffer, buffer)) {
|
||||||
if (!LZSS_Decompress(&temp_buffer[0], section.size, buffer.data(),
|
|
||||||
decompressed_size))
|
|
||||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
return Loader::ResultStatus::ErrorInvalidFormat;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Section is uncompressed...
|
// Section is uncompressed...
|
||||||
buffer.resize(section.size);
|
buffer.resize(section.size);
|
||||||
|
@ -142,7 +142,7 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Load(
|
|||||||
}
|
}
|
||||||
exe_load_func.push_back(instruction);
|
exe_load_func.push_back(instruction);
|
||||||
}
|
}
|
||||||
memcpy(exe_load_args, header.infos.builtin_load_exe_args,
|
std::memcpy(exe_load_args, header.infos.builtin_load_exe_args,
|
||||||
sizeof(_3gx_Infos::builtin_load_exe_args));
|
sizeof(_3gx_Infos::builtin_load_exe_args));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map(
|
|||||||
plugin_header.plgldr_reply = plg_context.plg_reply;
|
plugin_header.plgldr_reply = plg_context.plg_reply;
|
||||||
plugin_header.is_default_plugin = plg_context.is_default_path;
|
plugin_header.is_default_plugin = plg_context.is_default_path;
|
||||||
if (plg_context.use_user_load_parameters) {
|
if (plg_context.use_user_load_parameters) {
|
||||||
memcpy(plugin_header.config, plg_context.user_load_parameters.config,
|
std::memcpy(plugin_header.config, plg_context.user_load_parameters.config,
|
||||||
sizeof(PluginHeader::config));
|
sizeof(PluginHeader::config));
|
||||||
}
|
}
|
||||||
kernel.memory.WriteBlock(process, _3GX_exe_load_addr, &plugin_header, sizeof(PluginHeader));
|
kernel.memory.WriteBlock(process, _3GX_exe_load_addr, &plugin_header, sizeof(PluginHeader));
|
||||||
@ -286,8 +286,7 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
||||||
u32 memory_offset,
|
u32 memory_offset, std::span<const u32> exe_load_func,
|
||||||
const std::vector<u32>& exe_load_func,
|
|
||||||
const u32_le* exe_load_args, u32 checksum_size,
|
const u32_le* exe_load_args, u32 checksum_size,
|
||||||
u32 exe_checksum, bool no_flash) {
|
u32 exe_checksum, bool no_flash) {
|
||||||
|
|
||||||
@ -296,7 +295,8 @@ void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::K
|
|||||||
sizeof(u32) * 2);
|
sizeof(u32) * 2);
|
||||||
|
|
||||||
std::array<u32_le, g_plugin_loader_bootloader.size() / sizeof(u32)> bootloader;
|
std::array<u32_le, g_plugin_loader_bootloader.size() / sizeof(u32)> bootloader;
|
||||||
memcpy(bootloader.data(), g_plugin_loader_bootloader.data(), g_plugin_loader_bootloader.size());
|
std::memcpy(bootloader.data(), g_plugin_loader_bootloader.data(),
|
||||||
|
g_plugin_loader_bootloader.size());
|
||||||
|
|
||||||
for (auto it = bootloader.begin(); it < bootloader.end(); it++) {
|
for (auto it = bootloader.begin(); it < bootloader.end(); it++) {
|
||||||
switch (static_cast<u32>(*it)) {
|
switch (static_cast<u32>(*it)) {
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <core/file_sys/archive_backend.h>
|
#include <span>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
|
#include "core/file_sys/archive_backend.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/plgldr/plgldr.h"
|
#include "core/hle/service/plgldr/plgldr.h"
|
||||||
|
|
||||||
@ -71,7 +72,7 @@ private:
|
|||||||
|
|
||||||
static constexpr size_t bootloader_memory_size = 0x1000;
|
static constexpr size_t bootloader_memory_size = 0x1000;
|
||||||
static void MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
static void MapBootloader(Kernel::Process& process, Kernel::KernelSystem& kernel,
|
||||||
u32 memory_offset, const std::vector<u32>& exe_load_func,
|
u32 memory_offset, std::span<const u32> exe_load_func,
|
||||||
const u32_le* exe_load_args, u32 checksum_size, u32 exe_checksum,
|
const u32_le* exe_load_args, u32 checksum_size, u32 exe_checksum,
|
||||||
bool no_flash);
|
bool no_flash);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
Loader::ResultStatus Ticket::Load(const std::vector<u8> file_data, std::size_t offset) {
|
Loader::ResultStatus Ticket::Load(std::span<const u8> file_data, std::size_t offset) {
|
||||||
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
||||||
if (total_size < sizeof(u32))
|
if (total_size < sizeof(u32))
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
@ -35,8 +35,8 @@ Loader::ResultStatus Ticket::Load(const std::vector<u8> file_data, std::size_t o
|
|||||||
|
|
||||||
// Read signature + ticket body
|
// Read signature + ticket body
|
||||||
ticket_signature.resize(signature_size);
|
ticket_signature.resize(signature_size);
|
||||||
memcpy(ticket_signature.data(), &file_data[offset + sizeof(u32)], signature_size);
|
std::memcpy(ticket_signature.data(), &file_data[offset + sizeof(u32)], signature_size);
|
||||||
memcpy(&ticket_body, &file_data[offset + body_start], sizeof(Body));
|
std::memcpy(&ticket_body, &file_data[offset + body_start], sizeof(Body));
|
||||||
|
|
||||||
return Loader::ResultStatus::Success;
|
return Loader::ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
@ -47,7 +48,7 @@ public:
|
|||||||
static_assert(sizeof(Body) == 0x210, "Ticket body structure size is wrong");
|
static_assert(sizeof(Body) == 0x210, "Ticket body structure size is wrong");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
Loader::ResultStatus Load(const std::vector<u8> file_data, std::size_t offset = 0);
|
Loader::ResultStatus Load(std::span<const u8> file_data, std::size_t offset = 0);
|
||||||
std::optional<std::array<u8, 16>> GetTitleKey() const;
|
std::optional<std::array<u8, 16>> GetTitleKey() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -29,12 +29,13 @@ Loader::ResultStatus TitleMetadata::Load(const std::string& file_path) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ResultStatus TitleMetadata::Load(const std::vector<u8>& file_data, std::size_t offset) {
|
Loader::ResultStatus TitleMetadata::Load(std::span<const u8> file_data, std::size_t offset) {
|
||||||
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
std::size_t total_size = static_cast<std::size_t>(file_data.size() - offset);
|
||||||
if (total_size < sizeof(u32_be))
|
if (total_size < sizeof(u32_be)) {
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(&signature_type, &file_data[offset], sizeof(u32_be));
|
std::memcpy(&signature_type, &file_data[offset], sizeof(u32_be));
|
||||||
|
|
||||||
// Signature lengths are variable, and the body follows the signature
|
// Signature lengths are variable, and the body follows the signature
|
||||||
u32 signature_size = GetSignatureSize(signature_type);
|
u32 signature_size = GetSignatureSize(signature_type);
|
||||||
@ -46,13 +47,14 @@ Loader::ResultStatus TitleMetadata::Load(const std::vector<u8>& file_data, std::
|
|||||||
std::size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
|
std::size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
|
||||||
std::size_t body_end = body_start + sizeof(Body);
|
std::size_t body_end = body_start + sizeof(Body);
|
||||||
|
|
||||||
if (total_size < body_end)
|
if (total_size < body_end) {
|
||||||
return Loader::ResultStatus::Error;
|
return Loader::ResultStatus::Error;
|
||||||
|
}
|
||||||
|
|
||||||
// Read signature + TMD body, then load the amount of ContentChunks specified
|
// Read signature + TMD body, then load the amount of ContentChunks specified
|
||||||
tmd_signature.resize(signature_size);
|
tmd_signature.resize(signature_size);
|
||||||
memcpy(tmd_signature.data(), &file_data[offset + sizeof(u32_be)], signature_size);
|
std::memcpy(tmd_signature.data(), &file_data[offset + sizeof(u32_be)], signature_size);
|
||||||
memcpy(&tmd_body, &file_data[offset + body_start], sizeof(TitleMetadata::Body));
|
std::memcpy(&tmd_body, &file_data[offset + body_start], sizeof(TitleMetadata::Body));
|
||||||
|
|
||||||
std::size_t expected_size =
|
std::size_t expected_size =
|
||||||
body_start + sizeof(Body) + static_cast<u16>(tmd_body.content_count) * sizeof(ContentChunk);
|
body_start + sizeof(Body) + static_cast<u16>(tmd_body.content_count) * sizeof(ContentChunk);
|
||||||
@ -65,7 +67,7 @@ Loader::ResultStatus TitleMetadata::Load(const std::vector<u8>& file_data, std::
|
|||||||
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
||||||
ContentChunk chunk;
|
ContentChunk chunk;
|
||||||
|
|
||||||
memcpy(&chunk, &file_data[offset + body_end + (i * sizeof(ContentChunk))],
|
std::memcpy(&chunk, &file_data[offset + body_end + (i * sizeof(ContentChunk))],
|
||||||
sizeof(ContentChunk));
|
sizeof(ContentChunk));
|
||||||
tmd_chunks.push_back(chunk);
|
tmd_chunks.push_back(chunk);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@ -82,7 +83,7 @@ public:
|
|||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
Loader::ResultStatus Load(const std::string& file_path);
|
Loader::ResultStatus Load(const std::string& file_path);
|
||||||
Loader::ResultStatus Load(const std::vector<u8>& file_data, std::size_t offset = 0);
|
Loader::ResultStatus Load(std::span<const u8> file_data, std::size_t offset = 0);
|
||||||
Loader::ResultStatus Save(const std::string& file_path);
|
Loader::ResultStatus Save(const std::string& file_path);
|
||||||
|
|
||||||
u64 GetTitleID() const;
|
u64 GetTitleID() const;
|
||||||
|
@ -491,7 +491,7 @@ void SendReply(const char* reply) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(command_buffer, 0, sizeof(command_buffer));
|
std::memset(command_buffer, 0, sizeof(command_buffer));
|
||||||
|
|
||||||
command_length = static_cast<u32>(strlen(reply));
|
command_length = static_cast<u32>(strlen(reply));
|
||||||
if (command_length + 4 > sizeof(command_buffer)) {
|
if (command_length + 4 > sizeof(command_buffer)) {
|
||||||
@ -499,7 +499,7 @@ void SendReply(const char* reply) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(command_buffer + 1, reply, command_length);
|
std::memcpy(command_buffer + 1, reply, command_length);
|
||||||
|
|
||||||
u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
|
u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
|
||||||
command_buffer[0] = GDB_STUB_START;
|
command_buffer[0] = GDB_STUB_START;
|
||||||
@ -639,7 +639,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
|
|||||||
/// Read command from gdb client.
|
/// Read command from gdb client.
|
||||||
static void ReadCommand() {
|
static void ReadCommand() {
|
||||||
command_length = 0;
|
command_length = 0;
|
||||||
memset(command_buffer, 0, sizeof(command_buffer));
|
std::memset(command_buffer, 0, sizeof(command_buffer));
|
||||||
|
|
||||||
u8 c = ReadByte();
|
u8 c = ReadByte();
|
||||||
if (c == GDB_STUB_ACK) {
|
if (c == GDB_STUB_ACK) {
|
||||||
@ -711,7 +711,7 @@ static bool IsDataAvailable() {
|
|||||||
/// Send requested register to gdb client.
|
/// Send requested register to gdb client.
|
||||||
static void ReadRegister() {
|
static void ReadRegister() {
|
||||||
static u8 reply[64];
|
static u8 reply[64];
|
||||||
memset(reply, 0, sizeof(reply));
|
std::memset(reply, 0, sizeof(reply));
|
||||||
|
|
||||||
u32 id = HexCharToValue(command_buffer[1]);
|
u32 id = HexCharToValue(command_buffer[1]);
|
||||||
if (command_buffer[2] != '\0') {
|
if (command_buffer[2] != '\0') {
|
||||||
@ -737,7 +737,7 @@ static void ReadRegister() {
|
|||||||
/// Send all registers to the gdb client.
|
/// Send all registers to the gdb client.
|
||||||
static void ReadRegisters() {
|
static void ReadRegisters() {
|
||||||
static u8 buffer[GDB_BUFFER_SIZE - 4];
|
static u8 buffer[GDB_BUFFER_SIZE - 4];
|
||||||
memset(buffer, 0, sizeof(buffer));
|
std::memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
u8* bufptr = buffer;
|
u8* bufptr = buffer;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ void HandleHioReply(const u8* const command_buffer, const u32 command_length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip 'F' header
|
// Skip 'F' header
|
||||||
auto* command_pos = command_buffer + 1;
|
const u8* command_pos = command_buffer + 1;
|
||||||
|
|
||||||
if (*command_pos == 0 || *command_pos == ',') {
|
if (*command_pos == 0 || *command_pos == ',') {
|
||||||
LOG_WARNING(Debug_GDBStub, "bad HIO packet format position 0: {}", *command_pos);
|
LOG_WARNING(Debug_GDBStub, "bad HIO packet format position 0: {}", *command_pos);
|
||||||
|
@ -23,7 +23,7 @@ ResultCode ErrEula::ReceiveParameterImpl(const Service::APT::MessageParameter& p
|
|||||||
Service::APT::CaptureBufferInfo capture_info;
|
Service::APT::CaptureBufferInfo capture_info;
|
||||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||||
|
|
||||||
memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
std::memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
||||||
|
|
||||||
// TODO: allocated memory never released
|
// TODO: allocated memory never released
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
|
@ -31,7 +31,7 @@ ResultCode MiiSelector::ReceiveParameterImpl(const Service::APT::MessageParamete
|
|||||||
Service::APT::CaptureBufferInfo capture_info;
|
Service::APT::CaptureBufferInfo capture_info;
|
||||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||||
|
|
||||||
memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
std::memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
||||||
|
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
@ -54,7 +54,7 @@ ResultCode MiiSelector::Start(const Service::APT::MessageParameter& parameter) {
|
|||||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
||||||
"The size of the parameter (MiiConfig) is wrong");
|
"The size of the parameter (MiiConfig) is wrong");
|
||||||
|
|
||||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
std::memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||||
|
|
||||||
using namespace Frontend;
|
using namespace Frontend;
|
||||||
frontend_applet = Core::System::GetInstance().GetMiiSelector();
|
frontend_applet = Core::System::GetInstance().GetMiiSelector();
|
||||||
|
@ -23,7 +23,7 @@ ResultCode Mint::ReceiveParameterImpl(const Service::APT::MessageParameter& para
|
|||||||
Service::APT::CaptureBufferInfo capture_info;
|
Service::APT::CaptureBufferInfo capture_info;
|
||||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||||
|
|
||||||
memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
std::memcpy(&capture_info, parameter.buffer.data(), sizeof(capture_info));
|
||||||
|
|
||||||
// TODO: allocated memory never released
|
// TODO: allocated memory never released
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
|
@ -93,7 +93,7 @@ ResultCode SoftwareKeyboard::Start(Service::APT::MessageParameter const& paramet
|
|||||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
||||||
"The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
"The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
||||||
|
|
||||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
std::memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||||
text_memory = std::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
text_memory = std::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
||||||
|
|
||||||
DrawScreenKeyboard();
|
DrawScreenKeyboard();
|
||||||
@ -115,7 +115,7 @@ void SoftwareKeyboard::Update() {
|
|||||||
const KeyboardData& data = frontend_applet->ReceiveData();
|
const KeyboardData& data = frontend_applet->ReceiveData();
|
||||||
std::u16string text = Common::UTF8ToUTF16(data.text);
|
std::u16string text = Common::UTF8ToUTF16(data.text);
|
||||||
// Include a null terminator
|
// Include a null terminator
|
||||||
memcpy(text_memory->GetPointer(), text.c_str(), (text.length() + 1) * sizeof(char16_t));
|
std::memcpy(text_memory->GetPointer(), text.c_str(), (text.length() + 1) * sizeof(char16_t));
|
||||||
switch (config.num_buttons_m1) {
|
switch (config.num_buttons_m1) {
|
||||||
case SoftwareKeyboardButtonConfig::SingleButton:
|
case SoftwareKeyboardButtonConfig::SingleButton:
|
||||||
config.return_code = SoftwareKeyboardResult::D0Click;
|
config.return_code = SoftwareKeyboardResult::D0Click;
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
void Skip(unsigned size_in_words, bool set_to_null) {
|
void Skip(unsigned size_in_words, bool set_to_null) {
|
||||||
if (set_to_null)
|
if (set_to_null)
|
||||||
memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
std::memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
|
||||||
index += size_in_words;
|
index += size_in_words;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -304,13 +304,13 @@ MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process
|
|||||||
perms = desc.perms;
|
perms = desc.perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappedBuffer::Read(void* dest_buffer, std::size_t offset, std::size_t size) const {
|
void MappedBuffer::Read(void* dest_buffer, std::size_t offset, std::size_t size) {
|
||||||
ASSERT(perms & IPC::R);
|
ASSERT(perms & IPC::R);
|
||||||
ASSERT(offset + size <= this->size);
|
ASSERT(offset + size <= this->size);
|
||||||
memory->ReadBlock(*process, address + static_cast<VAddr>(offset), dest_buffer, size);
|
memory->ReadBlock(*process, address + static_cast<VAddr>(offset), dest_buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t size) const {
|
void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t size) {
|
||||||
ASSERT(perms & IPC::W);
|
ASSERT(perms & IPC::W);
|
||||||
ASSERT(offset + size <= this->size);
|
ASSERT(offset + size <= this->size);
|
||||||
memory->WriteBlock(*process, address + static_cast<VAddr>(offset), src_buffer, size);
|
memory->WriteBlock(*process, address + static_cast<VAddr>(offset), src_buffer, size);
|
||||||
|
@ -129,16 +129,14 @@ public:
|
|||||||
MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
|
MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
|
||||||
VAddr address, u32 id);
|
VAddr address, u32 id);
|
||||||
|
|
||||||
// Interface for service
|
// interface for service
|
||||||
void Read(void* dest_buffer, std::size_t offset, std::size_t size) const;
|
void Read(void* dest_buffer, std::size_t offset, std::size_t size);
|
||||||
|
void Write(const void* src_buffer, std::size_t offset, std::size_t size);
|
||||||
void Write(const void* src_buffer, std::size_t offset, std::size_t size) const;
|
|
||||||
|
|
||||||
std::size_t GetSize() const {
|
std::size_t GetSize() const {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface for ipc helper
|
// interface for ipc helper
|
||||||
u32 GenerateDescriptor() const {
|
u32 GenerateDescriptor() const {
|
||||||
return IPC::MappedBufferDesc(size, perms);
|
return IPC::MappedBufferDesc(size, perms);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -230,7 +231,7 @@ public:
|
|||||||
/// Retrieves a process from the current list of processes.
|
/// Retrieves a process from the current list of processes.
|
||||||
std::shared_ptr<Process> GetProcessById(u32 process_id) const;
|
std::shared_ptr<Process> GetProcessById(u32 process_id) const;
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<Process>>& GetProcessList() const {
|
std::span<const std::shared_ptr<Process>> GetProcessList() const {
|
||||||
return process_list;
|
return process_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2015 Citra Emulator Project
|
// Copyright 2015 Citra Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
#pragma optimize("", off)
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <boost/serialization/array.hpp>
|
#include <boost/serialization/array.hpp>
|
||||||
|
@ -543,13 +543,15 @@ void SVC::ExitProcess() {
|
|||||||
current_process->status = ProcessStatus::Exited;
|
current_process->status = ProcessStatus::Exited;
|
||||||
|
|
||||||
// Stop all the process threads that are currently waiting for objects.
|
// Stop all the process threads that are currently waiting for objects.
|
||||||
auto& thread_list = kernel.GetCurrentThreadManager().GetThreadList();
|
const auto thread_list = kernel.GetCurrentThreadManager().GetThreadList();
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process.lock() != current_process)
|
if (thread->owner_process.lock() != current_process) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (thread.get() == kernel.GetCurrentThreadManager().GetCurrentThread())
|
if (thread.get() == kernel.GetCurrentThreadManager().GetCurrentThread()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(Subv): When are the other running/ready threads terminated?
|
// TODO(Subv): When are the other running/ready threads terminated?
|
||||||
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
|
||||||
@ -695,7 +697,7 @@ ResultCode SVC::OpenThread(Handle* out_handle, Handle process_handle, u32 thread
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) {
|
for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) {
|
||||||
auto& thread_list = kernel.GetThreadManager(core_id).GetThreadList();
|
const auto thread_list = kernel.GetThreadManager(core_id).GetThreadList();
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) {
|
if (thread->owner_process.lock() == process && thread.get()->thread_id == thread_id) {
|
||||||
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(thread);
|
auto result_handle = kernel.GetCurrentProcess()->handle_table.Create(thread);
|
||||||
@ -2092,7 +2094,7 @@ ResultCode SVC::ControlProcess(Handle process_handle, u32 process_OP, u32 varg2,
|
|||||||
}
|
}
|
||||||
case ControlProcessOP::PROCESSOP_SCHEDULE_THREADS_WITHOUT_TLS_MAGIC: {
|
case ControlProcessOP::PROCESSOP_SCHEDULE_THREADS_WITHOUT_TLS_MAGIC: {
|
||||||
for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) {
|
for (u32 core_id = 0; core_id < system.GetNumCores(); core_id++) {
|
||||||
auto& thread_list = kernel.GetThreadManager(core_id).GetThreadList();
|
const auto thread_list = kernel.GetThreadManager(core_id).GetThreadList();
|
||||||
for (auto& thread : thread_list) {
|
for (auto& thread : thread_list) {
|
||||||
if (thread->owner_process.lock() != process) {
|
if (thread->owner_process.lock() != process) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#pragma optimize("", off)
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -304,7 +304,7 @@ void ThreadManager::DebugThreadQueue() {
|
|||||||
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
|
* alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full).
|
||||||
*/
|
*/
|
||||||
static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
|
static std::tuple<std::size_t, std::size_t, bool> GetFreeThreadLocalSlot(
|
||||||
const std::vector<std::bitset<8>>& tls_slots) {
|
std::span<const std::bitset<8>> tls_slots) {
|
||||||
// Iterate over all the allocated pages, and try to find one where not all slots are used.
|
// Iterate over all the allocated pages, and try to find one where not all slots are used.
|
||||||
for (std::size_t page = 0; page < tls_slots.size(); ++page) {
|
for (std::size_t page = 0; page < tls_slots.size(); ++page) {
|
||||||
const auto& page_tls_slots = tls_slots[page];
|
const auto& page_tls_slots = tls_slots[page];
|
||||||
@ -527,7 +527,7 @@ ThreadManager::~ThreadManager() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<Thread>>& ThreadManager::GetThreadList() {
|
std::span<const std::shared_ptr<Thread>> ThreadManager::GetThreadList() {
|
||||||
return thread_list;
|
return thread_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -113,7 +114,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Get a const reference to the thread list for debug use
|
* Get a const reference to the thread list for debug use
|
||||||
*/
|
*/
|
||||||
const std::vector<std::shared_ptr<Thread>>& GetThreadList();
|
std::span<const std::shared_ptr<Thread>> GetThreadList();
|
||||||
|
|
||||||
void SetCPU(ARM_Interface& cpu_) {
|
void SetCPU(ARM_Interface& cpu_) {
|
||||||
cpu = &cpu_;
|
cpu = &cpu_;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <core/hle/lock.h>
|
#include "core/hle/lock.h"
|
||||||
|
|
||||||
namespace HLE {
|
namespace HLE {
|
||||||
std::recursive_mutex g_hle_lock;
|
std::recursive_mutex g_hle_lock;
|
||||||
|
@ -223,7 +223,7 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
|
|||||||
std::size_t buf_max_size =
|
std::size_t buf_max_size =
|
||||||
std::min(static_cast<std::size_t>(offset + length), FileSys::CIA_HEADER_SIZE);
|
std::min(static_cast<std::size_t>(offset + length), FileSys::CIA_HEADER_SIZE);
|
||||||
data.resize(buf_max_size);
|
data.resize(buf_max_size);
|
||||||
memcpy(data.data() + offset, buffer, buf_copy_size);
|
std::memcpy(data.data() + offset, buffer, buf_copy_size);
|
||||||
|
|
||||||
// We have enough data to load a CIA header and parse it.
|
// We have enough data to load a CIA header and parse it.
|
||||||
if (written >= FileSys::CIA_HEADER_SIZE) {
|
if (written >= FileSys::CIA_HEADER_SIZE) {
|
||||||
@ -248,7 +248,7 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
|
|||||||
buf_offset;
|
buf_offset;
|
||||||
std::size_t buf_max_size = std::min(offset + length, container.GetContentOffset());
|
std::size_t buf_max_size = std::min(offset + length, container.GetContentOffset());
|
||||||
data.resize(buf_max_size);
|
data.resize(buf_max_size);
|
||||||
memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size);
|
std::memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(shinyquagsire23): Write out .tik files to nand?
|
// TODO(shinyquagsire23): Write out .tik files to nand?
|
||||||
@ -850,7 +850,7 @@ void Module::Interface::GetProgramList(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.PushMappedBuffer(title_ids_output);
|
rb.PushMappedBuffer(title_ids_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list,
|
ResultCode GetTitleInfoFromList(std::span<const u64> title_id_list,
|
||||||
Service::FS::MediaType media_type,
|
Service::FS::MediaType media_type,
|
||||||
Kernel::MappedBuffer& title_info_out) {
|
Kernel::MappedBuffer& title_info_out) {
|
||||||
std::size_t write_offset = 0;
|
std::size_t write_offset = 0;
|
||||||
|
@ -134,7 +134,7 @@ void Module::APTInterface::Initialize(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
static u32 DecompressLZ11(const u8* in, u8* out) {
|
static u32 DecompressLZ11(const u8* in, u8* out) {
|
||||||
u32_le decompressed_size;
|
u32_le decompressed_size;
|
||||||
memcpy(&decompressed_size, in, sizeof(u32));
|
std::memcpy(&decompressed_size, in, sizeof(u32));
|
||||||
in += 4;
|
in += 4;
|
||||||
|
|
||||||
u8 type = decompressed_size & 0xFF;
|
u8 type = decompressed_size & 0xFF;
|
||||||
|
@ -12,7 +12,7 @@ void RelocateSharedFont(std::shared_ptr<Kernel::SharedMemory> shared_font, VAddr
|
|||||||
const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset);
|
const u8* cfnt_ptr = shared_font->GetPointer(SharedFontStartOffset);
|
||||||
|
|
||||||
CFNT cfnt;
|
CFNT cfnt;
|
||||||
memcpy(&cfnt, cfnt_ptr, sizeof(cfnt));
|
std::memcpy(&cfnt, cfnt_ptr, sizeof(cfnt));
|
||||||
|
|
||||||
u32 assumed_cmap_offset = 0;
|
u32 assumed_cmap_offset = 0;
|
||||||
u32 assumed_cwdh_offset = 0;
|
u32 assumed_cwdh_offset = 0;
|
||||||
@ -27,17 +27,17 @@ void RelocateSharedFont(std::shared_ptr<Kernel::SharedMemory> shared_font, VAddr
|
|||||||
const u8* data = shared_font->GetPointer(current_offset);
|
const u8* data = shared_font->GetPointer(current_offset);
|
||||||
|
|
||||||
SectionHeader section_header;
|
SectionHeader section_header;
|
||||||
memcpy(§ion_header, data, sizeof(section_header));
|
std::memcpy(§ion_header, data, sizeof(section_header));
|
||||||
|
|
||||||
if (first_cmap_offset == 0 && memcmp(section_header.magic, "CMAP", 4) == 0) {
|
if (first_cmap_offset == 0 && std::memcmp(section_header.magic, "CMAP", 4) == 0) {
|
||||||
first_cmap_offset = current_offset;
|
first_cmap_offset = current_offset;
|
||||||
} else if (first_cwdh_offset == 0 && memcmp(section_header.magic, "CWDH", 4) == 0) {
|
} else if (first_cwdh_offset == 0 && std::memcmp(section_header.magic, "CWDH", 4) == 0) {
|
||||||
first_cwdh_offset = current_offset;
|
first_cwdh_offset = current_offset;
|
||||||
} else if (first_tglp_offset == 0 && memcmp(section_header.magic, "TGLP", 4) == 0) {
|
} else if (first_tglp_offset == 0 && std::memcmp(section_header.magic, "TGLP", 4) == 0) {
|
||||||
first_tglp_offset = current_offset;
|
first_tglp_offset = current_offset;
|
||||||
} else if (memcmp(section_header.magic, "FINF", 4) == 0) {
|
} else if (std::memcmp(section_header.magic, "FINF", 4) == 0) {
|
||||||
BCFNT::FINF finf;
|
BCFNT::FINF finf;
|
||||||
memcpy(&finf, data, sizeof(finf));
|
std::memcpy(&finf, data, sizeof(finf));
|
||||||
|
|
||||||
assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader);
|
assumed_cmap_offset = finf.cmap_offset - sizeof(SectionHeader);
|
||||||
assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader);
|
assumed_cwdh_offset = finf.cwdh_offset - sizeof(SectionHeader);
|
||||||
@ -59,44 +59,44 @@ void RelocateSharedFont(std::shared_ptr<Kernel::SharedMemory> shared_font, VAddr
|
|||||||
u8* data = shared_font->GetPointer(current_offset);
|
u8* data = shared_font->GetPointer(current_offset);
|
||||||
|
|
||||||
SectionHeader section_header;
|
SectionHeader section_header;
|
||||||
memcpy(§ion_header, data, sizeof(section_header));
|
std::memcpy(§ion_header, data, sizeof(section_header));
|
||||||
|
|
||||||
if (memcmp(section_header.magic, "FINF", 4) == 0) {
|
if (std::memcmp(section_header.magic, "FINF", 4) == 0) {
|
||||||
BCFNT::FINF finf;
|
BCFNT::FINF finf;
|
||||||
memcpy(&finf, data, sizeof(finf));
|
std::memcpy(&finf, data, sizeof(finf));
|
||||||
|
|
||||||
// Relocate the offsets in the FINF section
|
// Relocate the offsets in the FINF section
|
||||||
finf.cmap_offset += offset;
|
finf.cmap_offset += offset;
|
||||||
finf.cwdh_offset += offset;
|
finf.cwdh_offset += offset;
|
||||||
finf.tglp_offset += offset;
|
finf.tglp_offset += offset;
|
||||||
|
|
||||||
memcpy(data, &finf, sizeof(finf));
|
std::memcpy(data, &finf, sizeof(finf));
|
||||||
} else if (memcmp(section_header.magic, "CMAP", 4) == 0) {
|
} else if (std::memcmp(section_header.magic, "CMAP", 4) == 0) {
|
||||||
BCFNT::CMAP cmap;
|
BCFNT::CMAP cmap;
|
||||||
memcpy(&cmap, data, sizeof(cmap));
|
std::memcpy(&cmap, data, sizeof(cmap));
|
||||||
|
|
||||||
// Relocate the offsets in the CMAP section
|
// Relocate the offsets in the CMAP section
|
||||||
if (cmap.next_cmap_offset != 0)
|
if (cmap.next_cmap_offset != 0)
|
||||||
cmap.next_cmap_offset += offset;
|
cmap.next_cmap_offset += offset;
|
||||||
|
|
||||||
memcpy(data, &cmap, sizeof(cmap));
|
std::memcpy(data, &cmap, sizeof(cmap));
|
||||||
} else if (memcmp(section_header.magic, "CWDH", 4) == 0) {
|
} else if (std::memcmp(section_header.magic, "CWDH", 4) == 0) {
|
||||||
BCFNT::CWDH cwdh;
|
BCFNT::CWDH cwdh;
|
||||||
memcpy(&cwdh, data, sizeof(cwdh));
|
std::memcpy(&cwdh, data, sizeof(cwdh));
|
||||||
|
|
||||||
// Relocate the offsets in the CWDH section
|
// Relocate the offsets in the CWDH section
|
||||||
if (cwdh.next_cwdh_offset != 0)
|
if (cwdh.next_cwdh_offset != 0)
|
||||||
cwdh.next_cwdh_offset += offset;
|
cwdh.next_cwdh_offset += offset;
|
||||||
|
|
||||||
memcpy(data, &cwdh, sizeof(cwdh));
|
std::memcpy(data, &cwdh, sizeof(cwdh));
|
||||||
} else if (memcmp(section_header.magic, "TGLP", 4) == 0) {
|
} else if (std::memcmp(section_header.magic, "TGLP", 4) == 0) {
|
||||||
BCFNT::TGLP tglp;
|
BCFNT::TGLP tglp;
|
||||||
memcpy(&tglp, data, sizeof(tglp));
|
std::memcpy(&tglp, data, sizeof(tglp));
|
||||||
|
|
||||||
// Relocate the offsets in the TGLP section
|
// Relocate the offsets in the TGLP section
|
||||||
tglp.sheet_data_offset += offset;
|
tglp.sheet_data_offset += offset;
|
||||||
|
|
||||||
memcpy(data, &tglp, sizeof(tglp));
|
std::memcpy(data, &tglp, sizeof(tglp));
|
||||||
}
|
}
|
||||||
|
|
||||||
current_offset += section_header.section_size;
|
current_offset += section_header.section_size;
|
||||||
|
@ -834,7 +834,7 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) {
|
|||||||
open_mode.check);
|
open_mode.check);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Module::EncodeBase64(const std::vector<u8>& in) const {
|
std::string Module::EncodeBase64(std::span<const u8> in) const {
|
||||||
using namespace CryptoPP;
|
using namespace CryptoPP;
|
||||||
using Name::EncodingLookupArray;
|
using Name::EncodingLookupArray;
|
||||||
using Name::InsertLineBreaks;
|
using Name::InsertLineBreaks;
|
||||||
@ -855,7 +855,7 @@ std::string Module::EncodeBase64(const std::vector<u8>& in) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id,
|
std::string Module::GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id,
|
||||||
const std::vector<u8>& msg_id) const {
|
std::span<const u8> msg_id) const {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CecDataPathType::MboxList:
|
case CecDataPathType::MboxList:
|
||||||
return "/CEC/MBoxList____";
|
return "/CEC/MBoxList____";
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "core/hle/kernel/event.h"
|
#include "core/hle/kernel/event.h"
|
||||||
@ -610,10 +611,11 @@ private:
|
|||||||
0x26, 0x00, 0x01, 0x00};
|
0x26, 0x00, 0x01, 0x00};
|
||||||
|
|
||||||
/// Encoding function used for the message id
|
/// Encoding function used for the message id
|
||||||
std::string EncodeBase64(const std::vector<u8>& in) const;
|
std::string EncodeBase64(std::span<const u8> in) const;
|
||||||
|
|
||||||
std::string GetCecDataPathTypeAsString(const CecDataPathType type, const u32 program_id,
|
std::string GetCecDataPathTypeAsString(
|
||||||
const std::vector<u8>& msg_id = std::vector<u8>()) const;
|
const CecDataPathType type, const u32 program_id,
|
||||||
|
std::span<const u8> msg_id = std::span<const u8>{}) const;
|
||||||
|
|
||||||
std::string GetCecCommandAsString(const CecCommand command) const;
|
std::string GetCecCommandAsString(const CecCommand command) const;
|
||||||
|
|
||||||
|
@ -285,8 +285,8 @@ void Module::Interface::GenHashConsoleUnique(Kernel::HLERequestContext& ctx) {
|
|||||||
std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash;
|
std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash;
|
||||||
CryptoPP::SHA256().CalculateDigest(hash.data(), buffer.data(), sizeof(buffer));
|
CryptoPP::SHA256().CalculateDigest(hash.data(), buffer.data(), sizeof(buffer));
|
||||||
u32 low, high;
|
u32 low, high;
|
||||||
memcpy(&low, &hash[hash.size() - 8], sizeof(u32));
|
std::memcpy(&low, &hash[hash.size() - 8], sizeof(u32));
|
||||||
memcpy(&high, &hash[hash.size() - 4], sizeof(u32));
|
std::memcpy(&high, &hash[hash.size() - 4], sizeof(u32));
|
||||||
rb.Push(low);
|
rb.Push(low);
|
||||||
rb.Push(high);
|
rb.Push(high);
|
||||||
} else {
|
} else {
|
||||||
@ -439,7 +439,7 @@ ResultVal<void*> Module::GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 f
|
|||||||
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
|
ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output) {
|
||||||
void* pointer = nullptr;
|
void* pointer = nullptr;
|
||||||
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
||||||
memcpy(output, pointer, size);
|
std::memcpy(output, pointer, size);
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -447,7 +447,7 @@ ResultCode Module::GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* ou
|
|||||||
ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
|
ResultCode Module::SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input) {
|
||||||
void* pointer = nullptr;
|
void* pointer = nullptr;
|
||||||
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
CASCADE_RESULT(pointer, GetConfigInfoBlockPointer(block_id, size, flag));
|
||||||
memcpy(pointer, input, size);
|
std::memcpy(pointer, input, size);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,10 +473,10 @@ ResultCode Module::CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const
|
|||||||
config->block_entries[config->total_entries].offset_or_data = offset;
|
config->block_entries[config->total_entries].offset_or_data = offset;
|
||||||
|
|
||||||
// Write the data at the new offset
|
// Write the data at the new offset
|
||||||
memcpy(&cfg_config_file_buffer[offset], data, size);
|
std::memcpy(&cfg_config_file_buffer[offset], data, size);
|
||||||
} else {
|
} else {
|
||||||
// The offset_or_data field in the header contains the data itself if it's 4 bytes or less
|
// The offset_or_data field in the header contains the data itself if it's 4 bytes or less
|
||||||
memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size);
|
std::memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
++config->total_entries;
|
++config->total_entries;
|
||||||
@ -721,7 +721,7 @@ Module::~Module() = default;
|
|||||||
|
|
||||||
/// Checks if the language is available in the chosen region, and returns a proper one
|
/// Checks if the language is available in the chosen region, and returns a proper one
|
||||||
static std::tuple<u32 /*region*/, SystemLanguage> AdjustLanguageInfoBlock(
|
static std::tuple<u32 /*region*/, SystemLanguage> AdjustLanguageInfoBlock(
|
||||||
const std::vector<u32>& region_code, SystemLanguage language) {
|
std::span<const u32> region_code, SystemLanguage language) {
|
||||||
static const std::array<std::vector<SystemLanguage>, 7> region_languages{{
|
static const std::array<std::vector<SystemLanguage>, 7> region_languages{{
|
||||||
// JPN
|
// JPN
|
||||||
{LANGUAGE_JP},
|
{LANGUAGE_JP},
|
||||||
@ -750,13 +750,14 @@ static std::tuple<u32 /*region*/, SystemLanguage> AdjustLanguageInfoBlock(
|
|||||||
}
|
}
|
||||||
// The language is not available in any available region, so default to the first region and
|
// The language is not available in any available region, so default to the first region and
|
||||||
// language
|
// language
|
||||||
u32 default_region = region_code[0];
|
const u32 default_region = region_code[0];
|
||||||
return {default_region, region_languages[default_region][0]};
|
return {default_region, region_languages[default_region][0]};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::SetPreferredRegionCodes(const std::vector<u32>& region_codes) {
|
void Module::SetPreferredRegionCodes(std::span<const u32> region_codes) {
|
||||||
const SystemLanguage current_language = GetSystemLanguage();
|
const SystemLanguage current_language = GetSystemLanguage();
|
||||||
auto [region, adjusted_language] = AdjustLanguageInfoBlock(region_codes, current_language);
|
const auto [region, adjusted_language] =
|
||||||
|
AdjustLanguageInfoBlock(region_codes, current_language);
|
||||||
|
|
||||||
preferred_region_code = region;
|
preferred_region_code = region;
|
||||||
LOG_INFO(Service_CFG, "Preferred region code set to {}", preferred_region_code);
|
LOG_INFO(Service_CFG, "Preferred region code set to {}", preferred_region_code);
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ public:
|
|||||||
* setting is auto.
|
* setting is auto.
|
||||||
* @param region_codes the preferred region codes to set
|
* @param region_codes the preferred region codes to set
|
||||||
*/
|
*/
|
||||||
void SetPreferredRegionCodes(const std::vector<u32>& region_codes);
|
void SetPreferredRegionCodes(std::span<const u32> region_codes);
|
||||||
|
|
||||||
// Utilities for frontend to set config data.
|
// Utilities for frontend to set config data.
|
||||||
// Note: UpdateConfigNANDSavegame should be called after making changes to config data.
|
// Note: UpdateConfigNANDSavegame should be called after making changes to config data.
|
||||||
|
@ -230,7 +230,7 @@ ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low,
|
ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low,
|
||||||
const std::vector<u8>& smdh_icon,
|
std::span<const u8> smdh_icon,
|
||||||
const FileSys::ArchiveFormatInfo& format_info,
|
const FileSys::ArchiveFormatInfo& format_info,
|
||||||
u64 program_id) {
|
u64 program_id) {
|
||||||
// Construct the binary path to the archive first
|
// Construct the binary path to the archive first
|
||||||
@ -247,10 +247,11 @@ ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32
|
|||||||
auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
|
auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
|
||||||
|
|
||||||
ResultCode result = ext_savedata->Format(path, format_info, program_id);
|
ResultCode result = ext_savedata->Format(path, format_info, program_id);
|
||||||
if (result.IsError())
|
if (result.IsError()) {
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ext_savedata->WriteIcon(path, smdh_icon.data(), smdh_icon.size());
|
ext_savedata->WriteIcon(path, smdh_icon);
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
|
||||||
#include <boost/serialization/unique_ptr.hpp>
|
#include <boost/serialization/unique_ptr.hpp>
|
||||||
#include <boost/serialization/unordered_map.hpp>
|
#include <boost/serialization/unordered_map.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@ -219,7 +219,7 @@ public:
|
|||||||
* @return ResultCode 0 on success or the corresponding code on error
|
* @return ResultCode 0 on success or the corresponding code on error
|
||||||
*/
|
*/
|
||||||
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
|
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low,
|
||||||
const std::vector<u8>& smdh_icon,
|
std::span<const u8> smdh_icon,
|
||||||
const FileSys::ArchiveFormatInfo& format_info, u64 program_id);
|
const FileSys::ArchiveFormatInfo& format_info, u64 program_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/archives.h"
|
#include "common/archives.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
@ -142,7 +143,7 @@ static void WriteSingleHWReg(u32 base_address, u32 data) {
|
|||||||
* @param data A vector containing the source data
|
* @param data A vector containing the source data
|
||||||
* @return RESULT_SUCCESS if the parameters are valid, error code otherwise
|
* @return RESULT_SUCCESS if the parameters are valid, error code otherwise
|
||||||
*/
|
*/
|
||||||
static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const std::vector<u8>& data) {
|
static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, std::span<const u8> data) {
|
||||||
// This magic number is verified to be done by the gsp module
|
// This magic number is verified to be done by the gsp module
|
||||||
const u32 max_size_in_bytes = 0x80;
|
const u32 max_size_in_bytes = 0x80;
|
||||||
|
|
||||||
@ -185,8 +186,8 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const std::ve
|
|||||||
* @param masks A vector containing the masks
|
* @param masks A vector containing the masks
|
||||||
* @return RESULT_SUCCESS if the parameters are valid, error code otherwise
|
* @return RESULT_SUCCESS if the parameters are valid, error code otherwise
|
||||||
*/
|
*/
|
||||||
static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes,
|
static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, std::span<const u8> data,
|
||||||
const std::vector<u8>& data, const std::vector<u8>& masks) {
|
std::span<const u8> masks) {
|
||||||
// This magic number is verified to be done by the gsp module
|
// This magic number is verified to be done by the gsp module
|
||||||
const u32 max_size_in_bytes = 0x80;
|
const u32 max_size_in_bytes = 0x80;
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ void ExtraHID::OnDisconnect() {
|
|||||||
timing.UnscheduleEvent(hid_polling_callback_id, 0);
|
timing.UnscheduleEvent(hid_polling_callback_id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request) {
|
void ExtraHID::HandleConfigureHIDPollingRequest(std::span<const u8> request) {
|
||||||
if (request.size() != 3) {
|
if (request.size() != 3) {
|
||||||
LOG_ERROR(Service_IR, "Wrong request size ({}): {}", request.size(),
|
LOG_ERROR(Service_IR, "Wrong request size ({}): {}", request.size(),
|
||||||
fmt::format("{:02x}", fmt::join(request, " ")));
|
fmt::format("{:02x}", fmt::join(request, " ")));
|
||||||
@ -177,7 +177,7 @@ void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request)
|
|||||||
timing.ScheduleEvent(msToCycles(hid_period), hid_polling_callback_id);
|
timing.ScheduleEvent(msToCycles(hid_period), hid_polling_callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtraHID::HandleReadCalibrationDataRequest(const std::vector<u8>& request_buf) {
|
void ExtraHID::HandleReadCalibrationDataRequest(std::span<const u8> request_buf) {
|
||||||
struct ReadCalibrationDataRequest {
|
struct ReadCalibrationDataRequest {
|
||||||
RequestID request_id;
|
RequestID request_id;
|
||||||
u8 expected_response_time;
|
u8 expected_response_time;
|
||||||
@ -213,7 +213,7 @@ void ExtraHID::HandleReadCalibrationDataRequest(const std::vector<u8>& request_b
|
|||||||
Send(response);
|
Send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtraHID::OnReceive(const std::vector<u8>& data) {
|
void ExtraHID::OnReceive(std::span<const u8> data) {
|
||||||
switch (static_cast<RequestID>(data[0])) {
|
switch (static_cast<RequestID>(data[0])) {
|
||||||
case RequestID::ConfigureHIDPolling:
|
case RequestID::ConfigureHIDPolling:
|
||||||
HandleConfigureHIDPollingRequest(data);
|
HandleConfigureHIDPollingRequest(data);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <span>
|
||||||
#include <boost/serialization/array.hpp>
|
#include <boost/serialization/array.hpp>
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
@ -47,15 +48,15 @@ public:
|
|||||||
|
|
||||||
void OnConnect() override;
|
void OnConnect() override;
|
||||||
void OnDisconnect() override;
|
void OnDisconnect() override;
|
||||||
void OnReceive(const std::vector<u8>& data) override;
|
void OnReceive(std::span<const u8> data) override;
|
||||||
|
|
||||||
/// Requests input devices reload from current settings. Called when the input settings change.
|
/// Requests input devices reload from current settings. Called when the input settings change.
|
||||||
void RequestInputDevicesReload();
|
void RequestInputDevicesReload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SendHIDStatus();
|
void SendHIDStatus();
|
||||||
void HandleConfigureHIDPollingRequest(const std::vector<u8>& request);
|
void HandleConfigureHIDPollingRequest(std::span<const u8> request);
|
||||||
void HandleReadCalibrationDataRequest(const std::vector<u8>& request);
|
void HandleReadCalibrationDataRequest(std::span<const u8> request);
|
||||||
void LoadInputDevices();
|
void LoadInputDevices();
|
||||||
|
|
||||||
Core::Timing& timing;
|
Core::Timing& timing;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <boost/crc.hpp>
|
#include <boost/crc.hpp>
|
||||||
#include <boost/serialization/base_object.hpp>
|
#include <boost/serialization/base_object.hpp>
|
||||||
#include <boost/serialization/shared_ptr.hpp>
|
#include <boost/serialization/shared_ptr.hpp>
|
||||||
@ -98,9 +99,10 @@ public:
|
|||||||
* @params packet The data of the packet to put.
|
* @params packet The data of the packet to put.
|
||||||
* @returns whether the operation is successful.
|
* @returns whether the operation is successful.
|
||||||
*/
|
*/
|
||||||
bool Put(const std::vector<u8>& packet) {
|
bool Put(std::span<const u8> packet) {
|
||||||
if (info.packet_count == max_packet_count)
|
if (info.packet_count == max_packet_count) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
u32 write_offset;
|
u32 write_offset;
|
||||||
|
|
||||||
@ -182,12 +184,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetPacketInfo(u32 index, const PacketInfo& packet_info) {
|
void SetPacketInfo(u32 index, const PacketInfo& packet_info) {
|
||||||
memcpy(GetPacketInfoPointer(index), &packet_info, sizeof(PacketInfo));
|
std::memcpy(GetPacketInfoPointer(index), &packet_info, sizeof(PacketInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketInfo GetPacketInfo(u32 index) {
|
PacketInfo GetPacketInfo(u32 index) {
|
||||||
PacketInfo packet_info;
|
PacketInfo packet_info;
|
||||||
memcpy(&packet_info, GetPacketInfoPointer(index), sizeof(PacketInfo));
|
std::memcpy(&packet_info, GetPacketInfoPointer(index), sizeof(PacketInfo));
|
||||||
return packet_info;
|
return packet_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +200,7 @@ private:
|
|||||||
|
|
||||||
void UpdateBufferInfo() {
|
void UpdateBufferInfo() {
|
||||||
if (info_offset) {
|
if (info_offset) {
|
||||||
memcpy(shared_memory->GetPointer(info_offset), &info, sizeof(info));
|
std::memcpy(shared_memory->GetPointer(info_offset), &info, sizeof(info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +227,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Wraps the payload into packet and puts it to the receive buffer
|
/// Wraps the payload into packet and puts it to the receive buffer
|
||||||
void IR_USER::PutToReceive(const std::vector<u8>& payload) {
|
void IR_USER::PutToReceive(std::span<const u8> payload) {
|
||||||
LOG_TRACE(Service_IR, "called, data={}", fmt::format("{:02x}", fmt::join(payload, " ")));
|
LOG_TRACE(Service_IR, "called, data={}", fmt::format("{:02x}", fmt::join(payload, " ")));
|
||||||
std::size_t size = payload.size();
|
std::size_t size = payload.size();
|
||||||
|
|
||||||
@ -464,8 +466,8 @@ IR_USER::IR_USER(Core::System& system) : ServiceFramework("ir:USER", 1) {
|
|||||||
send_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:SendEvent");
|
send_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:SendEvent");
|
||||||
receive_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ReceiveEvent");
|
receive_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ReceiveEvent");
|
||||||
|
|
||||||
extra_hid = std::make_unique<ExtraHID>(
|
extra_hid = std::make_unique<ExtraHID>([this](std::span<const u8> data) { PutToReceive(data); },
|
||||||
[this](const std::vector<u8>& data) { PutToReceive(data); }, system.CoreTiming());
|
system.CoreTiming());
|
||||||
}
|
}
|
||||||
|
|
||||||
IR_USER::~IR_USER() {
|
IR_USER::~IR_USER() {
|
||||||
@ -481,7 +483,7 @@ void IR_USER::ReloadInputDevices() {
|
|||||||
IRDevice::IRDevice(SendFunc send_func_) : send_func(send_func_) {}
|
IRDevice::IRDevice(SendFunc send_func_) : send_func(send_func_) {}
|
||||||
IRDevice::~IRDevice() = default;
|
IRDevice::~IRDevice() = default;
|
||||||
|
|
||||||
void IRDevice::Send(const std::vector<u8>& data) {
|
void IRDevice::Send(std::span<const u8> data) {
|
||||||
send_func(data);
|
send_func(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <span>
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
@ -26,7 +26,7 @@ public:
|
|||||||
* A function object that implements the method to send data to the 3DS, which takes a vector of
|
* A function object that implements the method to send data to the 3DS, which takes a vector of
|
||||||
* data to send.
|
* data to send.
|
||||||
*/
|
*/
|
||||||
using SendFunc = std::function<void(const std::vector<u8>& data)>;
|
using SendFunc = std::function<void(std::span<const u8> data)>;
|
||||||
|
|
||||||
explicit IRDevice(SendFunc send_func);
|
explicit IRDevice(SendFunc send_func);
|
||||||
virtual ~IRDevice();
|
virtual ~IRDevice();
|
||||||
@ -38,11 +38,11 @@ public:
|
|||||||
virtual void OnDisconnect() = 0;
|
virtual void OnDisconnect() = 0;
|
||||||
|
|
||||||
/// Called when data is received from the 3DS. This is invoked by the ir:USER send function.
|
/// Called when data is received from the 3DS. This is invoked by the ir:USER send function.
|
||||||
virtual void OnReceive(const std::vector<u8>& data) = 0;
|
virtual void OnReceive(std::span<const u8> data) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Sends data to the 3DS. The actual sending method is specified in the constructor
|
/// Sends data to the 3DS. The actual sending method is specified in the constructor
|
||||||
void Send(const std::vector<u8>& data);
|
void Send(std::span<const u8> data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NOTE: This value is *not* serialized because it's always passed in the constructor
|
// NOTE: This value is *not* serialized because it's always passed in the constructor
|
||||||
@ -161,7 +161,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
void ReleaseReceivedData(Kernel::HLERequestContext& ctx);
|
void ReleaseReceivedData(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
void PutToReceive(const std::vector<u8>& payload);
|
void PutToReceive(std::span<const u8> payload);
|
||||||
|
|
||||||
std::shared_ptr<Kernel::Event> conn_status_event, send_event, receive_event;
|
std::shared_ptr<Kernel::Event> conn_status_event, send_event, receive_event;
|
||||||
std::shared_ptr<Kernel::SharedMemory> shared_memory;
|
std::shared_ptr<Kernel::SharedMemory> shared_memory;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <boost/serialization/weak_ptr.hpp>
|
#include <boost/serialization/weak_ptr.hpp>
|
||||||
#include "audio_core/input.h"
|
#include "audio_core/input.h"
|
||||||
#include "audio_core/input_details.h"
|
#include "audio_core/input_details.h"
|
||||||
@ -77,7 +78,7 @@ struct State {
|
|||||||
u8 sample_size = 0;
|
u8 sample_size = 0;
|
||||||
SampleRate sample_rate = SampleRate::Rate16360;
|
SampleRate sample_rate = SampleRate::Rate16360;
|
||||||
|
|
||||||
void WriteSamples(const std::vector<u8>& samples) {
|
void WriteSamples(std::span<const u8> samples) {
|
||||||
u32 bytes_total_written = 0;
|
u32 bytes_total_written = 0;
|
||||||
const std::size_t remaining_space = size - offset;
|
const std::size_t remaining_space = size - offset;
|
||||||
std::size_t bytes_to_write = std::min(samples.size(), remaining_space);
|
std::size_t bytes_to_write = std::min(samples.size(), remaining_space);
|
||||||
|
@ -843,14 +843,14 @@ void NWM_UDS::Unbind(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.Push<u32>(0);
|
rb.Push<u32>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode NWM_UDS::BeginHostingNetwork(const u8* network_info_buffer,
|
ResultCode NWM_UDS::BeginHostingNetwork(std::span<const u8> network_info_buffer,
|
||||||
std::size_t network_info_size, std::vector<u8> passphrase) {
|
std::vector<u8> passphrase) {
|
||||||
// TODO(Subv): Store the passphrase and verify it when attempting a connection.
|
// TODO(Subv): Store the passphrase and verify it when attempting a connection.
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(connection_status_mutex);
|
std::lock_guard lock(connection_status_mutex);
|
||||||
network_info = {};
|
network_info = {};
|
||||||
std::memcpy(&network_info, network_info_buffer, network_info_size);
|
std::memcpy(&network_info, network_info_buffer.data(), network_info_buffer.size());
|
||||||
|
|
||||||
// The real UDS module throws a fatal error if this assert fails.
|
// The real UDS module throws a fatal error if this assert fails.
|
||||||
ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member.");
|
ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member.");
|
||||||
@ -921,8 +921,7 @@ void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) {
|
|||||||
ASSERT(passphrase.size() == passphrase_size);
|
ASSERT(passphrase.size() == passphrase_size);
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "called");
|
LOG_DEBUG(Service_NWM, "called");
|
||||||
auto result = BeginHostingNetwork(network_info_buffer.data(), network_info_buffer.size(),
|
auto result = BeginHostingNetwork(network_info_buffer, std::move(passphrase));
|
||||||
std::move(passphrase));
|
|
||||||
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -940,8 +939,7 @@ void NWM_UDS::BeginHostingNetworkDeprecated(Kernel::HLERequestContext& ctx) {
|
|||||||
ASSERT(passphrase.size() == passphrase_size);
|
ASSERT(passphrase.size() == passphrase_size);
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "called");
|
LOG_DEBUG(Service_NWM, "called");
|
||||||
auto result = BeginHostingNetwork(network_info_buffer.data(), network_info_buffer.size(),
|
auto result = BeginHostingNetwork(network_info_buffer, std::move(passphrase));
|
||||||
std::move(passphrase));
|
|
||||||
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -1277,10 +1275,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
||||||
const u8* network_info_buffer, std::size_t network_info_size,
|
std::span<const u8> network_info_buffer, u8 connection_type,
|
||||||
u8 connection_type, std::vector<u8> passphrase) {
|
std::vector<u8> passphrase) {
|
||||||
network_info = {};
|
network_info = {};
|
||||||
std::memcpy(&network_info, network_info_buffer, network_info_size);
|
std::memcpy(&network_info, network_info_buffer.data(), network_info_buffer.size());
|
||||||
|
|
||||||
// Start the connection sequence
|
// Start the connection sequence
|
||||||
StartConnectionSequence(network_info.host_mac_address);
|
StartConnectionSequence(network_info.host_mac_address);
|
||||||
@ -1304,8 +1302,7 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
std::vector<u8> passphrase = rp.PopStaticBuffer();
|
std::vector<u8> passphrase = rp.PopStaticBuffer();
|
||||||
|
|
||||||
ConnectToNetwork(ctx, 0x1E, network_info_buffer.data(), network_info_buffer.size(),
|
ConnectToNetwork(ctx, 0x1E, network_info_buffer, connection_type, std::move(passphrase));
|
||||||
connection_type, std::move(passphrase));
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "called");
|
LOG_DEBUG(Service_NWM, "called");
|
||||||
}
|
}
|
||||||
@ -1322,8 +1319,7 @@ void NWM_UDS::ConnectToNetworkDeprecated(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
std::vector<u8> passphrase = rp.PopStaticBuffer();
|
std::vector<u8> passphrase = rp.PopStaticBuffer();
|
||||||
|
|
||||||
ConnectToNetwork(ctx, 0x09, network_info_buffer.data(), network_info_buffer.size(),
|
ConnectToNetwork(ctx, 0x09, network_info_buffer, connection_type, std::move(passphrase));
|
||||||
connection_type, std::move(passphrase));
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "called");
|
LOG_DEBUG(Service_NWM, "called");
|
||||||
}
|
}
|
||||||
|
@ -452,12 +452,12 @@ private:
|
|||||||
u32 sharedmem_size, const NodeInfo& node, u16 version,
|
u32 sharedmem_size, const NodeInfo& node, u16 version,
|
||||||
std::shared_ptr<Kernel::SharedMemory> sharedmem);
|
std::shared_ptr<Kernel::SharedMemory> sharedmem);
|
||||||
|
|
||||||
ResultCode BeginHostingNetwork(const u8* network_info_buffer, std::size_t network_info_size,
|
ResultCode BeginHostingNetwork(std::span<const u8> network_info_buffer,
|
||||||
std::vector<u8> passphrase);
|
std::vector<u8> passphrase);
|
||||||
|
|
||||||
void ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
void ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
|
||||||
const u8* network_info_buffer, std::size_t network_info_size,
|
std::span<const u8> network_info_buffer, u8 connection_type,
|
||||||
u8 connection_type, std::vector<u8> passphrase);
|
std::vector<u8> passphrase);
|
||||||
|
|
||||||
void BeaconBroadcastCallback(std::uintptr_t user_data, s64 cycles_late);
|
void BeaconBroadcastCallback(std::uintptr_t user_data, s64 cycles_late);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body) {
|
AuthenticationSeq GetAuthenticationSeqNumber(std::span<const u8> body) {
|
||||||
AuthenticationFrame frame;
|
AuthenticationFrame frame;
|
||||||
std::memcpy(&frame, body.data(), sizeof(frame));
|
std::memcpy(&frame, body.data(), sizeof(frame));
|
||||||
|
|
||||||
@ -74,9 +74,9 @@ std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_i
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<AssocStatus, u16> GetAssociationResult(const std::vector<u8>& body) {
|
std::tuple<AssocStatus, u16> GetAssociationResult(std::span<const u8> body) {
|
||||||
AssociationResponseFrame frame;
|
AssociationResponseFrame frame;
|
||||||
memcpy(&frame, body.data(), sizeof(frame));
|
std::memcpy(&frame, body.data(), sizeof(frame));
|
||||||
|
|
||||||
constexpr u16 AssociationIdMask = 0x3FFF;
|
constexpr u16 AssociationIdMask = 0x3FFF;
|
||||||
return std::make_tuple(frame.status_code, frame.assoc_id & AssociationIdMask);
|
return std::make_tuple(frame.status_code, frame.assoc_id & AssociationIdMask);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
@ -41,7 +42,7 @@ static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame h
|
|||||||
std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq);
|
std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq);
|
||||||
|
|
||||||
/// Returns the sequence number from the body of an Authentication frame.
|
/// Returns the sequence number from the body of an Authentication frame.
|
||||||
AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body);
|
AuthenticationSeq GetAuthenticationSeqNumber(std::span<const u8> body);
|
||||||
|
|
||||||
/// Generates an 802.11 association response frame with the specified status, association id and
|
/// Generates an 802.11 association response frame with the specified status, association id and
|
||||||
/// network id, starting at the frame body.
|
/// network id, starting at the frame body.
|
||||||
@ -49,6 +50,6 @@ std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_i
|
|||||||
|
|
||||||
/// Returns a tuple of (association status, association id) from the body of an AssociationResponse
|
/// Returns a tuple of (association status, association id) from the body of an AssociationResponse
|
||||||
/// frame.
|
/// frame.
|
||||||
std::tuple<AssocStatus, u16> GetAssociationResult(const std::vector<u8>& body);
|
std::tuple<AssocStatus, u16> GetAssociationResult(std::span<const u8> body);
|
||||||
|
|
||||||
} // namespace Service::NWM
|
} // namespace Service::NWM
|
||||||
|
@ -28,7 +28,7 @@ static std::vector<u8> GenerateLLCHeader(EtherType protocol) {
|
|||||||
header.protocol = protocol;
|
header.protocol = protocol;
|
||||||
|
|
||||||
std::vector<u8> buffer(sizeof(header));
|
std::vector<u8> buffer(sizeof(header));
|
||||||
memcpy(buffer.data(), &header, sizeof(header));
|
std::memcpy(buffer.data(), &header, sizeof(header));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ static std::vector<u8> GenerateSecureDataHeader(u16 data_size, u8 channel, u16 d
|
|||||||
header.src_node_id = src_node_id;
|
header.src_node_id = src_node_id;
|
||||||
|
|
||||||
std::vector<u8> buffer(sizeof(header));
|
std::vector<u8> buffer(sizeof(header));
|
||||||
memcpy(buffer.data(), &header, sizeof(header));
|
std::memcpy(buffer.data(), &header, sizeof(header));
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ static std::array<u8, CryptoPP::Weak::MD5::DIGESTSIZE> GetDataCryptoCTR(
|
|||||||
* @returns The key used for data frames crypto.
|
* @returns The key used for data frames crypto.
|
||||||
*/
|
*/
|
||||||
[[maybe_unused]] static std::array<u8, CryptoPP::AES::BLOCKSIZE> GenerateDataCCMPKey(
|
[[maybe_unused]] static std::array<u8, CryptoPP::AES::BLOCKSIZE> GenerateDataCCMPKey(
|
||||||
const std::vector<u8>& passphrase, const NetworkInfo& network_info) {
|
std::span<const u8> passphrase, const NetworkInfo& network_info) {
|
||||||
// Calculate the MD5 hash of the input passphrase.
|
// Calculate the MD5 hash of the input passphrase.
|
||||||
std::array<u8, CryptoPP::Weak::MD5::DIGESTSIZE> passphrase_hash;
|
std::array<u8, CryptoPP::Weak::MD5::DIGESTSIZE> passphrase_hash;
|
||||||
CryptoPP::Weak::MD5().CalculateDigest(passphrase_hash.data(), passphrase.data(),
|
CryptoPP::Weak::MD5().CalculateDigest(passphrase_hash.data(), passphrase.data(),
|
||||||
@ -158,9 +158,9 @@ static std::vector<u8> GenerateCCMPAAD(const MacAddress& sender, const MacAddres
|
|||||||
* @returns The decrypted payload.
|
* @returns The decrypted payload.
|
||||||
*/
|
*/
|
||||||
[[maybe_unused]] static std::vector<u8> DecryptDataFrame(
|
[[maybe_unused]] static std::vector<u8> DecryptDataFrame(
|
||||||
const std::vector<u8>& encrypted_payload,
|
std::span<const u8> encrypted_payload, const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key,
|
||||||
const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key, const MacAddress& sender,
|
const MacAddress& sender, const MacAddress& receiver, const MacAddress& bssid,
|
||||||
const MacAddress& receiver, const MacAddress& bssid, u16 sequence_number, u16 frame_control) {
|
u16 sequence_number, u16 frame_control) {
|
||||||
|
|
||||||
// Reference: IEEE 802.11-2007
|
// Reference: IEEE 802.11-2007
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ static std::vector<u8> GenerateCCMPAAD(const MacAddress& sender, const MacAddres
|
|||||||
* @returns The encrypted payload.
|
* @returns The encrypted payload.
|
||||||
*/
|
*/
|
||||||
[[maybe_unused]] static std::vector<u8> EncryptDataFrame(
|
[[maybe_unused]] static std::vector<u8> EncryptDataFrame(
|
||||||
const std::vector<u8>& payload, const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key,
|
std::span<const u8> payload, const std::array<u8, CryptoPP::AES::BLOCKSIZE>& ccmp_key,
|
||||||
const MacAddress& sender, const MacAddress& receiver, const MacAddress& bssid,
|
const MacAddress& sender, const MacAddress& receiver, const MacAddress& bssid,
|
||||||
u16 sequence_number, u16 frame_control) {
|
u16 sequence_number, u16 frame_control) {
|
||||||
// Reference: IEEE 802.11-2007
|
// Reference: IEEE 802.11-2007
|
||||||
@ -266,7 +266,7 @@ static std::vector<u8> GenerateCCMPAAD(const MacAddress& sender, const MacAddres
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node,
|
std::vector<u8> GenerateDataPayload(std::span<const u8> data, u8 channel, u16 dest_node,
|
||||||
u16 src_node, u16 sequence_number) {
|
u16 src_node, u16 sequence_number) {
|
||||||
std::vector<u8> buffer = GenerateLLCHeader(EtherType::SecureData);
|
std::vector<u8> buffer = GenerateLLCHeader(EtherType::SecureData);
|
||||||
std::vector<u8> securedata_header = GenerateSecureDataHeader(
|
std::vector<u8> securedata_header = GenerateSecureDataHeader(
|
||||||
@ -277,7 +277,7 @@ std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
SecureDataHeader ParseSecureDataHeader(const std::vector<u8>& data) {
|
SecureDataHeader ParseSecureDataHeader(std::span<const u8> data) {
|
||||||
SecureDataHeader header;
|
SecureDataHeader header;
|
||||||
|
|
||||||
// Skip the LLC header
|
// Skip the LLC header
|
||||||
@ -308,20 +308,20 @@ std::vector<u8> GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
EtherType GetFrameEtherType(const std::vector<u8>& frame) {
|
EtherType GetFrameEtherType(std::span<const u8> frame) {
|
||||||
LLCHeader header;
|
LLCHeader header;
|
||||||
std::memcpy(&header, frame.data(), sizeof(header));
|
std::memcpy(&header, frame.data(), sizeof(header));
|
||||||
return header.protocol;
|
return header.protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 GetEAPoLFrameType(const std::vector<u8>& frame) {
|
u16 GetEAPoLFrameType(std::span<const u8> frame) {
|
||||||
// Ignore the LLC header
|
// Ignore the LLC header
|
||||||
u16_be eapol_type;
|
u16_be eapol_type;
|
||||||
std::memcpy(&eapol_type, frame.data() + sizeof(LLCHeader), sizeof(eapol_type));
|
std::memcpy(&eapol_type, frame.data() + sizeof(LLCHeader), sizeof(eapol_type));
|
||||||
return eapol_type;
|
return eapol_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeInfo DeserializeNodeInfoFromFrame(const std::vector<u8>& frame) {
|
NodeInfo DeserializeNodeInfoFromFrame(std::span<const u8> frame) {
|
||||||
EAPoLStartPacket eapol_start;
|
EAPoLStartPacket eapol_start;
|
||||||
|
|
||||||
// Skip the LLC header
|
// Skip the LLC header
|
||||||
@ -372,7 +372,7 @@ std::vector<u8> GenerateEAPoLLogoffFrame(const MacAddress& mac_address, u16 netw
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPoLLogoffPacket ParseEAPoLLogoffFrame(const std::vector<u8>& frame) {
|
EAPoLLogoffPacket ParseEAPoLLogoffFrame(std::span<const u8> frame) {
|
||||||
EAPoLLogoffPacket eapol_logoff;
|
EAPoLLogoffPacket eapol_logoff;
|
||||||
|
|
||||||
// Skip the LLC header
|
// Skip the LLC header
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
@ -118,13 +119,13 @@ static_assert(sizeof(EAPoLLogoffPacket) == 0x298, "EAPoLLogoffPacket has the wro
|
|||||||
* Generates an unencrypted 802.11 data payload.
|
* Generates an unencrypted 802.11 data payload.
|
||||||
* @returns The generated frame payload.
|
* @returns The generated frame payload.
|
||||||
*/
|
*/
|
||||||
std::vector<u8> GenerateDataPayload(const std::vector<u8>& data, u8 channel, u16 dest_node,
|
std::vector<u8> GenerateDataPayload(std::span<const u8> data, u8 channel, u16 dest_node,
|
||||||
u16 src_node, u16 sequence_number);
|
u16 src_node, u16 sequence_number);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the SecureDataHeader stored in an 802.11 data frame.
|
* Returns the SecureDataHeader stored in an 802.11 data frame.
|
||||||
*/
|
*/
|
||||||
SecureDataHeader ParseSecureDataHeader(const std::vector<u8>& data);
|
SecureDataHeader ParseSecureDataHeader(std::span<const u8> data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generates an unencrypted 802.11 data frame body with the EAPoL-Start format for UDS
|
* Generates an unencrypted 802.11 data frame body with the EAPoL-Start format for UDS
|
||||||
@ -136,19 +137,19 @@ std::vector<u8> GenerateEAPoLStartFrame(u16 association_id, const NodeInfo& node
|
|||||||
/*
|
/*
|
||||||
* Returns the EtherType of the specified 802.11 frame.
|
* Returns the EtherType of the specified 802.11 frame.
|
||||||
*/
|
*/
|
||||||
EtherType GetFrameEtherType(const std::vector<u8>& frame);
|
EtherType GetFrameEtherType(std::span<const u8> frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the EAPoL type (Start / Logoff) of the specified 802.11 frame.
|
* Returns the EAPoL type (Start / Logoff) of the specified 802.11 frame.
|
||||||
* Note: The frame *must* be an EAPoL frame.
|
* Note: The frame *must* be an EAPoL frame.
|
||||||
*/
|
*/
|
||||||
u16 GetEAPoLFrameType(const std::vector<u8>& frame);
|
u16 GetEAPoLFrameType(std::span<const u8> frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a deserialized NodeInfo structure from the information inside an EAPoL-Start packet
|
* Returns a deserialized NodeInfo structure from the information inside an EAPoL-Start packet
|
||||||
* encapsulated in an 802.11 data frame.
|
* encapsulated in an 802.11 data frame.
|
||||||
*/
|
*/
|
||||||
NodeInfo DeserializeNodeInfoFromFrame(const std::vector<u8>& frame);
|
NodeInfo DeserializeNodeInfoFromFrame(std::span<const u8> frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a NodeInfo constructed from the data in the specified EAPoLNodeInfo.
|
* Returns a NodeInfo constructed from the data in the specified EAPoLNodeInfo.
|
||||||
@ -166,6 +167,6 @@ std::vector<u8> GenerateEAPoLLogoffFrame(const MacAddress& mac_address, u16 netw
|
|||||||
/*
|
/*
|
||||||
* Returns a EAPoLLogoffPacket representing the specified 802.11-encapsulated data frame.
|
* Returns a EAPoLLogoffPacket representing the specified 802.11-encapsulated data frame.
|
||||||
*/
|
*/
|
||||||
EAPoLLogoffPacket ParseEAPoLLogoffFrame(const std::vector<u8>& frame);
|
EAPoLLogoffPacket ParseEAPoLLogoffFrame(std::span<const u8> frame);
|
||||||
|
|
||||||
} // namespace Service::NWM
|
} // namespace Service::NWM
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/soc_u.h"
|
#include "core/hle/service/soc_u.h"
|
||||||
#include "core/network/network.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@ -154,6 +153,112 @@ static u32 SocketTypeFromPlatform(u32 type) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds the translation from system network errors to 3DS network errors
|
||||||
|
static const std::unordered_map<int, int> error_map = {{
|
||||||
|
{E2BIG, 1},
|
||||||
|
{ERRNO(EACCES), 2},
|
||||||
|
{ERRNO(EADDRINUSE), 3},
|
||||||
|
{ERRNO(EADDRNOTAVAIL), 4},
|
||||||
|
{ERRNO(EAFNOSUPPORT), 5},
|
||||||
|
{EAGAIN, 6},
|
||||||
|
#ifdef _WIN32
|
||||||
|
{WSAEWOULDBLOCK, 6},
|
||||||
|
#else
|
||||||
|
#if EAGAIN != EWOULDBLOCK
|
||||||
|
{EWOULDBLOCK, 6},
|
||||||
|
#endif
|
||||||
|
#endif // _WIN32
|
||||||
|
{ERRNO(EALREADY), 7},
|
||||||
|
{ERRNO(EBADF), 8},
|
||||||
|
{EBADMSG, 9},
|
||||||
|
{EBUSY, 10},
|
||||||
|
{ECANCELED, 11},
|
||||||
|
{ECHILD, 12},
|
||||||
|
{ERRNO(ECONNABORTED), 13},
|
||||||
|
{ERRNO(ECONNREFUSED), 14},
|
||||||
|
{ERRNO(ECONNRESET), 15},
|
||||||
|
{EDEADLK, 16},
|
||||||
|
{ERRNO(EDESTADDRREQ), 17},
|
||||||
|
{EDOM, 18},
|
||||||
|
{ERRNO(EDQUOT), 19},
|
||||||
|
{EEXIST, 20},
|
||||||
|
{ERRNO(EFAULT), 21},
|
||||||
|
{EFBIG, 22},
|
||||||
|
{ERRNO(EHOSTUNREACH), 23},
|
||||||
|
{EIDRM, 24},
|
||||||
|
{EILSEQ, 25},
|
||||||
|
{ERRNO(EINPROGRESS), 26},
|
||||||
|
{ERRNO(EINTR), 27},
|
||||||
|
{ERRNO(EINVAL), 28},
|
||||||
|
{EIO, 29},
|
||||||
|
{ERRNO(EISCONN), 30},
|
||||||
|
{EISDIR, 31},
|
||||||
|
{ERRNO(ELOOP), 32},
|
||||||
|
{ERRNO(EMFILE), 33},
|
||||||
|
{EMLINK, 34},
|
||||||
|
{ERRNO(EMSGSIZE), 35},
|
||||||
|
#ifdef EMULTIHOP
|
||||||
|
{ERRNO(EMULTIHOP), 36},
|
||||||
|
#endif
|
||||||
|
{ERRNO(ENAMETOOLONG), 37},
|
||||||
|
{ERRNO(ENETDOWN), 38},
|
||||||
|
{ERRNO(ENETRESET), 39},
|
||||||
|
{ERRNO(ENETUNREACH), 40},
|
||||||
|
{ENFILE, 41},
|
||||||
|
{ERRNO(ENOBUFS), 42},
|
||||||
|
#ifdef ENODATA
|
||||||
|
{ENODATA, 43},
|
||||||
|
#endif
|
||||||
|
{ENODEV, 44},
|
||||||
|
{ENOENT, 45},
|
||||||
|
{ENOEXEC, 46},
|
||||||
|
{ENOLCK, 47},
|
||||||
|
{ENOLINK, 48},
|
||||||
|
{ENOMEM, 49},
|
||||||
|
{ENOMSG, 50},
|
||||||
|
{ERRNO(ENOPROTOOPT), 51},
|
||||||
|
{ENOSPC, 52},
|
||||||
|
#ifdef ENOSR
|
||||||
|
{ENOSR, 53},
|
||||||
|
#endif
|
||||||
|
#ifdef ENOSTR
|
||||||
|
{ENOSTR, 54},
|
||||||
|
#endif
|
||||||
|
{ENOSYS, 55},
|
||||||
|
{ERRNO(ENOTCONN), 56},
|
||||||
|
{ENOTDIR, 57},
|
||||||
|
{ERRNO(ENOTEMPTY), 58},
|
||||||
|
{ERRNO(ENOTSOCK), 59},
|
||||||
|
{ENOTSUP, 60},
|
||||||
|
{ENOTTY, 61},
|
||||||
|
{ENXIO, 62},
|
||||||
|
{ERRNO(EOPNOTSUPP), 63},
|
||||||
|
{EOVERFLOW, 64},
|
||||||
|
{EPERM, 65},
|
||||||
|
{EPIPE, 66},
|
||||||
|
{EPROTO, 67},
|
||||||
|
{ERRNO(EPROTONOSUPPORT), 68},
|
||||||
|
{ERRNO(EPROTOTYPE), 69},
|
||||||
|
{ERANGE, 70},
|
||||||
|
{EROFS, 71},
|
||||||
|
{ESPIPE, 72},
|
||||||
|
{ESRCH, 73},
|
||||||
|
{ERRNO(ESTALE), 74},
|
||||||
|
#ifdef ETIME
|
||||||
|
{ETIME, 75},
|
||||||
|
#endif
|
||||||
|
{ERRNO(ETIMEDOUT), 76},
|
||||||
|
}};
|
||||||
|
|
||||||
|
/// Converts a network error from platform-specific to 3ds-specific
|
||||||
|
static int TranslateError(int error) {
|
||||||
|
const auto& found = error_map.find(error);
|
||||||
|
if (found != error_map.end()) {
|
||||||
|
return -found->second;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
struct CTRLinger {
|
struct CTRLinger {
|
||||||
u32_le l_onoff;
|
u32_le l_onoff;
|
||||||
u32_le l_linger;
|
u32_le l_linger;
|
||||||
@ -207,7 +312,7 @@ static void TranslateSockOptDataToPlatform(std::vector<u8>& out, const std::vect
|
|||||||
linger_out.l_linger = static_cast<decltype(linger_out.l_linger)>(
|
linger_out.l_linger = static_cast<decltype(linger_out.l_linger)>(
|
||||||
reinterpret_cast<const CTRLinger*>(in.data())->l_linger);
|
reinterpret_cast<const CTRLinger*>(in.data())->l_linger);
|
||||||
out.resize(sizeof(linger));
|
out.resize(sizeof(linger));
|
||||||
memcpy(out.data(), &linger_out, sizeof(linger));
|
std::memcpy(out.data(), &linger_out, sizeof(linger));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Other options should have the size of an int, even for booleans
|
// Other options should have the size of an int, even for booleans
|
||||||
@ -227,7 +332,7 @@ static void TranslateSockOptDataToPlatform(std::vector<u8>& out, const std::vect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
out.resize(sizeof(int));
|
out.resize(sizeof(int));
|
||||||
memcpy(out.data(), &value, sizeof(int));
|
std::memcpy(out.data(), &value, sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 TranslateSockOptSizeToPlatform(int platform_level, int platform_opt) {
|
static u32 TranslateSockOptSizeToPlatform(int platform_level, int platform_opt) {
|
||||||
@ -244,7 +349,7 @@ static void TranslateSockOptDataFromPlatform(std::vector<u8>& out, const std::ve
|
|||||||
reinterpret_cast<const linger*>(in.data())->l_onoff);
|
reinterpret_cast<const linger*>(in.data())->l_onoff);
|
||||||
linger_out.l_linger = static_cast<decltype(linger_out.l_linger)>(
|
linger_out.l_linger = static_cast<decltype(linger_out.l_linger)>(
|
||||||
reinterpret_cast<const linger*>(in.data())->l_linger);
|
reinterpret_cast<const linger*>(in.data())->l_linger);
|
||||||
memcpy(out.data(), &linger_out, std::min(out.size(), sizeof(CTRLinger)));
|
std::memcpy(out.data(), &linger_out, std::min(out.size(), sizeof(CTRLinger)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (out.size() == sizeof(u8) && in.size() == sizeof(int)) {
|
if (out.size() == sizeof(u8) && in.size() == sizeof(int)) {
|
||||||
@ -266,6 +371,42 @@ static void TranslateSockOptDataFromPlatform(std::vector<u8>& out, const std::ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SOC_U::GetSocketBlocking(const SocketHolder& socket_holder) {
|
||||||
|
return socket_holder.blocking;
|
||||||
|
}
|
||||||
|
u32 SOC_U::SetSocketBlocking(SocketHolder& socket_holder, bool blocking) {
|
||||||
|
u32 posix_ret = 0;
|
||||||
|
#ifdef _WIN32
|
||||||
|
unsigned long nonblocking = (blocking) ? 0 : 1;
|
||||||
|
int ret = ioctlsocket(socket_holder.socket_fd, FIONBIO, &nonblocking);
|
||||||
|
if (ret == SOCKET_ERROR_VALUE) {
|
||||||
|
posix_ret = TranslateError(GET_ERRNO);
|
||||||
|
return posix_ret;
|
||||||
|
}
|
||||||
|
socket_holder.blocking = blocking;
|
||||||
|
#else
|
||||||
|
int flags = ::fcntl(socket_holder.socket_fd, F_GETFL, 0);
|
||||||
|
if (flags == SOCKET_ERROR_VALUE) {
|
||||||
|
posix_ret = TranslateError(GET_ERRNO);
|
||||||
|
return posix_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags &= ~O_NONBLOCK;
|
||||||
|
if (!blocking) { // O_NONBLOCK
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket_holder.blocking = blocking;
|
||||||
|
|
||||||
|
const int ret = ::fcntl(socket_holder.socket_fd, F_SETFL, flags);
|
||||||
|
if (ret == SOCKET_ERROR_VALUE) {
|
||||||
|
posix_ret = TranslateError(GET_ERRNO);
|
||||||
|
return posix_ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return posix_ret;
|
||||||
|
}
|
||||||
|
|
||||||
static u32 SendRecvFlagsToPlatform(u32 flags) {
|
static u32 SendRecvFlagsToPlatform(u32 flags) {
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (flags & 1) {
|
if (flags & 1) {
|
||||||
@ -372,10 +513,173 @@ struct CTRPollFD {
|
|||||||
};
|
};
|
||||||
Events events; ///< Events to poll for (input)
|
Events events; ///< Events to poll for (input)
|
||||||
Events revents; ///< Events received (output)
|
Events revents; ///< Events received (output)
|
||||||
|
|
||||||
|
/// Converts a platform-specific pollfd to a 3ds specific structure
|
||||||
|
static CTRPollFD FromPlatform(SOC::SOC_U& socu, pollfd const& fd, u8 has_libctru_bug) {
|
||||||
|
CTRPollFD result;
|
||||||
|
result.events.hex = Events::TranslateTo3DS(fd.events, has_libctru_bug).hex;
|
||||||
|
result.revents.hex = Events::TranslateTo3DS(fd.revents, has_libctru_bug).hex;
|
||||||
|
for (const auto& socket : socu.open_sockets) {
|
||||||
|
if (socket.second.socket_fd == fd.fd) {
|
||||||
|
result.fd = socket.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a 3ds specific pollfd to a platform-specific structure
|
||||||
|
static pollfd ToPlatform(SOC::SOC_U& socu, CTRPollFD const& fd, u8& haslibctrbug) {
|
||||||
|
pollfd result;
|
||||||
|
u8 unused = 0;
|
||||||
|
result.events = Events::TranslateToPlatform(fd.events, false, haslibctrbug);
|
||||||
|
result.revents = Events::TranslateToPlatform(fd.revents, true, unused);
|
||||||
|
auto iter = socu.open_sockets.find(fd.fd);
|
||||||
|
result.fd = (iter != socu.open_sockets.end()) ? iter->second.socket_fd : 0;
|
||||||
|
if (iter == socu.open_sockets.end()) {
|
||||||
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", fd.fd);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static_assert(std::is_trivially_copyable_v<CTRPollFD>,
|
static_assert(std::is_trivially_copyable_v<CTRPollFD>,
|
||||||
"CTRPollFD is used with std::memcpy and must be trivially copyable");
|
"CTRPollFD is used with std::memcpy and must be trivially copyable");
|
||||||
|
|
||||||
|
/// Union to represent the 3ds' sockaddr structure
|
||||||
|
union CTRSockAddr {
|
||||||
|
/// Structure to represent a raw sockaddr
|
||||||
|
struct {
|
||||||
|
u8 len; ///< The length of the entire structure, only the set fields count
|
||||||
|
u8 sa_family; ///< The address family of the sockaddr
|
||||||
|
u8 sa_data[0x1A]; ///< The extra data, this varies, depending on the address family
|
||||||
|
} raw;
|
||||||
|
|
||||||
|
/// Structure to represent the 3ds' sockaddr_in structure
|
||||||
|
struct CTRSockAddrIn {
|
||||||
|
u8 len; ///< The length of the entire structure
|
||||||
|
u8 sin_family; ///< The address family of the sockaddr_in
|
||||||
|
u16 sin_port; ///< The port associated with this sockaddr_in
|
||||||
|
u32 sin_addr; ///< The actual address of the sockaddr_in
|
||||||
|
} in;
|
||||||
|
static_assert(sizeof(CTRSockAddrIn) == 8, "Invalid CTRSockAddrIn size");
|
||||||
|
|
||||||
|
/// Convert a 3DS CTRSockAddr to a platform-specific sockaddr
|
||||||
|
static sockaddr ToPlatform(CTRSockAddr const& ctr_addr) {
|
||||||
|
sockaddr result;
|
||||||
|
ASSERT_MSG(ctr_addr.raw.len == sizeof(CTRSockAddrIn),
|
||||||
|
"Unhandled address size (len) in CTRSockAddr::ToPlatform");
|
||||||
|
result.sa_family = SocketDomainToPlatform(ctr_addr.raw.sa_family);
|
||||||
|
std::memset(result.sa_data, 0, sizeof(result.sa_data));
|
||||||
|
|
||||||
|
// We can not guarantee ABI compatibility between platforms so we copy the fields manually
|
||||||
|
switch (result.sa_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
sockaddr_in* result_in = reinterpret_cast<sockaddr_in*>(&result);
|
||||||
|
result_in->sin_port = ctr_addr.in.sin_port;
|
||||||
|
result_in->sin_addr.s_addr = ctr_addr.in.sin_addr;
|
||||||
|
std::memset(result_in->sin_zero, 0, sizeof(result_in->sin_zero));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a platform-specific sockaddr to a 3DS CTRSockAddr
|
||||||
|
static CTRSockAddr FromPlatform(sockaddr const& addr) {
|
||||||
|
CTRSockAddr result;
|
||||||
|
result.raw.sa_family = static_cast<u8>(SocketDomainFromPlatform(addr.sa_family));
|
||||||
|
// We can not guarantee ABI compatibility between platforms so we copy the fields manually
|
||||||
|
switch (addr.sa_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
sockaddr_in const* addr_in = reinterpret_cast<sockaddr_in const*>(&addr);
|
||||||
|
result.raw.len = sizeof(CTRSockAddrIn);
|
||||||
|
result.in.sin_port = addr_in->sin_port;
|
||||||
|
result.in.sin_addr = addr_in->sin_addr.s_addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ASSERT_MSG(false, "Unhandled address family (sa_family) in CTRSockAddr::ToPlatform");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CTRAddrInfo {
|
||||||
|
s32_le ai_flags;
|
||||||
|
s32_le ai_family;
|
||||||
|
s32_le ai_socktype;
|
||||||
|
s32_le ai_protocol;
|
||||||
|
s32_le ai_addrlen;
|
||||||
|
char ai_canonname[256];
|
||||||
|
CTRSockAddr ai_addr;
|
||||||
|
|
||||||
|
static u32 AddressInfoFlagsToPlatform(u32 flags) {
|
||||||
|
u32 ret = 0;
|
||||||
|
if (flags & 1) {
|
||||||
|
ret |= AI_PASSIVE;
|
||||||
|
}
|
||||||
|
if (flags & 2) {
|
||||||
|
ret |= AI_CANONNAME;
|
||||||
|
}
|
||||||
|
if (flags & 4) {
|
||||||
|
ret |= AI_NUMERICHOST;
|
||||||
|
}
|
||||||
|
if (flags & 8) {
|
||||||
|
ret |= AI_NUMERICSERV;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 AddressInfoFlagsFromPlatform(u32 flags) {
|
||||||
|
u32 ret = 0;
|
||||||
|
if (flags & AI_PASSIVE) {
|
||||||
|
ret |= 1;
|
||||||
|
}
|
||||||
|
if (flags & AI_CANONNAME) {
|
||||||
|
ret |= 2;
|
||||||
|
}
|
||||||
|
if (flags & AI_NUMERICHOST) {
|
||||||
|
ret |= 4;
|
||||||
|
}
|
||||||
|
if (flags & AI_NUMERICSERV) {
|
||||||
|
ret |= 8;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a platform-specific addrinfo to a 3ds addrinfo.
|
||||||
|
static CTRAddrInfo FromPlatform(const addrinfo& addr) {
|
||||||
|
CTRAddrInfo ctr_addr{
|
||||||
|
.ai_flags = static_cast<s32_le>(AddressInfoFlagsFromPlatform(addr.ai_flags)),
|
||||||
|
.ai_family = static_cast<s32_le>(SocketDomainFromPlatform(addr.ai_family)),
|
||||||
|
.ai_socktype = static_cast<s32_le>(SocketTypeFromPlatform(addr.ai_socktype)),
|
||||||
|
.ai_protocol = static_cast<s32_le>(SocketProtocolFromPlatform(addr.ai_protocol)),
|
||||||
|
.ai_addr = CTRSockAddr::FromPlatform(*addr.ai_addr),
|
||||||
|
};
|
||||||
|
ctr_addr.ai_addrlen = static_cast<s32_le>(ctr_addr.ai_addr.raw.len);
|
||||||
|
if (addr.ai_canonname)
|
||||||
|
std::strncpy(ctr_addr.ai_canonname, addr.ai_canonname,
|
||||||
|
sizeof(ctr_addr.ai_canonname) - 1);
|
||||||
|
return ctr_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a platform-specific addrinfo to a 3ds addrinfo.
|
||||||
|
static addrinfo ToPlatform(const CTRAddrInfo& ctr_addr) {
|
||||||
|
// Only certain fields are meaningful in hints, copy them manually
|
||||||
|
addrinfo addr = {
|
||||||
|
.ai_flags = static_cast<int>(AddressInfoFlagsToPlatform(ctr_addr.ai_flags)),
|
||||||
|
.ai_family = static_cast<int>(SocketDomainToPlatform(ctr_addr.ai_family)),
|
||||||
|
.ai_socktype = static_cast<int>(SocketTypeToPlatform(ctr_addr.ai_socktype)),
|
||||||
|
.ai_protocol = static_cast<int>(SocketProtocolToPlatform(ctr_addr.ai_protocol)),
|
||||||
|
};
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static u32 NameInfoFlagsToPlatform(u32 flags) {
|
static u32 NameInfoFlagsToPlatform(u32 flags) {
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
if (flags & 1) {
|
if (flags & 1) {
|
||||||
@ -396,6 +700,8 @@ static u32 NameInfoFlagsToPlatform(u32 flags) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static_assert(sizeof(CTRAddrInfo) == 0x130, "Size of CTRAddrInfo is not correct");
|
||||||
|
|
||||||
void SOC_U::PreTimerAdjust() {
|
void SOC_U::PreTimerAdjust() {
|
||||||
adjust_value_last = std::chrono::steady_clock::now();
|
adjust_value_last = std::chrono::steady_clock::now();
|
||||||
}
|
}
|
||||||
@ -409,64 +715,84 @@ void SOC_U::PostTimerAdjust(Kernel::HLERequestContext& ctx, const std::string& c
|
|||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SOC_U::CleanupSockets() {
|
||||||
|
for (const auto& sock : open_sockets)
|
||||||
|
closesocket(sock.second.socket_fd);
|
||||||
|
open_sockets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void SOC_U::Socket(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Socket(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x02, 3, 2);
|
IPC::RequestParser rp(ctx, 0x02, 3, 2);
|
||||||
const auto domain = rp.Pop<Network::Domain>();
|
u32 domain = SocketDomainToPlatform(rp.Pop<u32>()); // Address family
|
||||||
const auto type = rp.Pop<Network::Type>();
|
u32 type = SocketTypeToPlatform(rp.Pop<u32>());
|
||||||
const u32 protocol = rp.Pop<u32>();
|
u32 protocol = SocketProtocolToPlatform(rp.Pop<u32>());
|
||||||
rp.PopPID();
|
rp.PopPID();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
|
|
||||||
// Only 0 is allowed according to 3dbrew, using 0 will let the OS decide which protocol to use
|
// Only 0 is allowed according to 3dbrew, using 0 will let the OS decide which protocol to use
|
||||||
if (protocol != 0) [[unlikely]] {
|
if (protocol != 0) {
|
||||||
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
||||||
rb.Skip(1, false);
|
rb.Skip(1, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain != Network::Domain::INET) [[unlikely]] {
|
if (domain != AF_INET) {
|
||||||
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
||||||
rb.Skip(1, false);
|
rb.Skip(1, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != Network::Type::DGRAM && type != Network::Type::STREAM) [[unlikely]] {
|
if (type != SOCK_DGRAM && type != SOCK_STREAM) {
|
||||||
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
rb.Push(UnimplementedFunction(ErrorModule::SOC)); // TODO(Subv): Correct error code
|
||||||
rb.Skip(1, false);
|
rb.Skip(1, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto socket = std::make_unique<Network::Socket>();
|
u64 ret = static_cast<u64>(::socket(domain, type, protocol));
|
||||||
const auto ret = socket->Initialize(domain, type, protocol);
|
u32 socketHandle = GetNextSocketID();
|
||||||
const u32 socket_handle = GetNextSocketID();
|
|
||||||
|
|
||||||
if (ret == Network::Errno::SUCCESS) {
|
if ((s64)ret != SOCKET_ERROR_VALUE) {
|
||||||
open_sockets.emplace(socket_handle, std::move(socket));
|
open_sockets[socketHandle] = {static_cast<decltype(SocketHolder::socket_fd)>(ret), true};
|
||||||
|
#if _WIN32
|
||||||
|
// Disable UDP connection reset
|
||||||
|
int new_behavior = 0;
|
||||||
|
unsigned long bytes_returned = 0;
|
||||||
|
WSAIoctl(static_cast<SOCKET>(ret), _WSAIOW(IOC_VENDOR, 12), &new_behavior,
|
||||||
|
sizeof(new_behavior), NULL, 0, &bytes_returned, NULL, NULL);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((s64)ret == SOCKET_ERROR_VALUE)
|
||||||
|
ret = TranslateError(GET_ERRNO);
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(socket_handle);
|
rb.Push(socketHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SOC_U::Bind(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Bind(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x05, 2, 4);
|
IPC::RequestParser rp(ctx, 0x05, 2, 4);
|
||||||
const u32 socket_handle = rp.Pop<u32>();
|
u32 socket_handle = rp.Pop<u32>();
|
||||||
const u32 len = rp.Pop<u32>();
|
auto fd_info = open_sockets.find(socket_handle);
|
||||||
rp.PopPID();
|
if (fd_info == open_sockets.end()) {
|
||||||
const auto sock_addr_buf = rp.PopStaticBuffer();
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
|
|
||||||
auto socket = FindSocket(socket_handle);
|
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
u32 len = rp.Pop<u32>();
|
||||||
|
rp.PopPID();
|
||||||
|
auto sock_addr_buf = rp.PopStaticBuffer();
|
||||||
|
|
||||||
Network::CTRSockAddr ctr_sock_addr{};
|
CTRSockAddr ctr_sock_addr;
|
||||||
std::memcpy(&ctr_sock_addr, sock_addr_buf.data(), len);
|
std::memcpy(&ctr_sock_addr, sock_addr_buf.data(), len);
|
||||||
|
|
||||||
const auto ret = socket->Bind(ctr_sock_addr);
|
sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr);
|
||||||
|
|
||||||
|
s32 ret = ::bind(fd_info->second.socket_fd, &sock_addr, sizeof(sock_addr));
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
ret = TranslateError(GET_ERRNO);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
@ -475,87 +801,92 @@ void SOC_U::Bind(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
void SOC_U::Fcntl(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Fcntl(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x13, 3, 2);
|
IPC::RequestParser rp(ctx, 0x13, 3, 2);
|
||||||
const u32 socket_handle = rp.Pop<u32>();
|
u32 socket_handle = rp.Pop<u32>();
|
||||||
const auto ctr_cmd = rp.Pop<Network::FcntlCmd>();
|
auto fd_info = open_sockets.find(socket_handle);
|
||||||
const u32 ctr_arg = rp.Pop<u32>();
|
if (fd_info == open_sockets.end()) {
|
||||||
rp.PopPID();
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
|
|
||||||
auto socket = FindSocket(socket_handle);
|
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
u32 ctr_cmd = rp.Pop<u32>();
|
||||||
|
u32 ctr_arg = rp.Pop<u32>();
|
||||||
|
rp.PopPID();
|
||||||
|
|
||||||
// TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
|
u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
|
||||||
u32 posix_ret = 0;
|
SCOPE_EXIT({
|
||||||
switch (ctr_cmd) {
|
|
||||||
case Network::FcntlCmd::GETFL:
|
|
||||||
if (!socket->IsBlocking()) {
|
|
||||||
posix_ret |= 4; // O_NONBLOCK
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Network::FcntlCmd::SETFL:
|
|
||||||
posix_ret = static_cast<u32>(socket->SetNonBlock(ctr_arg & 4));
|
|
||||||
default:
|
|
||||||
LOG_ERROR(Service_SOC, "Unsupported command ({}) in fcntl call", ctr_cmd);
|
|
||||||
posix_ret = static_cast<u32>(Network::Errno::INVAL); // TODO: Find the correct error
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(posix_ret);
|
rb.Push(posix_ret);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ctr_cmd == 3) { // F_GETFL
|
||||||
|
posix_ret = 0;
|
||||||
|
if (GetSocketBlocking(fd_info->second) == false)
|
||||||
|
posix_ret |= 4; // O_NONBLOCK
|
||||||
|
} else if (ctr_cmd == 4) { // F_SETFL
|
||||||
|
posix_ret = SetSocketBlocking(fd_info->second, !(ctr_arg & 4));
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_SOC, "Unsupported command ({}) in fcntl call", ctr_cmd);
|
||||||
|
posix_ret = TranslateError(EINVAL); // TODO: Find the correct error
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SOC_U::Listen(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Listen(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x03, 2, 2);
|
IPC::RequestParser rp(ctx, 0x03, 2, 2);
|
||||||
const u32 socket_handle = rp.Pop<u32>();
|
u32 socket_handle = rp.Pop<u32>();
|
||||||
const u32 backlog = rp.Pop<u32>();
|
auto fd_info = open_sockets.find(socket_handle);
|
||||||
rp.PopPID();
|
if (fd_info == open_sockets.end()) {
|
||||||
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
auto socket = FindSocket(socket_handle);
|
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
u32 backlog = rp.Pop<u32>();
|
||||||
|
rp.PopPID();
|
||||||
|
|
||||||
const auto ret = socket->Listen(backlog);
|
s32 ret = ::listen(fd_info->second.socket_fd, backlog);
|
||||||
|
if (ret != 0)
|
||||||
|
ret = TranslateError(GET_ERRNO);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ret);
|
rb.Push(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(sizeof(socklen_t) == sizeof(u32), "socklen_t has incorrect size!");
|
|
||||||
|
|
||||||
void SOC_U::Accept(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Accept(Kernel::HLERequestContext& ctx) {
|
||||||
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
|
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
|
||||||
// preventing graceful shutdown when closing the emulator, this can be fixed by always
|
// preventing graceful shutdown when closing the emulator, this can be fixed by always
|
||||||
// performing nonblocking operations and spinlock until the data is available
|
// performing nonblocking operations and spinlock until the data is available
|
||||||
IPC::RequestParser rp(ctx, 0x04, 2, 2);
|
IPC::RequestParser rp(ctx, 0x04, 2, 2);
|
||||||
const auto socket_handle = rp.Pop<u32>();
|
const auto socket_handle = rp.Pop<u32>();
|
||||||
[[maybe_unused]] const auto max_addr_len = rp.Pop<socklen_t>();
|
auto fd_info = open_sockets.find(socket_handle);
|
||||||
rp.PopPID();
|
if (fd_info == open_sockets.end()) {
|
||||||
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
auto socket = FindSocket(socket_handle);
|
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
[[maybe_unused]] const auto max_addr_len = static_cast<socklen_t>(rp.Pop<u32>());
|
||||||
|
rp.PopPID();
|
||||||
|
sockaddr addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
u32 ret = static_cast<u32>(::accept(fd_info->second.socket_fd, &addr, &addr_len));
|
||||||
|
|
||||||
auto [result, err] = socket->Accept();
|
if (static_cast<s32>(ret) != SOCKET_ERROR_VALUE) {
|
||||||
|
u32 socketID = GetNextSocketID();
|
||||||
|
open_sockets[socketID] = {static_cast<decltype(SocketHolder::socket_fd)>(ret), true};
|
||||||
|
ret = socketID;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u32 size = sizeof(result.sockaddr_in);
|
CTRSockAddr ctr_addr;
|
||||||
std::vector<u8> ctr_addr_buf(size);
|
std::vector<u8> ctr_addr_buf(sizeof(ctr_addr));
|
||||||
|
if (static_cast<s32>(ret) == SOCKET_ERROR_VALUE) {
|
||||||
u32 ret = static_cast<u32>(err);
|
ret = TranslateError(GET_ERRNO);
|
||||||
if (err == Network::Errno::SUCCESS) {
|
} else {
|
||||||
const u32 socket_id = GetNextSocketID();
|
ctr_addr = CTRSockAddr::FromPlatform(addr);
|
||||||
open_sockets.emplace(socket_id, std::move(result.socket));
|
std::memcpy(ctr_addr_buf.data(), &ctr_addr, sizeof(ctr_addr));
|
||||||
std::memcpy(ctr_addr_buf.data(), &result.sockaddr_in, size);
|
|
||||||
ret = socket_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||||
@ -568,7 +899,7 @@ void SOC_U::GetHostId(Kernel::HLERequestContext& ctx) {
|
|||||||
IPC::RequestParser rp(ctx, 0x16, 0, 0);
|
IPC::RequestParser rp(ctx, 0x16, 0, 0);
|
||||||
|
|
||||||
u32 host_id = 0;
|
u32 host_id = 0;
|
||||||
const auto info = GetDefaultInterfaceInfo();
|
auto info = GetDefaultInterfaceInfo();
|
||||||
if (info.has_value()) {
|
if (info.has_value()) {
|
||||||
host_id = info->address;
|
host_id = info->address;
|
||||||
}
|
}
|
||||||
@ -580,19 +911,25 @@ void SOC_U::GetHostId(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
void SOC_U::Close(Kernel::HLERequestContext& ctx) {
|
void SOC_U::Close(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x0B, 1, 2);
|
IPC::RequestParser rp(ctx, 0x0B, 1, 2);
|
||||||
const u32 socket_handle = rp.Pop<u32>();
|
u32 socket_handle = rp.Pop<u32>();
|
||||||
rp.PopPID();
|
auto fd_info = open_sockets.find(socket_handle);
|
||||||
|
if (fd_info == open_sockets.end()) {
|
||||||
auto socket = FindSocket(socket_handle);
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rp.PopPID();
|
||||||
|
|
||||||
|
s32 ret = 0;
|
||||||
|
|
||||||
|
ret = closesocket(fd_info->second.socket_fd);
|
||||||
|
|
||||||
const auto ret = socket->Close();
|
|
||||||
open_sockets.erase(socket_handle);
|
open_sockets.erase(socket_handle);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
ret = TranslateError(GET_ERRNO);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ret);
|
rb.Push(ret);
|
||||||
@ -601,49 +938,60 @@ void SOC_U::Close(Kernel::HLERequestContext& ctx) {
|
|||||||
void SOC_U::SendToOther(Kernel::HLERequestContext& ctx) {
|
void SOC_U::SendToOther(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x09, 4, 6);
|
IPC::RequestParser rp(ctx, 0x09, 4, 6);
|
||||||
const u32 socket_handle = rp.Pop<u32>();
|
const u32 socket_handle = rp.Pop<u32>();
|
||||||
const u32 len = rp.Pop<u32>();
|
const auto fd_info = open_sockets.find(socket_handle);
|
||||||
const auto flags = rp.Pop<Network::SendFlags>();
|
if (fd_info == open_sockets.end()) {
|
||||||
const u32 addr_len = rp.Pop<u32>();
|
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", socket_handle);
|
||||||
rp.PopPID();
|
|
||||||
const auto dest_addr_buffer = rp.PopStaticBuffer();
|
|
||||||
const auto input_mapped_buff = rp.PopMappedBuffer();
|
|
||||||
|
|
||||||
auto socket = FindSocket(socket_handle);
|
|
||||||
if (!socket) {
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(ERR_INVALID_HANDLE);
|
rb.Push(ERR_INVALID_HANDLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const u32 len = rp.Pop<u32>();
|
||||||
#if WIN32
|
u32 flags = SendRecvFlagsToPlatform(rp.Pop<u32>());
|
||||||
const bool unblock = True(flags & Network::SendFlags::DONTWAIT) && socket->IsBlocking();
|
bool dont_wait = (flags & MSGCUSTOM_HANDLE_DONTWAIT) != 0;
|
||||||
if (unblock) {
|
flags &= ~MSGCUSTOM_HANDLE_DONTWAIT;
|
||||||
socket->SetNonBlock(true);
|
#ifdef _WIN32
|
||||||
|
bool was_blocking = GetSocketBlocking(fd_info->second);
|
||||||
|
if (dont_wait && was_blocking) {
|
||||||
|
SetSocketBlocking(fd_info->second, false);
|
||||||
}
|
}
|
||||||
#endif
|
#else
|
||||||
|
if (dont_wait) {
|
||||||
|
flags |= MSG_DONTWAIT;
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
const u32 addr_len = rp.Pop<u32>();
|
||||||
|
rp.PopPID();
|
||||||
|
const auto dest_addr_buffer = rp.PopStaticBuffer();
|
||||||
|
|
||||||
std::vector<u8> message(len);
|
auto input_mapped_buff = rp.PopMappedBuffer();
|
||||||
const size_t size = std::min<size_t>(input_mapped_buff.GetSize(), len);
|
std::vector<u8> input_buff(len);
|
||||||
input_mapped_buff.Read(message.data(), 0, size);
|
input_mapped_buff.Read(input_buff.data(), 0,
|
||||||
|
std::min(input_mapped_buff.GetSize(), static_cast<size_t>(len)));
|
||||||
|
|
||||||
const auto [result, err] = [&] {
|
s32 ret = -1;
|
||||||
if (addr_len > 0) {
|
if (addr_len > 0) {
|
||||||
Network::CTRSockAddr ctr_dest_addr;
|
CTRSockAddr ctr_dest_addr;
|
||||||
std::memcpy(&ctr_dest_addr, dest_addr_buffer.data(), sizeof(ctr_dest_addr));
|
std::memcpy(&ctr_dest_addr, dest_addr_buffer.data(), sizeof(ctr_dest_addr));
|
||||||
return socket->SendTo(flags, message, &ctr_dest_addr);
|
sockaddr dest_addr = CTRSockAddr::ToPlatform(ctr_dest_addr);
|
||||||
|
ret = ::sendto(fd_info->second.socket_fd, reinterpret_cast<const char*>(input_buff.data()),
|
||||||
|
len, flags, &dest_addr, sizeof(dest_addr));
|
||||||
} else {
|
} else {
|
||||||
return socket->SendTo(flags, message, nullptr);
|
ret = ::sendto(fd_info->second.socket_fd, reinterpret_cast<const char*>(input_buff.data()),
|
||||||
|
len, flags, nullptr, 0);
|
||||||
}
|
}
|
||||||
}();
|
|
||||||
|
|
||||||
const u32 ret = err != Network::Errno::SUCCESS ? static_cast<u32>(err) : result;
|
const auto send_error = (ret == SOCKET_ERROR_VALUE) ? GET_ERRNO : 0;
|
||||||
|
|
||||||
#if WIN32
|
#ifdef _WIN32
|
||||||
if (unblock) {
|
if (dont_wait && was_blocking) {
|
||||||
socket->SetNonBlock(false);
|
SetSocketBlocking(fd_info->second, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (ret == SOCKET_ERROR_VALUE) {
|
||||||
|
ret = TranslateError(send_error);
|
||||||
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(ret);
|
rb.Push(ret);
|
||||||
@ -1082,7 +1430,7 @@ void SOC_U::InitializeSockets(Kernel::HLERequestContext& ctx) {
|
|||||||
void SOC_U::ShutdownSockets(Kernel::HLERequestContext& ctx) {
|
void SOC_U::ShutdownSockets(Kernel::HLERequestContext& ctx) {
|
||||||
// TODO(Subv): Implement
|
// TODO(Subv): Implement
|
||||||
IPC::RequestParser rp(ctx, 0x19, 0, 0);
|
IPC::RequestParser rp(ctx, 0x19, 0, 0);
|
||||||
open_sockets.clear();
|
CleanupSockets();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
@ -1194,7 +1542,7 @@ void SOC_U::GetNetworkOpt(Kernel::HLERequestContext& ctx) {
|
|||||||
case NetworkOpt::NETOPT_MAC_ADDRESS: {
|
case NetworkOpt::NETOPT_MAC_ADDRESS: {
|
||||||
if (opt_len >= 6) {
|
if (opt_len >= 6) {
|
||||||
std::array<u8, 6> fake_mac = {0};
|
std::array<u8, 6> fake_mac = {0};
|
||||||
memcpy(opt_data.data(), fake_mac.data(), fake_mac.size());
|
std::memcpy(opt_data.data(), fake_mac.data(), fake_mac.size());
|
||||||
}
|
}
|
||||||
LOG_WARNING(Service_SOC, "(STUBBED) called, level={} opt_name={}", level, opt_name);
|
LOG_WARNING(Service_SOC, "(STUBBED) called, level={} opt_name={}", level, opt_name);
|
||||||
err = 0;
|
err = 0;
|
||||||
@ -1326,15 +1674,6 @@ void SOC_U::GetNameInfoImpl(Kernel::HLERequestContext& ctx) {
|
|||||||
rb.PushStaticBuffer(std::move(serv), 1);
|
rb.PushStaticBuffer(std::move(serv), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::Socket* SOC_U::FindSocket(u32 handle) {
|
|
||||||
const auto it = open_sockets.find(handle);
|
|
||||||
if (it == open_sockets.end()) {
|
|
||||||
LOG_ERROR(Service_SOC, "Invalid socket handle: {}", handle);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return it->second.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
SOC_U::SOC_U() : ServiceFramework("soc:U") {
|
SOC_U::SOC_U() : ServiceFramework("soc:U") {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -1375,9 +1714,19 @@ SOC_U::SOC_U() : ServiceFramework("soc:U") {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA data;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SOC_U::~SOC_U() = default;
|
SOC_U::~SOC_U() {
|
||||||
|
CleanupSockets();
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<SOC_U::InterfaceInfo> SOC_U::GetDefaultInterfaceInfo() {
|
std::optional<SOC_U::InterfaceInfo> SOC_U::GetDefaultInterfaceInfo() {
|
||||||
if (this->interface_info_cached) {
|
if (this->interface_info_cached) {
|
||||||
@ -1428,7 +1777,7 @@ std::optional<SOC_U::InterfaceInfo> SOC_U::GetDefaultInterfaceInfo() {
|
|||||||
int num_interfaces = bytes_used / sizeof(INTERFACE_INFO);
|
int num_interfaces = bytes_used / sizeof(INTERFACE_INFO);
|
||||||
for (int i = 0; i < num_interfaces; i++) {
|
for (int i = 0; i < num_interfaces; i++) {
|
||||||
if (((sockaddr*)&(interface_list[i].iiAddress))->sa_family == AF_INET &&
|
if (((sockaddr*)&(interface_list[i].iiAddress))->sa_family == AF_INET &&
|
||||||
memcmp(&((sockaddr_in*)&(interface_list[i].iiAddress))->sin_addr.s_addr,
|
std::memcmp(&((sockaddr_in*)&(interface_list[i].iiAddress))->sin_addr.s_addr,
|
||||||
&s_info.sin_addr.s_addr, sizeof(s_info.sin_addr.s_addr)) == 0) {
|
&s_info.sin_addr.s_addr, sizeof(s_info.sin_addr.s_addr)) == 0) {
|
||||||
ret.address = ((sockaddr_in*)&(interface_list[i].iiAddress))->sin_addr.s_addr;
|
ret.address = ((sockaddr_in*)&(interface_list[i].iiAddress))->sin_addr.s_addr;
|
||||||
ret.netmask = ((sockaddr_in*)&(interface_list[i].iiNetmask))->sin_addr.s_addr;
|
ret.netmask = ((sockaddr_in*)&(interface_list[i].iiNetmask))->sin_addr.s_addr;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <boost/serialization/unordered_map.hpp>
|
#include <boost/serialization/unordered_map.hpp>
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "core/network/sockets.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@ -17,6 +16,26 @@ class System;
|
|||||||
|
|
||||||
namespace Service::SOC {
|
namespace Service::SOC {
|
||||||
|
|
||||||
|
/// Holds information about a particular socket
|
||||||
|
struct SocketHolder {
|
||||||
|
#ifdef _WIN32
|
||||||
|
using SOCKET = unsigned long long;
|
||||||
|
SOCKET socket_fd; ///< The socket descriptor
|
||||||
|
#else
|
||||||
|
int socket_fd; ///< The socket descriptor
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
bool blocking = true; ///< Whether the socket is blocking or not.
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <class Archive>
|
||||||
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
|
ar& socket_fd;
|
||||||
|
ar& blocking;
|
||||||
|
}
|
||||||
|
friend class boost::serialization::access;
|
||||||
|
};
|
||||||
|
|
||||||
class SOC_U final : public ServiceFramework<SOC_U> {
|
class SOC_U final : public ServiceFramework<SOC_U> {
|
||||||
public:
|
public:
|
||||||
SOC_U();
|
SOC_U();
|
||||||
@ -44,8 +63,11 @@ private:
|
|||||||
|
|
||||||
static const std::unordered_map<u64, std::pair<int, int>> sockopt_map;
|
static const std::unordered_map<u64, std::pair<int, int>> sockopt_map;
|
||||||
static std::pair<int, int> TranslateSockOpt(int level, int opt);
|
static std::pair<int, int> TranslateSockOpt(int level, int opt);
|
||||||
|
bool GetSocketBlocking(const SocketHolder& socket_holder);
|
||||||
|
u32 SetSocketBlocking(SocketHolder& socket_holder, bool blocking);
|
||||||
|
|
||||||
// From https://github.com/devkitPro/libctru/blob/1de86ea3/libctru/include/3ds/services/soc.h#L15
|
// From
|
||||||
|
// https://github.com/devkitPro/libctru/blob/1de86ea38aec419744149daf692556e187d4678a/libctru/include/3ds/services/soc.h#L15
|
||||||
enum class NetworkOpt {
|
enum class NetworkOpt {
|
||||||
NETOPT_MAC_ADDRESS = 0x1004, ///< The mac address of the interface
|
NETOPT_MAC_ADDRESS = 0x1004, ///< The mac address of the interface
|
||||||
NETOPT_ARP_TABLE = 0x3002, ///< The ARP table
|
NETOPT_ARP_TABLE = 0x3002, ///< The ARP table
|
||||||
@ -101,14 +123,30 @@ private:
|
|||||||
void GetAddrInfoImpl(Kernel::HLERequestContext& ctx);
|
void GetAddrInfoImpl(Kernel::HLERequestContext& ctx);
|
||||||
void GetNameInfoImpl(Kernel::HLERequestContext& ctx);
|
void GetNameInfoImpl(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
Network::Socket* FindSocket(u32 handle);
|
// Socked ids
|
||||||
|
u32 next_socket_id = 3;
|
||||||
|
u32 GetNextSocketID() {
|
||||||
|
return next_socket_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// System timer adjust
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> adjust_value_last;
|
||||||
void PreTimerAdjust();
|
void PreTimerAdjust();
|
||||||
void PostTimerAdjust(Kernel::HLERequestContext& ctx, const std::string& caller_method);
|
void PostTimerAdjust(Kernel::HLERequestContext& ctx, const std::string& caller_method);
|
||||||
|
|
||||||
[[nodiscard]] u32 GetNextSocketID() {
|
/// Close all open sockets
|
||||||
return next_socket_id++;
|
void CleanupSockets();
|
||||||
}
|
|
||||||
|
/// Holds info about the currently open sockets
|
||||||
|
friend struct CTRPollFD;
|
||||||
|
std::unordered_map<u32, SocketHolder> open_sockets;
|
||||||
|
|
||||||
|
/// Cache interface info for the current session
|
||||||
|
/// These two fields are not saved to savestates on purpose
|
||||||
|
/// as network interfaces may change and it's better to.
|
||||||
|
/// obtain them again between play sessions.
|
||||||
|
bool interface_info_cached = false;
|
||||||
|
InterfaceInfo interface_info;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
@ -116,18 +154,6 @@ private:
|
|||||||
ar& open_sockets;
|
ar& open_sockets;
|
||||||
}
|
}
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
|
|
||||||
private:
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock> adjust_value_last;
|
|
||||||
std::unordered_map<u32, std::unique_ptr<Network::Socket>> open_sockets;
|
|
||||||
u32 next_socket_id = 3;
|
|
||||||
|
|
||||||
// Cache interface info for the current session
|
|
||||||
// These two fields are not saved to savestates on purpose
|
|
||||||
// as network interfaces may change and it's better to.
|
|
||||||
// obtain them again between play sessions.
|
|
||||||
bool interface_info_cached = false;
|
|
||||||
InterfaceInfo interface_info;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<SOC_U> GetService(Core::System& system);
|
std::shared_ptr<SOC_U> GetService(Core::System& system);
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& nonce,
|
std::vector<u8> EncryptSignCCM(std::span<const u8> pdata, const CCMNonce& nonce,
|
||||||
std::size_t slot_id) {
|
std::size_t slot_id) {
|
||||||
if (!IsNormalKeyAvailable(slot_id)) {
|
if (!IsNormalKeyAvailable(slot_id)) {
|
||||||
LOG_ERROR(HW_AES, "Key slot {} not available. Will use zero key.", slot_id);
|
LOG_ERROR(HW_AES, "Key slot {} not available. Will use zero key.", slot_id);
|
||||||
@ -63,7 +63,7 @@ std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& non
|
|||||||
return cipher;
|
return cipher;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> DecryptVerifyCCM(const std::vector<u8>& cipher, const CCMNonce& nonce,
|
std::vector<u8> DecryptVerifyCCM(std::span<const u8> cipher, const CCMNonce& nonce,
|
||||||
std::size_t slot_id) {
|
std::size_t slot_id) {
|
||||||
if (!IsNormalKeyAvailable(slot_id)) {
|
if (!IsNormalKeyAvailable(slot_id)) {
|
||||||
LOG_ERROR(HW_AES, "Key slot {} not available. Will use zero key.", slot_id);
|
LOG_ERROR(HW_AES, "Key slot {} not available. Will use zero key.", slot_id);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ using CCMNonce = std::array<u8, CCM_NONCE_SIZE>;
|
|||||||
* @param slot_id The slot ID of the key to use for encryption
|
* @param slot_id The slot ID of the key to use for encryption
|
||||||
* @returns a vector of u8 containing the encrypted data with MAC at the end
|
* @returns a vector of u8 containing the encrypted data with MAC at the end
|
||||||
*/
|
*/
|
||||||
std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& nonce,
|
std::vector<u8> EncryptSignCCM(std::span<const u8> pdata, const CCMNonce& nonce,
|
||||||
std::size_t slot_id);
|
std::size_t slot_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +34,7 @@ std::vector<u8> EncryptSignCCM(const std::vector<u8>& pdata, const CCMNonce& non
|
|||||||
* @param slot_id The slot ID of the key to use for decryption
|
* @param slot_id The slot ID of the key to use for decryption
|
||||||
* @returns a vector of u8 containing the decrypted data; an empty vector if the verification fails
|
* @returns a vector of u8 containing the decrypted data; an empty vector if the verification fails
|
||||||
*/
|
*/
|
||||||
std::vector<u8> DecryptVerifyCCM(const std::vector<u8>& cipher, const CCMNonce& nonce,
|
std::vector<u8> DecryptVerifyCCM(std::span<const u8> cipher, const CCMNonce& nonce,
|
||||||
std::size_t slot_id);
|
std::size_t slot_id);
|
||||||
|
|
||||||
} // namespace HW::AES
|
} // namespace HW::AES
|
||||||
|
@ -116,13 +116,13 @@ static void MemoryFill(const Regs::MemoryFillConfig& config) {
|
|||||||
u32 value = config.value_32bit;
|
u32 value = config.value_32bit;
|
||||||
std::size_t len = (end - start) / sizeof(u32);
|
std::size_t len = (end - start) / sizeof(u32);
|
||||||
for (std::size_t i = 0; i < len; ++i)
|
for (std::size_t i = 0; i < len; ++i)
|
||||||
memcpy(&start[i * sizeof(u32)], &value, sizeof(u32));
|
std::memcpy(&start[i * sizeof(u32)], &value, sizeof(u32));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// fill with 16-bit values
|
// fill with 16-bit values
|
||||||
u16 value_16bit = config.value_16bit.Value();
|
u16 value_16bit = config.value_16bit.Value();
|
||||||
for (u8* ptr = start; ptr < end; ptr += sizeof(u16))
|
for (u8* ptr = start; ptr < end; ptr += sizeof(u16))
|
||||||
memcpy(ptr, &value_16bit, sizeof(u16));
|
std::memcpy(ptr, &value_16bit, sizeof(u16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +521,7 @@ static void VBlankCallback(std::uintptr_t user_data, s64 cycles_late) {
|
|||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init(Memory::MemorySystem& memory) {
|
void Init(Memory::MemorySystem& memory) {
|
||||||
g_memory = &memory;
|
g_memory = &memory;
|
||||||
memset(&g_regs, 0, sizeof(g_regs));
|
std::memset(&g_regs, 0, sizeof(g_regs));
|
||||||
|
|
||||||
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
||||||
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
auto& framebuffer_sub = g_regs.framebuffer_config[1];
|
||||||
|
@ -64,7 +64,7 @@ template void Write<u8>(u32 addr, const u8 data);
|
|||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init() {
|
void Init() {
|
||||||
memset(&g_regs, 0, sizeof(g_regs));
|
std::memset(&g_regs, 0, sizeof(g_regs));
|
||||||
LOG_DEBUG(HW_LCD, "initialized OK");
|
LOG_DEBUG(HW_LCD, "initialized OK");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ std::vector<u8> HexToBytes(const std::string& hex) {
|
|||||||
constexpr std::size_t SlotSize = 4;
|
constexpr std::size_t SlotSize = 4;
|
||||||
std::array<RsaSlot, SlotSize> rsa_slots;
|
std::array<RsaSlot, SlotSize> rsa_slots;
|
||||||
|
|
||||||
std::vector<u8> RsaSlot::GetSignature(const std::vector<u8>& message) const {
|
std::vector<u8> RsaSlot::GetSignature(std::span<const u8> message) const {
|
||||||
CryptoPP::Integer sig =
|
CryptoPP::Integer sig =
|
||||||
CryptoPP::ModularExponentiation(CryptoPP::Integer(message.data(), message.size()),
|
CryptoPP::ModularExponentiation(CryptoPP::Integer(message.data(), message.size()),
|
||||||
CryptoPP::Integer(exponent.data(), exponent.size()),
|
CryptoPP::Integer(exponent.data(), exponent.size()),
|
||||||
@ -85,7 +85,7 @@ RsaSlot GetSlot(std::size_t slot_id) {
|
|||||||
return rsa_slots[slot_id];
|
return rsa_slots[slot_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> CreateASN1Message(const std::vector<u8>& data) {
|
std::vector<u8> CreateASN1Message(std::span<const u8> data) {
|
||||||
static constexpr std::array<u8, 224> asn1_header = {
|
static constexpr std::array<u8, 224> asn1_header = {
|
||||||
{0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
{0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ public:
|
|||||||
RsaSlot() = default;
|
RsaSlot() = default;
|
||||||
RsaSlot(std::vector<u8> exponent, std::vector<u8> modulus)
|
RsaSlot(std::vector<u8> exponent, std::vector<u8> modulus)
|
||||||
: init(true), exponent(std::move(exponent)), modulus(std::move(modulus)) {}
|
: init(true), exponent(std::move(exponent)), modulus(std::move(modulus)) {}
|
||||||
std::vector<u8> GetSignature(const std::vector<u8>& message) const;
|
std::vector<u8> GetSignature(std::span<const u8> message) const;
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
// TODO(B3N30): Maybe check if exponent and modulus are vailid
|
// TODO(B3N30): Maybe check if exponent and modulus are vailid
|
||||||
@ -31,6 +32,6 @@ void InitSlots();
|
|||||||
|
|
||||||
RsaSlot GetSlot(std::size_t slot_id);
|
RsaSlot GetSlot(std::size_t slot_id);
|
||||||
|
|
||||||
std::vector<u8> CreateASN1Message(const std::vector<u8>& data);
|
std::vector<u8> CreateASN1Message(std::span<const u8> data);
|
||||||
|
|
||||||
} // namespace HW::RSA
|
} // namespace HW::RSA
|
@ -149,7 +149,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr,
|
|||||||
return ERROR_READ;
|
return ERROR_READ;
|
||||||
|
|
||||||
// BSS clear
|
// BSS clear
|
||||||
memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
|
std::memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
|
||||||
|
|
||||||
// Relocate the segments
|
// Relocate the segments
|
||||||
for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
|
for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
|
||||||
|
@ -327,7 +327,7 @@ std::shared_ptr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
|
|||||||
codeset_segment->addr = segment_addr;
|
codeset_segment->addr = segment_addr;
|
||||||
codeset_segment->size = aligned_size;
|
codeset_segment->size = aligned_size;
|
||||||
|
|
||||||
memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz);
|
std::memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz);
|
||||||
current_image_position += aligned_size;
|
current_image_position += aligned_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ void AppLoader_NCCH::ParseRegionLockoutInfo(u64 program_id) {
|
|||||||
std::vector<u8> smdh_buffer;
|
std::vector<u8> smdh_buffer;
|
||||||
if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) {
|
if (ReadIcon(smdh_buffer) == ResultStatus::Success && smdh_buffer.size() >= sizeof(SMDH)) {
|
||||||
SMDH smdh;
|
SMDH smdh;
|
||||||
memcpy(&smdh, smdh_buffer.data(), sizeof(SMDH));
|
std::memcpy(&smdh, smdh_buffer.data(), sizeof(SMDH));
|
||||||
u32 region_lockout = smdh.region_lockout;
|
u32 region_lockout = smdh.region_lockout;
|
||||||
constexpr u32 REGION_COUNT = 7;
|
constexpr u32 REGION_COUNT = 7;
|
||||||
std::vector<u32> regions;
|
std::vector<u32> regions;
|
||||||
@ -185,15 +185,20 @@ void AppLoader_NCCH::ParseRegionLockoutInfo(u64 program_id) {
|
|||||||
} else {
|
} else {
|
||||||
const auto region = Core::GetSystemTitleRegion(program_id);
|
const auto region = Core::GetSystemTitleRegion(program_id);
|
||||||
if (region.has_value()) {
|
if (region.has_value()) {
|
||||||
cfg->SetPreferredRegionCodes({region.value()});
|
const std::array regions{region.value()};
|
||||||
|
cfg->SetPreferredRegionCodes(regions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppLoader_NCCH::IsGbaVirtualConsole(const std::vector<u8>& code) {
|
bool AppLoader_NCCH::IsGbaVirtualConsole(std::span<const u8> code) {
|
||||||
const u32* gbaVcHeader = reinterpret_cast<const u32*>(code.data() + code.size() - 0x10);
|
if (code.size() < 0x10) [[unlikely]] {
|
||||||
return code.size() >= 0x10 && gbaVcHeader[0] == MakeMagic('.', 'C', 'A', 'A') &&
|
return false;
|
||||||
gbaVcHeader[1] == 1;
|
}
|
||||||
|
|
||||||
|
u32 gbaVcHeader[2];
|
||||||
|
std::memcpy(gbaVcHeader, code.data() + code.size() - 0x10, sizeof(gbaVcHeader));
|
||||||
|
return gbaVcHeader[0] == MakeMagic('.', 'C', 'A', 'A') && gbaVcHeader[1] == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
|
ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||||
@ -317,7 +322,7 @@ ResultStatus AppLoader_NCCH::ReadTitle(std::string& title) {
|
|||||||
return ResultStatus::ErrorInvalidFormat;
|
return ResultStatus::ErrorInvalidFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&smdh, data.data(), sizeof(Loader::SMDH));
|
std::memcpy(&smdh, data.data(), sizeof(Loader::SMDH));
|
||||||
|
|
||||||
const auto& short_title = smdh.GetShortTitle(SMDH::TitleLanguage::English);
|
const auto& short_title = smdh.GetShortTitle(SMDH::TitleLanguage::English);
|
||||||
auto title_end = std::find(short_title.begin(), short_title.end(), u'\0');
|
auto title_end = std::find(short_title.begin(), short_title.end(), u'\0');
|
||||||
|
@ -78,7 +78,7 @@ private:
|
|||||||
void ParseRegionLockoutInfo(u64 program_id);
|
void ParseRegionLockoutInfo(u64 program_id);
|
||||||
|
|
||||||
/// Detects whether the NCCH contains GBA Virtual Console.
|
/// Detects whether the NCCH contains GBA Virtual Console.
|
||||||
bool IsGbaVirtualConsole(const std::vector<u8>& code);
|
bool IsGbaVirtualConsole(std::span<const u8> code);
|
||||||
|
|
||||||
FileSys::NCCHContainer base_ncch;
|
FileSys::NCCHContainer base_ncch;
|
||||||
FileSys::NCCHContainer update_ncch;
|
FileSys::NCCHContainer update_ncch;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user