diff options
| -rw-r--r-- | src/common/thread_queue_list.h | 6 | ||||
| -rw-r--r-- | src/common/uint128.cpp | 4 | ||||
| -rw-r--r-- | src/common/uint128.h | 5 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/code_set.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/code_set.h | 90 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 43 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/audio/hwopus.cpp | 82 | ||||
| -rw-r--r-- | src/core/loader/elf.cpp | 1 | ||||
| -rw-r--r-- | src/core/loader/linker.cpp | 147 | ||||
| -rw-r--r-- | src/core/loader/linker.h | 36 | ||||
| -rw-r--r-- | src/core/loader/nro.cpp | 1 | ||||
| -rw-r--r-- | src/core/loader/nro.h | 4 | ||||
| -rw-r--r-- | src/core/loader/nso.cpp | 1 | ||||
| -rw-r--r-- | src/core/loader/nso.h | 4 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 4 |
19 files changed, 180 insertions, 277 deletions
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h index e7594db68..791f99a8c 100644 --- a/src/common/thread_queue_list.h +++ b/src/common/thread_queue_list.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <deque> | 8 | #include <deque> |
| 9 | #include <boost/range/algorithm_ext/erase.hpp> | ||
| 10 | 9 | ||
| 11 | namespace Common { | 10 | namespace Common { |
| 12 | 11 | ||
| @@ -111,8 +110,9 @@ struct ThreadQueueList { | |||
| 111 | } | 110 | } |
| 112 | 111 | ||
| 113 | void remove(Priority priority, const T& thread_id) { | 112 | void remove(Priority priority, const T& thread_id) { |
| 114 | Queue* cur = &queues[priority]; | 113 | Queue* const cur = &queues[priority]; |
| 115 | boost::remove_erase(cur->data, thread_id); | 114 | const auto iter = std::remove(cur->data.begin(), cur->data.end(), thread_id); |
| 115 | cur->data.erase(iter, cur->data.end()); | ||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | void rotate(Priority priority) { | 118 | void rotate(Priority priority) { |
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp index 2238a52c5..32bf56730 100644 --- a/src/common/uint128.cpp +++ b/src/common/uint128.cpp | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 1 | #ifdef _MSC_VER | 5 | #ifdef _MSC_VER |
| 2 | #include <intrin.h> | 6 | #include <intrin.h> |
| 3 | 7 | ||
diff --git a/src/common/uint128.h b/src/common/uint128.h index 52e6b46eb..a3be2a2cb 100644 --- a/src/common/uint128.h +++ b/src/common/uint128.h | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 1 | 6 | ||
| 2 | #include <utility> | 7 | #include <utility> |
| 3 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index aee8bc27d..16920e2e9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -107,6 +107,8 @@ add_library(core STATIC | |||
| 107 | hle/kernel/client_port.h | 107 | hle/kernel/client_port.h |
| 108 | hle/kernel/client_session.cpp | 108 | hle/kernel/client_session.cpp |
| 109 | hle/kernel/client_session.h | 109 | hle/kernel/client_session.h |
| 110 | hle/kernel/code_set.cpp | ||
| 111 | hle/kernel/code_set.h | ||
| 110 | hle/kernel/errors.h | 112 | hle/kernel/errors.h |
| 111 | hle/kernel/handle_table.cpp | 113 | hle/kernel/handle_table.cpp |
| 112 | hle/kernel/handle_table.h | 114 | hle/kernel/handle_table.h |
| @@ -419,8 +421,6 @@ add_library(core STATIC | |||
| 419 | loader/deconstructed_rom_directory.h | 421 | loader/deconstructed_rom_directory.h |
| 420 | loader/elf.cpp | 422 | loader/elf.cpp |
| 421 | loader/elf.h | 423 | loader/elf.h |
| 422 | loader/linker.cpp | ||
| 423 | loader/linker.h | ||
| 424 | loader/loader.cpp | 424 | loader/loader.cpp |
| 425 | loader/loader.h | 425 | loader/loader.h |
| 426 | loader/nax.cpp | 426 | loader/nax.cpp |
diff --git a/src/core/hle/kernel/code_set.cpp b/src/core/hle/kernel/code_set.cpp new file mode 100644 index 000000000..1f434e9af --- /dev/null +++ b/src/core/hle/kernel/code_set.cpp | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/code_set.h" | ||
| 6 | |||
| 7 | namespace Kernel { | ||
| 8 | |||
| 9 | CodeSet::CodeSet() = default; | ||
| 10 | CodeSet::~CodeSet() = default; | ||
| 11 | |||
| 12 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h new file mode 100644 index 000000000..834fd23d2 --- /dev/null +++ b/src/core/hle/kernel/code_set.h | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Represents executable data that may be loaded into a kernel process. | ||
| 17 | * | ||
| 18 | * A code set consists of three basic segments: | ||
| 19 | * - A code (AKA text) segment, | ||
| 20 | * - A read-only data segment (rodata) | ||
| 21 | * - A data segment | ||
| 22 | * | ||
| 23 | * The code segment is the portion of the object file that contains | ||
| 24 | * executable instructions. | ||
| 25 | * | ||
| 26 | * The read-only data segment in the portion of the object file that | ||
| 27 | * contains (as one would expect) read-only data, such as fixed constant | ||
| 28 | * values and data structures. | ||
| 29 | * | ||
| 30 | * The data segment is similar to the read-only data segment -- it contains | ||
| 31 | * variables and data structures that have predefined values, however, | ||
| 32 | * entities within this segment can be modified. | ||
| 33 | */ | ||
| 34 | struct CodeSet final { | ||
| 35 | /// A single segment within a code set. | ||
| 36 | struct Segment final { | ||
| 37 | /// The byte offset that this segment is located at. | ||
| 38 | std::size_t offset = 0; | ||
| 39 | |||
| 40 | /// The address to map this segment to. | ||
| 41 | VAddr addr = 0; | ||
| 42 | |||
| 43 | /// The size of this segment in bytes. | ||
| 44 | u32 size = 0; | ||
| 45 | }; | ||
| 46 | |||
| 47 | explicit CodeSet(); | ||
| 48 | ~CodeSet(); | ||
| 49 | |||
| 50 | CodeSet(const CodeSet&) = delete; | ||
| 51 | CodeSet& operator=(const CodeSet&) = delete; | ||
| 52 | |||
| 53 | CodeSet(CodeSet&&) = default; | ||
| 54 | CodeSet& operator=(CodeSet&&) = default; | ||
| 55 | |||
| 56 | Segment& CodeSegment() { | ||
| 57 | return segments[0]; | ||
| 58 | } | ||
| 59 | |||
| 60 | const Segment& CodeSegment() const { | ||
| 61 | return segments[0]; | ||
| 62 | } | ||
| 63 | |||
| 64 | Segment& RODataSegment() { | ||
| 65 | return segments[1]; | ||
| 66 | } | ||
| 67 | |||
| 68 | const Segment& RODataSegment() const { | ||
| 69 | return segments[1]; | ||
| 70 | } | ||
| 71 | |||
| 72 | Segment& DataSegment() { | ||
| 73 | return segments[2]; | ||
| 74 | } | ||
| 75 | |||
| 76 | const Segment& DataSegment() const { | ||
| 77 | return segments[2]; | ||
| 78 | } | ||
| 79 | |||
| 80 | /// The overall data that backs this code set. | ||
| 81 | std::shared_ptr<std::vector<u8>> memory; | ||
| 82 | |||
| 83 | /// The segments that comprise this code set. | ||
| 84 | std::array<Segment, 3> segments; | ||
| 85 | |||
| 86 | /// The entry point address for this code set. | ||
| 87 | VAddr entrypoint = 0; | ||
| 88 | }; | ||
| 89 | |||
| 90 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 65c51003d..15a16ae14 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/file_sys/program_metadata.h" | 11 | #include "core/file_sys/program_metadata.h" |
| 12 | #include "core/hle/kernel/code_set.h" | ||
| 12 | #include "core/hle/kernel/errors.h" | 13 | #include "core/hle/kernel/errors.h" |
| 13 | #include "core/hle/kernel/kernel.h" | 14 | #include "core/hle/kernel/kernel.h" |
| 14 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| @@ -50,9 +51,6 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_poi | |||
| 50 | } | 51 | } |
| 51 | } // Anonymous namespace | 52 | } // Anonymous namespace |
| 52 | 53 | ||
| 53 | CodeSet::CodeSet() = default; | ||
| 54 | CodeSet::~CodeSet() = default; | ||
| 55 | |||
| 56 | SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { | 54 | SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { |
| 57 | auto& kernel = system.Kernel(); | 55 | auto& kernel = system.Kernel(); |
| 58 | 56 | ||
| @@ -212,7 +210,7 @@ void Process::FreeTLSSlot(VAddr tls_address) { | |||
| 212 | } | 210 | } |
| 213 | 211 | ||
| 214 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { | 212 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { |
| 215 | const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, | 213 | const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions, |
| 216 | MemoryState memory_state) { | 214 | MemoryState memory_state) { |
| 217 | const auto vma = vm_manager | 215 | const auto vma = vm_manager |
| 218 | .MapMemoryBlock(segment.addr + base_addr, module_.memory, | 216 | .MapMemoryBlock(segment.addr + base_addr, module_.memory, |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 47ffd4ad3..3ae7c922c 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <bitset> | 8 | #include <bitset> |
| 9 | #include <cstddef> | 9 | #include <cstddef> |
| 10 | #include <memory> | ||
| 11 | #include <string> | 10 | #include <string> |
| 12 | #include <vector> | 11 | #include <vector> |
| 13 | #include <boost/container/static_vector.hpp> | 12 | #include <boost/container/static_vector.hpp> |
| @@ -33,6 +32,8 @@ class KernelCore; | |||
| 33 | class ResourceLimit; | 32 | class ResourceLimit; |
| 34 | class Thread; | 33 | class Thread; |
| 35 | 34 | ||
| 35 | struct CodeSet; | ||
| 36 | |||
| 36 | struct AddressMapping { | 37 | struct AddressMapping { |
| 37 | // Address and size must be page-aligned | 38 | // Address and size must be page-aligned |
| 38 | VAddr address; | 39 | VAddr address; |
| @@ -65,46 +66,6 @@ enum class ProcessStatus { | |||
| 65 | DebugBreak, | 66 | DebugBreak, |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | struct CodeSet final { | ||
| 69 | struct Segment { | ||
| 70 | std::size_t offset = 0; | ||
| 71 | VAddr addr = 0; | ||
| 72 | u32 size = 0; | ||
| 73 | }; | ||
| 74 | |||
| 75 | explicit CodeSet(); | ||
| 76 | ~CodeSet(); | ||
| 77 | |||
| 78 | Segment& CodeSegment() { | ||
| 79 | return segments[0]; | ||
| 80 | } | ||
| 81 | |||
| 82 | const Segment& CodeSegment() const { | ||
| 83 | return segments[0]; | ||
| 84 | } | ||
| 85 | |||
| 86 | Segment& RODataSegment() { | ||
| 87 | return segments[1]; | ||
| 88 | } | ||
| 89 | |||
| 90 | const Segment& RODataSegment() const { | ||
| 91 | return segments[1]; | ||
| 92 | } | ||
| 93 | |||
| 94 | Segment& DataSegment() { | ||
| 95 | return segments[2]; | ||
| 96 | } | ||
| 97 | |||
| 98 | const Segment& DataSegment() const { | ||
| 99 | return segments[2]; | ||
| 100 | } | ||
| 101 | |||
| 102 | std::shared_ptr<std::vector<u8>> memory; | ||
| 103 | |||
| 104 | std::array<Segment, 3> segments; | ||
| 105 | VAddr entrypoint = 0; | ||
| 106 | }; | ||
| 107 | |||
| 108 | class Process final : public WaitObject { | 69 | class Process final : public WaitObject { |
| 109 | public: | 70 | public: |
| 110 | enum : u64 { | 71 | enum : u64 { |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d9ffebc3f..3b22e8e0d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -314,8 +314,9 @@ void Thread::UpdatePriority() { | |||
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | // Ensure that the thread is within the correct location in the waiting list. | 316 | // Ensure that the thread is within the correct location in the waiting list. |
| 317 | auto old_owner = lock_owner; | ||
| 317 | lock_owner->RemoveMutexWaiter(this); | 318 | lock_owner->RemoveMutexWaiter(this); |
| 318 | lock_owner->AddMutexWaiter(this); | 319 | old_owner->AddMutexWaiter(this); |
| 319 | 320 | ||
| 320 | // Recursively update the priority of the thread that depends on the priority of this one. | 321 | // Recursively update the priority of the thread that depends on the priority of this one. |
| 321 | lock_owner->UpdatePriority(); | 322 | lock_owner->UpdatePriority(); |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 377e12cfa..cb4a1160d 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <vector> | 8 | #include <vector> |
| 9 | 9 | ||
| 10 | #include <opus.h> | 10 | #include <opus.h> |
| 11 | #include <opus_multistream.h> | ||
| 11 | 12 | ||
| 12 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| @@ -18,12 +19,12 @@ | |||
| 18 | namespace Service::Audio { | 19 | namespace Service::Audio { |
| 19 | namespace { | 20 | namespace { |
| 20 | struct OpusDeleter { | 21 | struct OpusDeleter { |
| 21 | void operator()(void* ptr) const { | 22 | void operator()(OpusMSDecoder* ptr) const { |
| 22 | operator delete(ptr); | 23 | opus_multistream_decoder_destroy(ptr); |
| 23 | } | 24 | } |
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 26 | using OpusDecoderPtr = std::unique_ptr<OpusDecoder, OpusDeleter>; | 27 | using OpusDecoderPtr = std::unique_ptr<OpusMSDecoder, OpusDeleter>; |
| 27 | 28 | ||
| 28 | struct OpusPacketHeader { | 29 | struct OpusPacketHeader { |
| 29 | // Packet size in bytes. | 30 | // Packet size in bytes. |
| @@ -33,7 +34,7 @@ struct OpusPacketHeader { | |||
| 33 | }; | 34 | }; |
| 34 | static_assert(sizeof(OpusPacketHeader) == 0x8, "OpusHeader is an invalid size"); | 35 | static_assert(sizeof(OpusPacketHeader) == 0x8, "OpusHeader is an invalid size"); |
| 35 | 36 | ||
| 36 | class OpusDecoderStateBase { | 37 | class OpusDecoderState { |
| 37 | public: | 38 | public: |
| 38 | /// Describes extra behavior that may be asked of the decoding context. | 39 | /// Describes extra behavior that may be asked of the decoding context. |
| 39 | enum class ExtraBehavior { | 40 | enum class ExtraBehavior { |
| @@ -49,22 +50,13 @@ public: | |||
| 49 | Enabled, | 50 | Enabled, |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 52 | virtual ~OpusDecoderStateBase() = default; | ||
| 53 | |||
| 54 | // Decodes interleaved Opus packets. Optionally allows reporting time taken to | ||
| 55 | // perform the decoding, as well as any relevant extra behavior. | ||
| 56 | virtual void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, | ||
| 57 | ExtraBehavior extra_behavior) = 0; | ||
| 58 | }; | ||
| 59 | |||
| 60 | // Represents the decoder state for a non-multistream decoder. | ||
| 61 | class OpusDecoderState final : public OpusDecoderStateBase { | ||
| 62 | public: | ||
| 63 | explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) | 53 | explicit OpusDecoderState(OpusDecoderPtr decoder, u32 sample_rate, u32 channel_count) |
| 64 | : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} | 54 | : decoder{std::move(decoder)}, sample_rate{sample_rate}, channel_count{channel_count} {} |
| 65 | 55 | ||
| 56 | // Decodes interleaved Opus packets. Optionally allows reporting time taken to | ||
| 57 | // perform the decoding, as well as any relevant extra behavior. | ||
| 66 | void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, | 58 | void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time, |
| 67 | ExtraBehavior extra_behavior) override { | 59 | ExtraBehavior extra_behavior) { |
| 68 | if (perf_time == PerfTime::Disabled) { | 60 | if (perf_time == PerfTime::Disabled) { |
| 69 | DecodeInterleavedHelper(ctx, nullptr, extra_behavior); | 61 | DecodeInterleavedHelper(ctx, nullptr, extra_behavior); |
| 70 | } else { | 62 | } else { |
| @@ -135,7 +127,7 @@ private: | |||
| 135 | 127 | ||
| 136 | const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); | 128 | const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); |
| 137 | const auto out_sample_count = | 129 | const auto out_sample_count = |
| 138 | opus_decode(decoder.get(), frame, hdr.size, output.data(), frame_size, 0); | 130 | opus_multistream_decode(decoder.get(), frame, hdr.size, output.data(), frame_size, 0); |
| 139 | if (out_sample_count < 0) { | 131 | if (out_sample_count < 0) { |
| 140 | LOG_ERROR(Audio, | 132 | LOG_ERROR(Audio, |
| 141 | "Incorrect sample count received from opus_decode, " | 133 | "Incorrect sample count received from opus_decode, " |
| @@ -158,7 +150,7 @@ private: | |||
| 158 | void ResetDecoderContext() { | 150 | void ResetDecoderContext() { |
| 159 | ASSERT(decoder != nullptr); | 151 | ASSERT(decoder != nullptr); |
| 160 | 152 | ||
| 161 | opus_decoder_ctl(decoder.get(), OPUS_RESET_STATE); | 153 | opus_multistream_decoder_ctl(decoder.get(), OPUS_RESET_STATE); |
| 162 | } | 154 | } |
| 163 | 155 | ||
| 164 | OpusDecoderPtr decoder; | 156 | OpusDecoderPtr decoder; |
| @@ -168,7 +160,7 @@ private: | |||
| 168 | 160 | ||
| 169 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { | 161 | class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { |
| 170 | public: | 162 | public: |
| 171 | explicit IHardwareOpusDecoderManager(std::unique_ptr<OpusDecoderStateBase> decoder_state) | 163 | explicit IHardwareOpusDecoderManager(OpusDecoderState decoder_state) |
| 172 | : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { | 164 | : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { |
| 173 | // clang-format off | 165 | // clang-format off |
| 174 | static const FunctionInfo functions[] = { | 166 | static const FunctionInfo functions[] = { |
| @@ -190,35 +182,51 @@ private: | |||
| 190 | void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) { | 182 | void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) { |
| 191 | LOG_DEBUG(Audio, "called"); | 183 | LOG_DEBUG(Audio, "called"); |
| 192 | 184 | ||
| 193 | decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Disabled, | 185 | decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Disabled, |
| 194 | OpusDecoderStateBase::ExtraBehavior::None); | 186 | OpusDecoderState::ExtraBehavior::None); |
| 195 | } | 187 | } |
| 196 | 188 | ||
| 197 | void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) { | 189 | void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) { |
| 198 | LOG_DEBUG(Audio, "called"); | 190 | LOG_DEBUG(Audio, "called"); |
| 199 | 191 | ||
| 200 | decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, | 192 | decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, |
| 201 | OpusDecoderStateBase::ExtraBehavior::None); | 193 | OpusDecoderState::ExtraBehavior::None); |
| 202 | } | 194 | } |
| 203 | 195 | ||
| 204 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { | 196 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { |
| 205 | LOG_DEBUG(Audio, "called"); | 197 | LOG_DEBUG(Audio, "called"); |
| 206 | 198 | ||
| 207 | IPC::RequestParser rp{ctx}; | 199 | IPC::RequestParser rp{ctx}; |
| 208 | const auto extra_behavior = rp.Pop<bool>() | 200 | const auto extra_behavior = rp.Pop<bool>() ? OpusDecoderState::ExtraBehavior::ResetContext |
| 209 | ? OpusDecoderStateBase::ExtraBehavior::ResetContext | 201 | : OpusDecoderState::ExtraBehavior::None; |
| 210 | : OpusDecoderStateBase::ExtraBehavior::None; | ||
| 211 | 202 | ||
| 212 | decoder_state->DecodeInterleaved(ctx, OpusDecoderStateBase::PerfTime::Enabled, | 203 | decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled, extra_behavior); |
| 213 | extra_behavior); | ||
| 214 | } | 204 | } |
| 215 | 205 | ||
| 216 | std::unique_ptr<OpusDecoderStateBase> decoder_state; | 206 | OpusDecoderState decoder_state; |
| 217 | }; | 207 | }; |
| 218 | 208 | ||
| 219 | std::size_t WorkerBufferSize(u32 channel_count) { | 209 | std::size_t WorkerBufferSize(u32 channel_count) { |
| 220 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); | 210 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); |
| 221 | return opus_decoder_get_size(static_cast<int>(channel_count)); | 211 | constexpr int num_streams = 1; |
| 212 | const int num_stereo_streams = channel_count == 2 ? 1 : 0; | ||
| 213 | return opus_multistream_decoder_get_size(num_streams, num_stereo_streams); | ||
| 214 | } | ||
| 215 | |||
| 216 | // Creates the mapping table that maps the input channels to the particular | ||
| 217 | // output channels. In the stereo case, we map the left and right input channels | ||
| 218 | // to the left and right output channels respectively. | ||
| 219 | // | ||
| 220 | // However, in the monophonic case, we only map the one available channel | ||
| 221 | // to the sole output channel. We specify 255 for the would-be right channel | ||
| 222 | // as this is a special value defined by Opus to indicate to the decoder to | ||
| 223 | // ignore that channel. | ||
| 224 | std::array<u8, 2> CreateMappingTable(u32 channel_count) { | ||
| 225 | if (channel_count == 2) { | ||
| 226 | return {{0, 1}}; | ||
| 227 | } | ||
| 228 | |||
| 229 | return {{0, 255}}; | ||
| 222 | } | 230 | } |
| 223 | } // Anonymous namespace | 231 | } // Anonymous namespace |
| 224 | 232 | ||
| @@ -259,9 +267,15 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 259 | const std::size_t worker_sz = WorkerBufferSize(channel_count); | 267 | const std::size_t worker_sz = WorkerBufferSize(channel_count); |
| 260 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); | 268 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); |
| 261 | 269 | ||
| 262 | OpusDecoderPtr decoder{static_cast<OpusDecoder*>(operator new(worker_sz))}; | 270 | const int num_stereo_streams = channel_count == 2 ? 1 : 0; |
| 263 | if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) { | 271 | const auto mapping_table = CreateMappingTable(channel_count); |
| 264 | LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err); | 272 | |
| 273 | int error = 0; | ||
| 274 | OpusDecoderPtr decoder{ | ||
| 275 | opus_multistream_decoder_create(sample_rate, static_cast<int>(channel_count), 1, | ||
| 276 | num_stereo_streams, mapping_table.data(), &error)}; | ||
| 277 | if (error != OPUS_OK || decoder == nullptr) { | ||
| 278 | LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error); | ||
| 265 | IPC::ResponseBuilder rb{ctx, 2}; | 279 | IPC::ResponseBuilder rb{ctx, 2}; |
| 266 | // TODO(ogniK): Use correct error code | 280 | // TODO(ogniK): Use correct error code |
| 267 | rb.Push(ResultCode(-1)); | 281 | rb.Push(ResultCode(-1)); |
| @@ -271,7 +285,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 271 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 285 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 272 | rb.Push(RESULT_SUCCESS); | 286 | rb.Push(RESULT_SUCCESS); |
| 273 | rb.PushIpcInterface<IHardwareOpusDecoderManager>( | 287 | rb.PushIpcInterface<IHardwareOpusDecoderManager>( |
| 274 | std::make_unique<OpusDecoderState>(std::move(decoder), sample_rate, channel_count)); | 288 | OpusDecoderState{std::move(decoder), sample_rate, channel_count}); |
| 275 | } | 289 | } |
| 276 | 290 | ||
| 277 | HwOpus::HwOpus() : ServiceFramework("hwopus") { | 291 | HwOpus::HwOpus() : ServiceFramework("hwopus") { |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 6057c7f26..8b1920f22 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "core/hle/kernel/code_set.h" | ||
| 12 | #include "core/hle/kernel/process.h" | 13 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/vm_manager.h" | 14 | #include "core/hle/kernel/vm_manager.h" |
| 14 | #include "core/loader/elf.h" | 15 | #include "core/loader/elf.h" |
diff --git a/src/core/loader/linker.cpp b/src/core/loader/linker.cpp deleted file mode 100644 index 57ca8c3ee..000000000 --- a/src/core/loader/linker.cpp +++ /dev/null | |||
| @@ -1,147 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <vector> | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/swap.h" | ||
| 10 | #include "core/loader/linker.h" | ||
| 11 | #include "core/memory.h" | ||
| 12 | |||
| 13 | namespace Loader { | ||
| 14 | |||
| 15 | enum class RelocationType : u32 { ABS64 = 257, GLOB_DAT = 1025, JUMP_SLOT = 1026, RELATIVE = 1027 }; | ||
| 16 | |||
| 17 | enum DynamicType : u32 { | ||
| 18 | DT_NULL = 0, | ||
| 19 | DT_PLTRELSZ = 2, | ||
| 20 | DT_STRTAB = 5, | ||
| 21 | DT_SYMTAB = 6, | ||
| 22 | DT_RELA = 7, | ||
| 23 | DT_RELASZ = 8, | ||
| 24 | DT_STRSZ = 10, | ||
| 25 | DT_JMPREL = 23, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct Elf64_Rela { | ||
| 29 | u64_le offset; | ||
| 30 | RelocationType type; | ||
| 31 | u32_le symbol; | ||
| 32 | s64_le addend; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(Elf64_Rela) == 0x18, "Elf64_Rela has incorrect size."); | ||
| 35 | |||
| 36 | struct Elf64_Dyn { | ||
| 37 | u64_le tag; | ||
| 38 | u64_le value; | ||
| 39 | }; | ||
| 40 | static_assert(sizeof(Elf64_Dyn) == 0x10, "Elf64_Dyn has incorrect size."); | ||
| 41 | |||
| 42 | struct Elf64_Sym { | ||
| 43 | u32_le name; | ||
| 44 | INSERT_PADDING_BYTES(0x2); | ||
| 45 | u16_le shndx; | ||
| 46 | u64_le value; | ||
| 47 | u64_le size; | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(Elf64_Sym) == 0x18, "Elf64_Sym has incorrect size."); | ||
| 50 | |||
| 51 | void Linker::WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols, | ||
| 52 | u64 relocation_offset, u64 size, VAddr load_base) { | ||
| 53 | for (u64 i = 0; i < size; i += sizeof(Elf64_Rela)) { | ||
| 54 | Elf64_Rela rela; | ||
| 55 | std::memcpy(&rela, &program_image[relocation_offset + i], sizeof(Elf64_Rela)); | ||
| 56 | |||
| 57 | const Symbol& symbol = symbols[rela.symbol]; | ||
| 58 | switch (rela.type) { | ||
| 59 | case RelocationType::RELATIVE: { | ||
| 60 | const u64 value = load_base + rela.addend; | ||
| 61 | if (!symbol.name.empty()) { | ||
| 62 | exports[symbol.name] = value; | ||
| 63 | } | ||
| 64 | std::memcpy(&program_image[rela.offset], &value, sizeof(u64)); | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | case RelocationType::JUMP_SLOT: | ||
| 68 | case RelocationType::GLOB_DAT: | ||
| 69 | if (!symbol.value) { | ||
| 70 | imports[symbol.name] = {rela.offset + load_base, 0}; | ||
| 71 | } else { | ||
| 72 | exports[symbol.name] = symbol.value; | ||
| 73 | std::memcpy(&program_image[rela.offset], &symbol.value, sizeof(u64)); | ||
| 74 | } | ||
| 75 | break; | ||
| 76 | case RelocationType::ABS64: | ||
| 77 | if (!symbol.value) { | ||
| 78 | imports[symbol.name] = {rela.offset + load_base, rela.addend}; | ||
| 79 | } else { | ||
| 80 | const u64 value = symbol.value + rela.addend; | ||
| 81 | exports[symbol.name] = value; | ||
| 82 | std::memcpy(&program_image[rela.offset], &value, sizeof(u64)); | ||
| 83 | } | ||
| 84 | break; | ||
| 85 | default: | ||
| 86 | LOG_CRITICAL(Loader, "Unknown relocation type: {}", static_cast<int>(rela.type)); | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | void Linker::Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base) { | ||
| 93 | std::map<u64, u64> dynamic; | ||
| 94 | while (dynamic_section_offset < program_image.size()) { | ||
| 95 | Elf64_Dyn dyn; | ||
| 96 | std::memcpy(&dyn, &program_image[dynamic_section_offset], sizeof(Elf64_Dyn)); | ||
| 97 | dynamic_section_offset += sizeof(Elf64_Dyn); | ||
| 98 | |||
| 99 | if (dyn.tag == DT_NULL) { | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | dynamic[dyn.tag] = dyn.value; | ||
| 103 | } | ||
| 104 | |||
| 105 | u64 offset = dynamic[DT_SYMTAB]; | ||
| 106 | std::vector<Symbol> symbols; | ||
| 107 | while (offset < program_image.size()) { | ||
| 108 | Elf64_Sym sym; | ||
| 109 | std::memcpy(&sym, &program_image[offset], sizeof(Elf64_Sym)); | ||
| 110 | offset += sizeof(Elf64_Sym); | ||
| 111 | |||
| 112 | if (sym.name >= dynamic[DT_STRSZ]) { | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | |||
| 116 | std::string name = reinterpret_cast<char*>(&program_image[dynamic[DT_STRTAB] + sym.name]); | ||
| 117 | if (sym.value) { | ||
| 118 | exports[name] = load_base + sym.value; | ||
| 119 | symbols.emplace_back(std::move(name), load_base + sym.value); | ||
| 120 | } else { | ||
| 121 | symbols.emplace_back(std::move(name), 0); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | if (dynamic.find(DT_RELA) != dynamic.end()) { | ||
| 126 | WriteRelocations(program_image, symbols, dynamic[DT_RELA], dynamic[DT_RELASZ], load_base); | ||
| 127 | } | ||
| 128 | |||
| 129 | if (dynamic.find(DT_JMPREL) != dynamic.end()) { | ||
| 130 | WriteRelocations(program_image, symbols, dynamic[DT_JMPREL], dynamic[DT_PLTRELSZ], | ||
| 131 | load_base); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | void Linker::ResolveImports() { | ||
| 136 | // Resolve imports | ||
| 137 | for (const auto& import : imports) { | ||
| 138 | const auto& search = exports.find(import.first); | ||
| 139 | if (search != exports.end()) { | ||
| 140 | Memory::Write64(import.second.ea, search->second + import.second.addend); | ||
| 141 | } else { | ||
| 142 | LOG_ERROR(Loader, "Unresolved import: {}", import.first); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | } // namespace Loader | ||
diff --git a/src/core/loader/linker.h b/src/core/loader/linker.h deleted file mode 100644 index 107625837..000000000 --- a/src/core/loader/linker.h +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <map> | ||
| 8 | #include <string> | ||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Loader { | ||
| 12 | |||
| 13 | class Linker { | ||
| 14 | protected: | ||
| 15 | struct Symbol { | ||
| 16 | Symbol(std::string&& name, u64 value) : name(std::move(name)), value(value) {} | ||
| 17 | std::string name; | ||
| 18 | u64 value; | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct Import { | ||
| 22 | VAddr ea; | ||
| 23 | s64 addend; | ||
| 24 | }; | ||
| 25 | |||
| 26 | void WriteRelocations(std::vector<u8>& program_image, const std::vector<Symbol>& symbols, | ||
| 27 | u64 relocation_offset, u64 size, VAddr load_base); | ||
| 28 | void Relocate(std::vector<u8>& program_image, u32 dynamic_section_offset, VAddr load_base); | ||
| 29 | |||
| 30 | void ResolveImports(); | ||
| 31 | |||
| 32 | std::map<std::string, Import> imports; | ||
| 33 | std::map<std::string, VAddr> exports; | ||
| 34 | }; | ||
| 35 | |||
| 36 | } // namespace Loader | ||
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 4fad0c0dd..5de02a94b 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "core/file_sys/romfs_factory.h" | 14 | #include "core/file_sys/romfs_factory.h" |
| 15 | #include "core/file_sys/vfs_offset.h" | 15 | #include "core/file_sys/vfs_offset.h" |
| 16 | #include "core/gdbstub/gdbstub.h" | 16 | #include "core/gdbstub/gdbstub.h" |
| 17 | #include "core/hle/kernel/code_set.h" | ||
| 17 | #include "core/hle/kernel/process.h" | 18 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/vm_manager.h" | 19 | #include "core/hle/kernel/vm_manager.h" |
| 19 | #include "core/hle/service/filesystem/filesystem.h" | 20 | #include "core/hle/service/filesystem/filesystem.h" |
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index 013d629c0..85b0ed644 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h | |||
| @@ -4,10 +4,10 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "core/loader/linker.h" | ||
| 11 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| 12 | 12 | ||
| 13 | namespace FileSys { | 13 | namespace FileSys { |
| @@ -21,7 +21,7 @@ class Process; | |||
| 21 | namespace Loader { | 21 | namespace Loader { |
| 22 | 22 | ||
| 23 | /// Loads an NRO file | 23 | /// Loads an NRO file |
| 24 | class AppLoader_NRO final : public AppLoader, Linker { | 24 | class AppLoader_NRO final : public AppLoader { |
| 25 | public: | 25 | public: |
| 26 | explicit AppLoader_NRO(FileSys::VirtualFile file); | 26 | explicit AppLoader_NRO(FileSys::VirtualFile file); |
| 27 | ~AppLoader_NRO() override; | 27 | ~AppLoader_NRO() override; |
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 6ded0b707..e1c8908a1 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/file_sys/patch_manager.h" | 12 | #include "core/file_sys/patch_manager.h" |
| 13 | #include "core/gdbstub/gdbstub.h" | 13 | #include "core/gdbstub/gdbstub.h" |
| 14 | #include "core/hle/kernel/code_set.h" | ||
| 14 | #include "core/hle/kernel/process.h" | 15 | #include "core/hle/kernel/process.h" |
| 15 | #include "core/hle/kernel/vm_manager.h" | 16 | #include "core/hle/kernel/vm_manager.h" |
| 16 | #include "core/loader/nso.h" | 17 | #include "core/loader/nso.h" |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 135b6ea5a..167c8a694 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | #include <optional> | 7 | #include <optional> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/swap.h" | ||
| 9 | #include "core/file_sys/patch_manager.h" | 10 | #include "core/file_sys/patch_manager.h" |
| 10 | #include "core/loader/linker.h" | ||
| 11 | #include "core/loader/loader.h" | 11 | #include "core/loader/loader.h" |
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| @@ -26,7 +26,7 @@ struct NSOArgumentHeader { | |||
| 26 | static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrect size."); | 26 | static_assert(sizeof(NSOArgumentHeader) == 0x20, "NSOArgumentHeader has incorrect size."); |
| 27 | 27 | ||
| 28 | /// Loads an NSO file | 28 | /// Loads an NSO file |
| 29 | class AppLoader_NSO final : public AppLoader, Linker { | 29 | class AppLoader_NSO final : public AppLoader { |
| 30 | public: | 30 | public: |
| 31 | explicit AppLoader_NSO(FileSys::VirtualFile file); | 31 | explicit AppLoader_NSO(FileSys::VirtualFile file); |
| 32 | 32 | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d2c97b1f8..05ad19e1d 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -24,8 +24,6 @@ void EmuThread::run() { | |||
| 24 | 24 | ||
| 25 | MicroProfileOnThreadCreate("EmuThread"); | 25 | MicroProfileOnThreadCreate("EmuThread"); |
| 26 | 26 | ||
| 27 | stop_run = false; | ||
| 28 | |||
| 29 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | 27 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); |
| 30 | 28 | ||
| 31 | Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( | 29 | Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( |
| @@ -40,7 +38,7 @@ void EmuThread::run() { | |||
| 40 | render_window->DoneCurrent(); | 38 | render_window->DoneCurrent(); |
| 41 | } | 39 | } |
| 42 | 40 | ||
| 43 | // holds whether the cpu was running during the last iteration, | 41 | // Holds whether the cpu was running during the last iteration, |
| 44 | // so that the DebugModeLeft signal can be emitted before the | 42 | // so that the DebugModeLeft signal can be emitted before the |
| 45 | // next execution step | 43 | // next execution step |
| 46 | bool was_active = false; | 44 | bool was_active = false; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index c6c66a787..245f25847 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -114,9 +114,9 @@ int main(int argc, char** argv) { | |||
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | while (optind < argc) { | 116 | while (optind < argc) { |
| 117 | char arg = getopt_long(argc, argv, "g:fhvp::", long_options, &option_index); | 117 | int arg = getopt_long(argc, argv, "g:fhvp::", long_options, &option_index); |
| 118 | if (arg != -1) { | 118 | if (arg != -1) { |
| 119 | switch (arg) { | 119 | switch (static_cast<char>(arg)) { |
| 120 | case 'g': | 120 | case 'g': |
| 121 | errno = 0; | 121 | errno = 0; |
| 122 | gdb_port = strtoul(optarg, &endarg, 0); | 122 | gdb_port = strtoul(optarg, &endarg, 0); |