Compare commits

..

2 Commits

Author SHA1 Message Date
gdkchan
e2763358ca Expose BufferDescriptorC 2018-01-17 16:38:56 -03:00
gdkchan
a5c50a5b28 Add support for reading Buffer C Descriptors on hle_ipc 2018-01-17 16:22:05 -03:00
14 changed files with 156 additions and 178 deletions

View File

@@ -53,10 +53,10 @@ template <typename T>
class Field : public FieldInterface {
public:
Field(FieldType type, std::string name, const T& value)
: name(std::move(name)), type(type), value(value) {}
: type(type), name(std::move(name)), value(value) {}
Field(FieldType type, std::string name, T&& value)
: name(std::move(name)), type(type), value(std::move(value)) {}
: type(type), name(std::move(name)), value(std::move(value)) {}
Field(const Field& other) : Field(other.type, other.name, other.value) {}

View File

@@ -58,6 +58,7 @@ set(SRCS
hle/service/sm/controller.cpp
hle/service/sm/sm.cpp
hle/service/time/time.cpp
hle/service/time/time_s.cpp
hle/service/vi/vi.cpp
hle/service/vi/vi_m.cpp
hle/shared_page.cpp
@@ -89,7 +90,6 @@ set(HEADERS
file_sys/ivfc_archive.h
file_sys/path_parser.h
file_sys/savedata_archive.h
file_sys/title_metadata.h
frontend/emu_window.h
frontend/framebuffer_layout.h
frontend/input.h
@@ -148,6 +148,7 @@ set(HEADERS
hle/service/sm/controller.h
hle/service/sm/sm.h
hle/service/time/time.h
hle/service/time/time_s.h
hle/service/vi/vi.h
hle/service/vi/vi_m.h
hle/shared_page.h

View File

@@ -4,7 +4,6 @@
#pragma once
#include <array>
#include <string>
#include <vector>
#include "common/common_types.h"

View File

@@ -54,6 +54,10 @@ public:
unsigned GetCurrentOffset() const {
return static_cast<unsigned>(index);
}
void SetCurrentOffset(unsigned offset) {
index = static_cast<ptrdiff_t>(offset);
}
};
class RequestBuilder : public RequestHelperBase {

View File

@@ -81,13 +81,8 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) {
buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
}
if (command_header->buf_c_descriptor_flags !=
IPC::CommandHeader::BufferDescriptorCFlag::Disabled) {
if (command_header->buf_c_descriptor_flags !=
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
UNIMPLEMENTED();
}
}
buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
// Padding to align to 16 bytes
rp.AlignWithPadding();
@@ -117,6 +112,31 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
ASSERT(data_payload_header->magic == Common::MakeMagic('S', 'F', 'C', 'O'));
}
rp.SetCurrentOffset(buffer_c_offset);
// For Inline buffers, the response data is written directly to buffer_c_offset
// and in this case we don't have any BufferDescriptorC on the request.
if (command_header->buf_c_descriptor_flags >
IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
if (command_header->buf_c_descriptor_flags ==
IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
} else {
unsigned num_buf_c_descriptors =
static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2;
// This is used to detect possible underflows, in case something is broken
// with the two ifs above and the flags value is == 0 || == 1.
ASSERT(num_buf_c_descriptors < 14);
for (unsigned i = 0; i < num_buf_c_descriptors; ++i) {
buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
}
}
}
rp.SetCurrentOffset(data_payload_offset);
command = rp.Pop<u32_le>();
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
}

View File

@@ -143,6 +143,10 @@ public:
return buffer_b_desciptors;
}
const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
return buffer_c_desciptors;
}
const std::unique_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const {
return domain_message_header;
}
@@ -200,8 +204,10 @@ private:
std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors;
std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors;
std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors;
std::vector<IPC::BufferDescriptorC> buffer_c_desciptors;
unsigned data_payload_offset{};
unsigned buffer_c_offset{};
u32_le command{};
};

View File

