Compare commits

..

6 Commits

Author SHA1 Message Date
Lioncash
1342c53e27 loader: Remove Linker class
Given the class is now currently unused, it can be removed.
2019-03-19 21:32:02 -04:00
Lioncash
ab00552118 loader: Remove Linker inheritance from NRO and NSO loaders
Neither the NRO or NSO loaders actually make use of the functions or
members provided by the Linker interface, so we can just remove the
inheritance altogether.
2019-03-19 21:31:59 -04:00
bunnei
746167f11a Merge pull request #2258 from lioncash/am
service/am: Supply remaining missing IAudioController functions
2019-03-18 22:20:36 -04:00
Lioncash
26b809549b service/am: Add basic implementation of ChangeMainAppletMasterVolume
All this does is supply a new volume level and a fade time in
nanoseconds for the volume transition to occur within.
2019-03-18 09:18:34 -04:00
Lioncash
c07ebeac19 service/am: Unstub SetTransparentVolumeRate()
Like the other volume setter, this mainly just sets a data member within
the service, nothing too special.
2019-03-18 09:18:34 -04:00
Lioncash
ecd3afdc8e service/am: Unstub SetExpectedMasterVolume()
This function passes in the desired main applet and library applet
volume levels. We can then just pass those values back within the
relevant volume getter functions, allowing us to unstub those as well.

The initial values for the library and main applet volumes differ. The
main applet volume is 0.25 by default, while the library applet volume
is initialized to 1.0 by default in the services themselves.
2019-03-18 09:18:34 -04:00
10 changed files with 89 additions and 216 deletions

View File

