Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device file abstraction & Mouse hid implementation #1530

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/ngs2/ngs2_impl.cpp
src/core/libraries/ngs2/ngs2_impl.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.h
src/core/libraries/audio3d/audio3d_error.h
src/core/libraries/audio3d/audio3d_impl.cpp
Expand Down Expand Up @@ -461,6 +461,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/types.h
src/common/uint128.h
src/common/unique_function.h
src/common/va_ctx.h
src/common/version.h
src/common/ntapi.h
src/common/ntapi.cpp
Expand All @@ -485,6 +486,11 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
src/core/devices/base_device.cpp
src/core/devices/base_device.h
src/core/devices/hid_device.cpp
src/core/devices/hid_device.h
src/core/devices/hid_device_mouse.cpp
src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
Expand Down Expand Up @@ -724,6 +730,8 @@ set(IMGUI src/imgui/imgui_config.h

set(INPUT src/input/controller.cpp
src/input/controller.h
src/input/mouse.cpp
src/input/mouse.h
)

set(EMULATOR src/emulator.cpp
Expand Down
22 changes: 12 additions & 10 deletions src/common/io_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,16 +377,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false;
}

u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
}

errno = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/common/io_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "common/concepts.h"
#include "common/types.h"
#include "enum.h"

namespace Common::FS {

Expand Down Expand Up @@ -42,6 +43,7 @@ enum class FileAccessMode {
*/
ReadAppend = Read | Append,
};
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);

enum class FileType {
BinaryFile,
Expand Down
1 change: 1 addition & 0 deletions src/common/logging/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Common, Memory) \
CLS(Core) \
SUB(Core, Linker) \
SUB(Core, Devices) \
CLS(Config) \
CLS(Debug) \
CLS(Kernel) \
Expand Down
1 change: 1 addition & 0 deletions src/common/logging/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum class Class : u8 {
Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core
Core_Linker, ///< The module linker
Core_Devices, ///< Devices emulation
Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel.
Expand Down
111 changes: 111 additions & 0 deletions src/common/va_ctx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <xmmintrin.h>
#include "common/types.h"

#define VA_ARGS \
uint64_t rdi, uint64_t rsi, uint64_t rdx, uint64_t rcx, uint64_t r8, uint64_t r9, \
uint64_t overflow_arg_area, __m128 xmm0, __m128 xmm1, __m128 xmm2, __m128 xmm3, \
__m128 xmm4, __m128 xmm5, __m128 xmm6, __m128 xmm7, ...

#define VA_CTX(ctx) \
alignas(16)::Common::VaCtx ctx{}; \
(ctx).reg_save_area.gp[0] = rdi; \
(ctx).reg_save_area.gp[1] = rsi; \
(ctx).reg_save_area.gp[2] = rdx; \
(ctx).reg_save_area.gp[3] = rcx; \
(ctx).reg_save_area.gp[4] = r8; \
(ctx).reg_save_area.gp[5] = r9; \
(ctx).reg_save_area.fp[0] = xmm0; \
(ctx).reg_save_area.fp[1] = xmm1; \
(ctx).reg_save_area.fp[2] = xmm2; \
(ctx).reg_save_area.fp[3] = xmm3; \
(ctx).reg_save_area.fp[4] = xmm4; \
(ctx).reg_save_area.fp[5] = xmm5; \
(ctx).reg_save_area.fp[6] = xmm6; \
(ctx).reg_save_area.fp[7] = xmm7; \
(ctx).va_list.reg_save_area = &(ctx).reg_save_area; \
(ctx).va_list.gp_offset = offsetof(::Common::VaRegSave, gp); \
(ctx).va_list.fp_offset = offsetof(::Common::VaRegSave, fp); \
(ctx).va_list.overflow_arg_area = &overflow_arg_area;

namespace Common {

// https://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure

struct VaList {
u32 gp_offset;
u32 fp_offset;
void* overflow_arg_area;
void* reg_save_area;
};

struct VaRegSave {
u64 gp[6];
__m128 fp[8];
};

struct VaCtx {
VaRegSave reg_save_area;
VaList va_list;
};

template <class T, uint32_t Size>
T vaArgRegSaveAreaGp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->gp_offset);
l->gp_offset += Size;
return *addr;
}
template <class T, u64 Align, u64 Size>
T vaArgOverflowArgArea(VaList* l) {
auto ptr = ((reinterpret_cast<u64>(l->overflow_arg_area) + (Align - 1)) & ~(Align - 1));
auto* addr = reinterpret_cast<T*>(ptr);
l->overflow_arg_area = reinterpret_cast<void*>(ptr + Size);
return *addr;
}

template <class T, uint32_t Size>
T vaArgRegSaveAreaFp(VaList* l) {
auto* addr = reinterpret_cast<T*>(static_cast<u8*>(l->reg_save_area) + l->fp_offset);
l->fp_offset += Size;
return *addr;
}

inline int vaArgInteger(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<int, 8>(l);
}
return vaArgOverflowArgArea<int, 1, 8>(l);
}

inline long long vaArgLongLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long long, 8>(l);
}
return vaArgOverflowArgArea<long long, 1, 8>(l);
}
inline long vaArgLong(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<long, 8>(l);
}
return vaArgOverflowArgArea<long, 1, 8>(l);
}