@@ -2,140 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <chrono>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/time/time.h"
#include "core/hle/service/time/time_s.h"
namespace Service {
namespace Time {
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
};
RegisterHandlers(functions);
}
private:
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
IPC::RequestBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(time_since_epoch);
LOG_DEBUG(Service, "called");
}
};
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
public:
ISteadyClock() : ServiceFramework("ISteadyClock") {}
};
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
public:
ITimeZoneService() : ServiceFramework("ITimeZoneService") {
static const FunctionInfo functions[] = {
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
};
RegisterHandlers(functions);
}
private:
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
LocationName name{};
IPC::RequestBuilder rb{ctx, 11};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(name);
}
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 posixTime = rp.Pop<u64>();
LOG_WARNING(Service, "(STUBBED) called, posixTime=0x%016llX", posixTime);
CalendarTime calendarTime{2018, 1, 1, 0, 0, 0};
CalendarAdditionalInfo additionalInfo{};
IPC::RequestBuilder rb{ctx, 10};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(calendarTime);
rb.PushRaw(additionalInfo);
}
};
void TIME::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
auto client_port = std::make_shared<ISystemClock>()->CreatePort();
auto session = client_port->Connect();
if (session.Succeeded()) {
LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u",
(*session)->GetObjectId());
IPC::RequestBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(std::move(session).Unwrap());
} else {
UNIMPLEMENTED();
}
}
void TIME::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
auto client_port = std::make_shared<ISystemClock>()->CreatePort();
auto session = client_port->Connect();
if (session.Succeeded()) {
LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u",
(*session)->GetObjectId());
IPC::RequestBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(std::move(session).Unwrap());
} else {
UNIMPLEMENTED();
}
}
void TIME::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
auto client_port = std::make_shared<ISteadyClock>()->CreatePort();
auto session = client_port->Connect();
if (session.Succeeded()) {
LOG_DEBUG(Service, "called, initialized ISteadyClock -> session=%u",
(*session)->GetObjectId());
IPC::RequestBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(std::move(session).Unwrap());
} else {
UNIMPLEMENTED();
}
}
void TIME::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>();
LOG_DEBUG(Service, "called");
}
TIME::TIME(const char* name) : ServiceFramework(name) {
static const FunctionInfo functions[] = {
{0x00000000, &TIME::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
{0x00000001, &TIME::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"},
{0x00000002, &TIME::GetStandardSteadyClock, "GetStandardSteadyClock"},
{0x00000003, &TIME::GetTimeZoneService, "GetTimeZoneService"},
};
RegisterHandlers(functions);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<TIME>("time:a")->InstallAsService(service_manager);
std::make_shared<TIME>("time:r")->InstallAsService(service_manager);
std::make_shared<TIME>("time:s")->InstallAsService(service_manager);
std::make_shared<TIME>("time:u")->InstallAsService(service_manager);
std::make_shared<TimeS>()->InstallAsService(service_manager);
}
} // namespace Time

View File

@@ -9,42 +9,6 @@
namespace Service {
namespace Time {
// TODO(Rozelette) RE this structure
struct LocationName {
INSERT_PADDING_BYTES(0x24);
};
static_assert(sizeof(LocationName) == 0x24, "LocationName structure has incorrect size");
struct CalendarTime {
u16_le year;
u8 month; // Starts at 1
u8 day; // Starts at 1
u8 hour;
u8 minute;
u8 second;
INSERT_PADDING_BYTES(1);
};
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
// TODO(Rozelette) RE this structure
struct CalendarAdditionalInfo {
INSERT_PADDING_BYTES(0x18);
};
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
"CalendarAdditionalInfo structure has incorrect size");
class TIME final : public ServiceFramework<TIME> {
public:
explicit TIME(const char* name);
~TIME() = default;
private:
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx);
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
};
/// Registers all Time services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

View File

@@ -0,0 +1,58 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <chrono>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
#include "core/hle/service/time/time_s.h"
namespace Service {
namespace Time {
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
static const FunctionInfo functions[] = {
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
};
RegisterHandlers(functions);
}
private:
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
IPC::RequestBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(time_since_epoch);
LOG_DEBUG(Service, "called");
}
};
void TimeS::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
auto client_port = std::make_shared<ISystemClock>()->CreatePort();
auto session = client_port->Connect();
if (session.Succeeded()) {
LOG_DEBUG(Service, "called, initialized ISystemClock -> session=%u",
(*session)->GetObjectId());
IPC::RequestBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushMoveObjects(std::move(session).Unwrap());
} else {
UNIMPLEMENTED();
}
}
TimeS::TimeS() : ServiceFramework("time:s") {
static const FunctionInfo functions[] = {
{0x00000000, &TimeS::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
};
RegisterHandlers(functions);
}
} // namespace Time
} // namespace Service