@@ -419,8 +419,6 @@ add_library(core STATIC
loader/deconstructed_rom_directory.h
loader/elf.cpp
loader/elf.h
loader/linker.cpp
loader/linker.h
loader/loader.cpp
loader/loader.h
loader/nax.cpp

View File

@@ -2,10 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstring>
#include <stack>
#include "audio_core/audio_renderer.h"
#include "core/core.h"
#include "core/file_sys/savedata_factory.h"
@@ -93,38 +93,84 @@ void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx)
}
IAudioController::IAudioController() : ServiceFramework("IAudioController") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
{1, &IAudioController::GetMainAppletExpectedMasterVolume,
"GetMainAppletExpectedMasterVolume"},
{2, &IAudioController::GetLibraryAppletExpectedMasterVolume,
"GetLibraryAppletExpectedMasterVolume"},
{3, nullptr, "ChangeMainAppletMasterVolume"},
{4, nullptr, "SetTransparentVolumeRate"},
{1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
{2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
{3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
{4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
};
// clang-format on
RegisterHandlers(functions);
}
IAudioController::~IAudioController() = default;
void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const float main_applet_volume_tmp = rp.Pop<float>();
const float library_applet_volume_tmp = rp.Pop<float>();
LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
main_applet_volume_tmp, library_applet_volume_tmp);
// Ensure the volume values remain within the 0-100% range
main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
library_applet_volume =
std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(volume);
rb.Push(main_applet_volume);
}
void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(volume);
rb.Push(library_applet_volume);
}
void IAudioController::ChangeMainAppletMasterVolume(Kernel::HLERequestContext& ctx) {
struct Parameters {
float volume;
s64 fade_time_ns;
};
static_assert(sizeof(Parameters) == 16);
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
parameters.fade_time_ns);
main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void IAudioController::SetTransparentAudioRate(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const float transparent_volume_rate_tmp = rp.Pop<float>();
LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
// Clamp volume range to 0-100%.
transparent_volume_rate =
std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {

View File

@@ -4,6 +4,7 @@
#pragma once
#include <chrono>
#include <memory>
#include <queue>
#include "core/hle/kernel/writable_event.h"
@@ -81,8 +82,21 @@ private:
void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx);
void GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx);
void GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx);
void ChangeMainAppletMasterVolume(Kernel::HLERequestContext& ctx);
void SetTransparentAudioRate(Kernel::HLERequestContext& ctx);
u32 volume{100};
static constexpr float min_allowed_volume = 0.0f;
static constexpr float max_allowed_volume = 1.0f;
float main_applet_volume{0.25f};
float library_applet_volume{max_allowed_volume};
float transparent_volume_rate{min_allowed_volume};
// Volume transition fade time in nanoseconds.
// e.g. If the main applet volume was 0% and was changed to 50%
// with a fade of 50ns, then over the course of 50ns,
// the volume will gradually fade up to 50%
std::chrono::nanoseconds fade_time_ns{0};
};
class IDisplayController final : public ServiceFramework<IDisplayController> {

View File

@@ -1,147 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <vector>
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/swap.h"
#include "core/loader/linker.h"
#include "core/memory.h"
namespace Loader {
enum class RelocationType : u32 { ABS64 = 257, GLOB_DAT = 1025, JUMP_SLOT = 1026, RELATIVE = 1027 };
enum DynamicType : u32 {
DT_NULL = 0,
DT_PLTRELSZ = 2,
DT_STRTAB = 5,
DT_SYMTAB = 6,
DT_RELA = 7,
DT_RELASZ = 8,
DT_STRSZ = 10,
DT_JMPREL = 23,
};
struct Elf64_Rela {
u64_le offset;
RelocationType type;
u32_le symbol;
s64_le addend;
};
static_assert(sizeof(Elf64_Rela) == 0x18, "Elf64_Rela has incorrect size.");
struct Elf64_Dyn {
u64_le tag;
u64_le value;
};
static_assert(sizeof(Elf64_Dyn) == 0x10, "Elf64_Dyn has incorrect size.");
struct Elf64_Sym {
u32_le name;
INSERT_PADDING_BYTES(0x2);
u16_le shndx;
u64_le value;
u64_le size;
};
static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size.");
void Linker::WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols,
u64 relocation_offset, u64 size, VAddr load_base) {
for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) {
Elf64_Rela rela;
std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela));
const Symbol& symbol = symbols[rela.symbol];
switch (rela.type) {
case RelocationType::RELATIVE: {
const u64 value = load_base + rela.addend;
if (!symbol.name.empty()) {
exports[symbol.name] = value;
}
std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
break;
}
case RelocationType::JUMP_SLOT:
case RelocationType::GLOB_DAT:
if (!symbol.value) {
imports[symbol.name] = {rela.offset + load_base, 0};
} else {
exports[symbol.name] = symbol.value;
std::memcpy(&program_image[rela.offset], &symbol.value, sizeof(u64));
}
break;
case RelocationType::ABS64:
if (!symbol.value) {
imports[symbol.name] = {rela.offset + load_base, rela.addend};
} else {
const u64 value = symbol.value + rela.addend;
exports[symbol.name] = value;
std::memcpy(&program_image[rela.offset], &value, sizeof(u64));
}
break;
default:
LOG_CRITICAL(Loader, "Unknown relocation type: {}", static_cast<int>(rela.type));
break;
}
}
}
void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base) {
std::map<u64, u64> dynamic;
while (dynamic_section_offset < program_image.size()) {
Elf64_Dyn dyn;
std::memcpy(&dyn, &program_image[dynamic_section_offset], sizeof(Elf64_Dyn));
dynamic_section_offset += sizeof(Elf64_Dyn);
if (dyn.tag == DT_NULL) {
break;
}
dynamic[dyn.tag] = dyn.value;
}
u64 offset = dynamic[DT_SYMTAB];
std::vector<Symbol> symbols;
while (offset < program_image.size()) {
Elf64_Sym sym;
std::memcpy(&sym, &program_image[offset], sizeof(Elf64_Sym));
offset += sizeof(Elf64_Sym);
if (sym.name >= dynamic[DT_STRSZ]) {
break;
}
std::string name = reinterpret_cast<char*>(&program_image[dynamic[DT_STRTAB] + sym.name]);
if (sym.value) {
exports[name] = load_base + sym.value;
symbols.emplace_back(std::move(name), load_base + sym.value);
} else {
symbols.emplace_back(std::move(name), 0);
}
}
if (dynamic.find(DT_RELA) != dynamic.end()) {
WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], load_base);
}
if (dynamic.find(DT_JMPREL) != dynamic.end()) {
WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ],
load_base);
}
}
void Linker::ResolveImports() {
// Resolve imports
for (const auto& import : imports) {
const auto& search = exports.find(import.first);
if (search != exports.end()) {
Memory::Write64(import.second.ea, search->second + import.second.addend);
} else {
LOG_ERROR(Loader, "Unresolved import: {}", import.first);
}
}
}
} // namespace Loader