inline double vaArgDouble(VaList* l) {
if (l->fp_offset <= 160) {
return vaArgRegSaveAreaFp<double, 16>(l);
}
return vaArgOverflowArgArea<double, 1, 8>(l);
}

template <class T>
T* vaArgPtr(VaList* l) {
if (l->gp_offset <= 40) {
return vaArgRegSaveAreaGp<T*, 8>(l);
}
return vaArgOverflowArgArea<T*, 1, 8>(l);
}

} // namespace Common
12 changes: 12 additions & 0 deletions src/core/devices/base_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "base_device.h"

namespace Core::Devices {

BaseDevice::BaseDevice() = default;

BaseDevice::~BaseDevice() = default;

} // namespace Core::Devices
68 changes: 68 additions & 0 deletions src/core/devices/base_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/types.h"
#include "common/va_ctx.h"
#include "core/libraries/error_codes.h"

namespace Libraries::Kernel {
struct OrbisKernelStat;
struct SceKernelIovec;
} // namespace Libraries::Kernel

namespace Core::Devices {

class BaseDevice {
public:
explicit BaseDevice();

virtual ~BaseDevice() = 0;

virtual int ioctl(u64 cmd, Common::VaCtx* args) {
return ORBIS_KERNEL_ERROR_ENOTTY;
}

virtual s64 write(const void* buf, size_t nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual s64 read(void* buf, size_t nbytes) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual s64 pread(void* buf, size_t nbytes, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual int fstat(Libraries::Kernel::OrbisKernelStat* sb) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual s32 fsync() {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual int ftruncate(s64 length) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual int getdents(void* buf, u32 nbytes, s64* basep) {
return ORBIS_KERNEL_ERROR_EBADF;
}

virtual s64 pwrite(const void* buf, size_t nbytes, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
};

} // namespace Core::Devices
68 changes: 68 additions & 0 deletions src/core/devices/hid_device.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <core/libraries/system/msgdialog_ui.h>

#include "common/logging/log.h"
#include "common/singleton.h"
#include "common/va_ctx.h"
#include "core/libraries/error_codes.h"
#include "hid_device.h"
#include "input/mouse.h"
#include "ioccom.h"

namespace Core::Devices {

struct InitHidRaw {
u32 user_id;
u32 type;
u32 _unknown2;
};
static_assert(sizeof(InitHidRaw) == 0xC);

constexpr auto HID_CMD_INIT_HANDLE_FOR_USER_ID = _IOW('H', 0x2, InitHidRaw);

int HidDevice::GenericCallback(u64 cmd, Common::VaCtx* args) {
LOG_TRACE(Core_Devices, "HID({:X}) generic: ioctl cmd={:X}", handle, cmd);
if (cmd == HID_CMD_INIT_HANDLE_FOR_USER_ID) {
auto data = vaArgPtr<InitHidRaw>(&args->va_list);
this->user_id = data->user_id;
if (data->type == 0) {
LOG_INFO(Core_Devices, "HID({:X}) open: type=mouse, user_id={}", handle, data->user_id);
this->m_callback = &HidDevice::MouseCallback;
// FIXME Replace by status bar
if (!Common::Singleton<Input::GameMouse>::Instance()->m_connected) {
using namespace ::Libraries::MsgDialog;
ShowMsgDialog(MsgDialogState(MsgDialogState::UserState{
.type = ButtonType::YESNO,
.msg = "Game wants to use your mouse.\nDo you want to allow it?",
}),
false, [](DialogResult result) {
if (result.buttonId == ButtonId::YES) {
auto* mouse = Common::Singleton<Input::GameMouse>::Instance();
mouse->m_connected = true;
}
});
}
} else {
LOG_WARNING(Core_Devices, "HID({:X}) open: unknown type={}", handle, data->type);
}
return static_cast<int>(handle);
}
LOG_WARNING(Core_Devices, "HID({:X}) generic: unknown ioctl cmd = {:X}", handle, cmd);
return ORBIS_KERNEL_ERROR_ENOTTY;
}

BaseDevice* HidDevice::Create(u32 handle, const char*, int, u16) {
return new HidDevice(handle);
}

HidDevice::HidDevice(u32 handle) : handle{handle} {}

HidDevice::~HidDevice() = default;

int HidDevice::ioctl(u64 cmd, Common::VaCtx* args) {
return (this->*m_callback)(cmd, args);
}

} // namespace Core::Devices
30 changes: 30 additions & 0 deletions src/core/devices/hid_device.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "base_device.h"

namespace Core::Devices {

class HidDevice final : BaseDevice {
u32 handle;
u32 user_id{};

int MouseCallback(u64 cmd, Common::VaCtx* args);

int GenericCallback(u64 cmd, Common::VaCtx* args);

int (HidDevice::*m_callback)(u64 cmd, Common::VaCtx* args) = &HidDevice::GenericCallback;

public:
static BaseDevice* Create(u32 handle, const char*, int, u16);

explicit HidDevice(u32 handle);

~HidDevice() override;

int ioctl(u64 cmd, Common::VaCtx* args) override;
};

} // namespace Core::Devices
Loading