View File

@@ -0,0 +1,23 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/service.h"
namespace Service {
namespace Time {
class TimeS final : public ServiceFramework<TimeS> {
public:
TimeS();
~TimeS() = default;
private:
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
};
} // namespace Time
} // namespace Service

View File

@@ -118,6 +118,13 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) {
}
program_image.resize(PageAlignSize(static_cast<u32>(program_image.size()) + bss_size));
// Relocate symbols if there was a proper MOD header - This must happen after the image has been
// loaded into memory
if (has_mod_header) {
Relocate(program_image, nro_header.module_header_offset + mod_header.dynamic_offset,
load_base);
}
// Load codeset for current process
codeset->name = path;
codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
@@ -147,6 +154,8 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(base_addr, 48, Kernel::DEFAULT_STACK_SIZE);
ResolveImports();
is_loaded = true;
return ResultStatus::Success;
}

View File

@@ -88,7 +88,7 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
}
VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base) {
VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base, bool relocate) {
FileUtil::IOFile file(path, "rb");
if (!file.IsOpen()) {
return {};
@@ -135,6 +135,12 @@ VAddr AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base) {
const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
program_image.resize(image_size);
// Relocate symbols if there was a proper MOD header - This must happen after the image has been
// loaded into memory
if (has_mod_header && relocate) {
Relocate(program_image, module_offset + mod_header.dynamic_offset, load_base);
}
// Load codeset for current process
codeset->name = path;
codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
@@ -175,6 +181,8 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
ResolveImports();
is_loaded = true;
return ResultStatus::Success;
}

View File

@@ -34,7 +34,7 @@ public:
ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
private:
VAddr LoadNso(const std::string& path, VAddr load_base);
VAddr LoadNso(const std::string& path, VAddr load_base, bool relocate = false);
std::string filepath;
};

View File

@@ -1,8 +1,12 @@
#include <QApplication>
#include <QHBoxLayout>
#include <QKeyEvent>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
// Required for screen DPI information
#include <QScreen>
#include <QWindow>
#endif
#include "common/microprofile.h"
#include "common/scm_rev.h"
@@ -116,13 +120,15 @@ GRenderWindow::~GRenderWindow() {
void GRenderWindow::moveContext() {
DoneCurrent();
// We need to move GL context to the swapping thread in Qt5
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
// If the thread started running, move the GL Context to the new thread. Otherwise, move it
// back.
auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr)
? emu_thread
: qApp->thread();
child->context()->moveToThread(thread);
#endif
}
void GRenderWindow::SwapBuffers() {
@@ -185,8 +191,12 @@ QByteArray GRenderWindow::saveGeometry() {
}
qreal GRenderWindow::windowPixelRatio() {
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
// windowHandle() might not be accessible until the window is displayed to screen.
return windowHandle() ? windowHandle()->screen()->devicePixelRatio() : 1.0f;
#else
return 1.0f;
#endif
}
void GRenderWindow::closeEvent(QCloseEvent* event) {
@@ -289,7 +299,9 @@ void GRenderWindow::OnEmulationStopping() {
void GRenderWindow::showEvent(QShowEvent* event) {
QWidget::showEvent(event);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
// windowHandle() is not initialized until the Window is shown, so we connect it here.
connect(this->windowHandle(), SIGNAL(screenChanged(QScreen*)), this,
SLOT(OnFramebufferSizeChanged()), Qt::UniqueConnection);
#endif
}