View File

@@ -1,36 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <string>
#include "common/common_types.h"
namespace Loader {
class Linker {
protected:
struct Symbol {
Symbol(std::string&& name, u64 value) : name(std::move(name)), value(value) {}
std::string name;
u64 value;
};
struct Import {
VAddr ea;
s64 addend;
};
void WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols,
u64 relocation_offset, u64 size, VAddr load_base);
void Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base);
void ResolveImports();
std::map<std::string, Import> imports;
std::map<std::string, VAddr> exports;
};
} // namespace Loader

View File

@@ -4,10 +4,10 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
namespace FileSys {
@@ -21,7 +21,7 @@ class Process;
namespace Loader {
/// Loads an NRO file
class AppLoader_NRO final : public AppLoader, Linker {
class AppLoader_NRO final : public AppLoader {
public:
explicit AppLoader_NRO(FileSys::VirtualFile file);
~AppLoader_NRO() override;

View File

@@ -6,8 +6,8 @@
#include <optional>
#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/patch_manager.h"
#include "core/loader/linker.h"
#include "core/loader/loader.h"
namespace Kernel {
@@ -26,7 +26,7 @@ struct NSOArgumentHeader {
static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrect size.");
/// Loads an NSO file
class AppLoader_NSO final : public AppLoader, Linker {
class AppLoader_NSO final : public AppLoader {
public:
explicit AppLoader_NSO(FileSys::VirtualFile file);

View File

@@ -24,19 +24,17 @@ namespace InputCommon::SDL {
class State {
public:
using Pollers = std::vector<std::unique_ptr<Polling::DevicePoller>>;
/// Unregisters SDL device factories and shut them down.
/// Unresisters SDL device factories and shut them down.
virtual ~State() = default;
virtual Pollers GetPollers(Polling::DeviceType type) = 0;
virtual std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers(
InputCommon::Polling::DeviceType type) = 0;
};
class NullState : public State {
public:
Pollers GetPollers(Polling::DeviceType type) override {
return {};
}
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers(
InputCommon::Polling::DeviceType type) override {}
};
std::unique_ptr<State> Init();

View File

@@ -650,9 +650,9 @@ private:
};
} // namespace Polling
SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
Pollers pollers;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers(
InputCommon::Polling::DeviceType type) {
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers;
switch (type) {
case InputCommon::Polling::DeviceType::Analog:
pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
@@ -660,9 +660,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
case InputCommon::Polling::DeviceType::Button:
pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
break;
return pollers;
}
return pollers;
}
} // namespace SDL

View File

@@ -25,7 +25,7 @@ public:
/// Initializes and registers SDL device factories
SDLState();
/// Unregisters SDL device factories and shut them down.
/// Unresisters SDL device factories and shut them down.
~SDLState() override;
/// Handle SDL_Events for joysticks from SDL_PollEvent
@@ -35,7 +35,8 @@ public:
std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
/// Get all DevicePoller that use the SDL backend for a specific device type
Pollers GetPollers(Polling::DeviceType type) override;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers(
InputCommon::Polling::DeviceType type) override;
/// Used by the Pollers during config
std::atomic<bool> polling = false;