Better faking of the user profile.
This commit is contained in:
parent
57dda9c755
commit
0a9d936f1e
|
@ -16,6 +16,7 @@
|
||||||
#include <xenia/kernel/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/xobject.h>
|
#include <xenia/kernel/xobject.h>
|
||||||
#include <xenia/kernel/apps/apps.h>
|
#include <xenia/kernel/apps/apps.h>
|
||||||
|
#include <xenia/kernel/objects/xevent.h>
|
||||||
#include <xenia/kernel/objects/xmodule.h>
|
#include <xenia/kernel/objects/xmodule.h>
|
||||||
#include <xenia/kernel/objects/xnotify_listener.h>
|
#include <xenia/kernel/objects/xnotify_listener.h>
|
||||||
#include <xenia/kernel/objects/xthread.h>
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
@ -41,6 +42,7 @@ KernelState::KernelState(Emulator* emulator) :
|
||||||
dispatcher_ = new Dispatcher(this);
|
dispatcher_ = new Dispatcher(this);
|
||||||
|
|
||||||
app_manager_ = std::make_unique<XAppManager>();
|
app_manager_ = std::make_unique<XAppManager>();
|
||||||
|
user_profile_ = std::make_unique<UserProfile>();
|
||||||
|
|
||||||
object_table_ = new ObjectTable();
|
object_table_ = new ObjectTable();
|
||||||
object_mutex_ = xe_mutex_alloc(10000);
|
object_mutex_ = xe_mutex_alloc(10000);
|
||||||
|
@ -171,3 +173,36 @@ void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) {
|
||||||
}
|
}
|
||||||
xe_mutex_unlock(object_mutex_);
|
xe_mutex_unlock(object_mutex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KernelState::CompleteOverlapped(uint32_t overlapped_ptr, X_RESULT result, uint32_t length) {
|
||||||
|
auto ptr = memory()->membase() + overlapped_ptr;
|
||||||
|
XOverlappedSetResult(ptr, result);
|
||||||
|
XOverlappedSetLength(ptr, length);
|
||||||
|
XOverlappedSetExtendedError(ptr, result);
|
||||||
|
X_HANDLE event_handle = XOverlappedGetEvent(ptr);
|
||||||
|
if (event_handle) {
|
||||||
|
XEvent* ev = nullptr;
|
||||||
|
if (XSUCCEEDED(object_table()->GetObject(
|
||||||
|
event_handle, reinterpret_cast<XObject**>(&ev)))) {
|
||||||
|
ev->Set(0, false);
|
||||||
|
ev->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (XOverlappedGetCompletionRoutine(ptr)) {
|
||||||
|
assert_always();
|
||||||
|
X_HANDLE thread_handle = XOverlappedGetContext(ptr);
|
||||||
|
XThread* thread = nullptr;
|
||||||
|
if (XSUCCEEDED(object_table()->GetObject(
|
||||||
|
thread_handle, reinterpret_cast<XObject**>(&thread)))) {
|
||||||
|
// TODO(benvanik): queue APC on the thread that requested the overlapped operation.
|
||||||
|
thread->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelState::CompleteOverlappedImmediate(uint32_t overlapped_ptr, X_RESULT result, uint32_t length) {
|
||||||
|
auto ptr = memory()->membase() + overlapped_ptr;
|
||||||
|
XOverlappedSetContext(ptr,
|
||||||
|
XThread::GetCurrentThreadHandle());
|
||||||
|
CompleteOverlapped(overlapped_ptr, result, length);
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <xenia/xbox.h>
|
#include <xenia/xbox.h>
|
||||||
#include <xenia/kernel/app.h>
|
#include <xenia/kernel/app.h>
|
||||||
#include <xenia/kernel/object_table.h>
|
#include <xenia/kernel/object_table.h>
|
||||||
|
#include <xenia/kernel/user_profile.h>
|
||||||
#include <xenia/kernel/fs/filesystem.h>
|
#include <xenia/kernel/fs/filesystem.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ public:
|
||||||
Dispatcher* dispatcher() const { return dispatcher_; }
|
Dispatcher* dispatcher() const { return dispatcher_; }
|
||||||
|
|
||||||
XAppManager* app_manager() const { return app_manager_.get(); }
|
XAppManager* app_manager() const { return app_manager_.get(); }
|
||||||
|
UserProfile* user_profile() const { return user_profile_.get(); }
|
||||||
|
|
||||||
ObjectTable* object_table() const { return object_table_; }
|
ObjectTable* object_table() const { return object_table_; }
|
||||||
|
|
||||||
|
@ -66,6 +68,9 @@ public:
|
||||||
void UnregisterNotifyListener(XNotifyListener* listener);
|
void UnregisterNotifyListener(XNotifyListener* listener);
|
||||||
void BroadcastNotification(XNotificationID id, uint32_t data);
|
void BroadcastNotification(XNotificationID id, uint32_t data);
|
||||||
|
|
||||||
|
void CompleteOverlapped(uint32_t overlapped_ptr, X_RESULT result, uint32_t length = 0);
|
||||||
|
void CompleteOverlappedImmediate(uint32_t overlapped_ptr, X_RESULT result, uint32_t length = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator* emulator_;
|
Emulator* emulator_;
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
|
@ -75,6 +80,7 @@ private:
|
||||||
Dispatcher* dispatcher_;
|
Dispatcher* dispatcher_;
|
||||||
|
|
||||||
std::unique_ptr<XAppManager> app_manager_;
|
std::unique_ptr<XAppManager> app_manager_;
|
||||||
|
std::unique_ptr<UserProfile> user_profile_;
|
||||||
|
|
||||||
ObjectTable* object_table_;
|
ObjectTable* object_table_;
|
||||||
xe_mutex_t* object_mutex_;
|
xe_mutex_t* object_mutex_;
|
||||||
|
|
|
@ -44,13 +44,13 @@ void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
xe_mutex_lock(lock_);
|
xe_mutex_lock(lock_);
|
||||||
auto existing = notifications_.find(id);
|
if (notifications_.count(id)) {
|
||||||
if (existing != notifications_.end()) {
|
|
||||||
// Already exists. Overwrite.
|
// Already exists. Overwrite.
|
||||||
notifications_[id] = data;
|
notifications_[id] = data;
|
||||||
} else {
|
} else {
|
||||||
// New.
|
// New.
|
||||||
notification_count_++;
|
notification_count_++;
|
||||||
|
notifications_.insert({ id, data });
|
||||||
}
|
}
|
||||||
SetEvent(wait_handle_);
|
SetEvent(wait_handle_);
|
||||||
xe_mutex_unlock(lock_);
|
xe_mutex_unlock(lock_);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
'native_list.h',
|
'native_list.h',
|
||||||
'object_table.cc',
|
'object_table.cc',
|
||||||
'object_table.h',
|
'object_table.h',
|
||||||
|
'user_profile.cc',
|
||||||
|
'user_profile.h',
|
||||||
'xam_content.cc',
|
'xam_content.cc',
|
||||||
'xam_content.h',
|
'xam_content.h',
|
||||||
'xam_info.cc',
|
'xam_info.cc',
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xenia/kernel/user_profile.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
|
UserProfile::UserProfile() {
|
||||||
|
xuid_ = 0xBABEBABEBABEBABE;
|
||||||
|
name_ = "User";
|
||||||
|
|
||||||
|
// http://cs.rin.ru/forum/viewtopic.php?f=38&t=60668&hilit=gfwl+live&start=195
|
||||||
|
// XPROFILE_GAMER_YAXIS_INVERSION
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040002, 0));
|
||||||
|
// XPROFILE_OPTION_CONTROLLER_VIBRATION
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040003, 3));
|
||||||
|
// XPROFILE_GAMERCARD_ZONE
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040004, 0));
|
||||||
|
// XPROFILE_GAMERCARD_REGION
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040005, 0));
|
||||||
|
// XPROFILE_GAMERCARD_CRED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040006, 0xFA));
|
||||||
|
// XPROFILE_GAMERCARD_REP
|
||||||
|
AddSetting(std::make_unique<FloatSetting>(0x5004000B, 0.0f));
|
||||||
|
// XPROFILE_OPTION_VOICE_MUTED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x1004000C, 0));
|
||||||
|
// XPROFILE_OPTION_VOICE_THRU_SPEAKERS
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x1004000D, 0));
|
||||||
|
// XPROFILE_OPTION_VOICE_VOLUME
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x1004000E, 0x64));
|
||||||
|
// XPROFILE_GAMERCARD_MOTTO
|
||||||
|
AddSetting(std::make_unique<UnicodeSetting>(0x402C0011, L""));
|
||||||
|
// XPROFILE_GAMERCARD_TITLES_PLAYED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040012, 1));
|
||||||
|
// XPROFILE_GAMERCARD_ACHIEVEMENTS_EARNED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040013, 0));
|
||||||
|
// XPROFILE_GAMER_DIFFICULTY
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040015, 0));
|
||||||
|
// XPROFILE_GAMER_ACTION_AUTO_AIM
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040022, 1));
|
||||||
|
// XPROFILE_GAMER_ACTION_AUTO_CENTER
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040023, 0));
|
||||||
|
// XPROFILE_GAMER_ACTION_MOVEMENT_CONTROL
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040024, 0));
|
||||||
|
// XPROFILE_GAMER_RACE_TRANSMISSION
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040026, 0));
|
||||||
|
// XPROFILE_GAMER_RACE_CAMERA_LOCATION
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040027, 0));
|
||||||
|
// XPROFILE_GAMER_RACE_BRAKE_CONTROL
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040028, 0));
|
||||||
|
// XPROFILE_GAMER_RACE_ACCELERATOR_CONTROL
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040029, 0));
|
||||||
|
// XPROFILE_GAMERCARD_TITLE_CRED_EARNED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040038, 0));
|
||||||
|
// XPROFILE_GAMERCARD_TITLE_ACHIEVEMENTS_EARNED
|
||||||
|
AddSetting(std::make_unique<Int32Setting>(0x10040039, 0));
|
||||||
|
|
||||||
|
// If we set this, games will try to get it.
|
||||||
|
// XPROFILE_GAMERCARD_PICTURE_KEY
|
||||||
|
// AddSetting(WStringSetting(0x4064000F, L""));
|
||||||
|
|
||||||
|
std::vector<uint8_t> zeros;
|
||||||
|
zeros.resize(1000);
|
||||||
|
// XPROFILE_TITLE_SPECIFIC1
|
||||||
|
AddSetting(std::make_unique<BinarySetting>(0x63E83FFF, zeros));
|
||||||
|
// XPROFILE_TITLE_SPECIFIC2
|
||||||
|
AddSetting(std::make_unique<BinarySetting>(0x63E83FFE, zeros));
|
||||||
|
// XPROFILE_TITLE_SPECIFIC3
|
||||||
|
AddSetting(std::make_unique<BinarySetting>(0x63E83FFD, zeros));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UserProfile::AddSetting(std::unique_ptr<Setting> setting) {
|
||||||
|
settings_.insert({ setting->setting_id, setting.get() });
|
||||||
|
setting_list_.push_back(std::move(setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UserProfile::Setting* UserProfile::GetSetting(uint32_t setting_id) {
|
||||||
|
const auto& it = settings_.find(setting_id);
|
||||||
|
if (it == settings_.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,189 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_XBOXKRNL_USER_PROFILE_H_
|
||||||
|
#define XENIA_KERNEL_XBOXKRNL_USER_PROFILE_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xenia/common.h>
|
||||||
|
#include <xenia/core.h>
|
||||||
|
|
||||||
|
#include <xenia/xbox.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
|
class UserProfile {
|
||||||
|
public:
|
||||||
|
struct Setting {
|
||||||
|
enum class Type {
|
||||||
|
UNKNOWN = 0,
|
||||||
|
INT32 = 1,
|
||||||
|
INT64 = 2,
|
||||||
|
DOUBLE = 3,
|
||||||
|
WSTRING = 4,
|
||||||
|
FLOAT = 5,
|
||||||
|
BINARY = 6,
|
||||||
|
DATETIME = 7,
|
||||||
|
INVALID = 0xFF,
|
||||||
|
};
|
||||||
|
union Key {
|
||||||
|
struct {
|
||||||
|
uint32_t id : 14;
|
||||||
|
uint32_t unk : 2;
|
||||||
|
uint32_t size : 12;
|
||||||
|
uint32_t type : 4;
|
||||||
|
};
|
||||||
|
uint32_t value;
|
||||||
|
};
|
||||||
|
uint32_t setting_id;
|
||||||
|
Type type;
|
||||||
|
size_t size;
|
||||||
|
Setting(uint32_t setting_id, Type type, size_t size)
|
||||||
|
: setting_id(setting_id), type(type), size(size) {}
|
||||||
|
virtual size_t extra_size() const { return 0; }
|
||||||
|
virtual size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) {
|
||||||
|
poly::store_and_swap<uint8_t>(user_data + kTypeOffset, static_cast<uint8_t>(type));
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
bool is_title_specific() const {
|
||||||
|
return (setting_id & 0x3F00) == 0x3F00;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
const size_t kTypeOffset = 0;
|
||||||
|
const size_t kValueOffset = 8;
|
||||||
|
const size_t kPointerOffset = 12;
|
||||||
|
};
|
||||||
|
struct Int32Setting : public Setting {
|
||||||
|
Int32Setting(uint32_t setting_id, int32_t value)
|
||||||
|
: Setting(setting_id, Type::INT32, 4), value(value) {}
|
||||||
|
int32_t value;
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kValueOffset, value);
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct Int64Setting : public Setting {
|
||||||
|
Int64Setting(uint32_t setting_id, int64_t value)
|
||||||
|
: Setting(setting_id, Type::INT64, 8), value(value) {}
|
||||||
|
int64_t value;
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
poly::store_and_swap<int64_t>(user_data + kValueOffset, value);
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct DoubleSetting : public Setting {
|
||||||
|
DoubleSetting(uint32_t setting_id, double value)
|
||||||
|
: Setting(setting_id, Type::DOUBLE, 8), value(value) {}
|
||||||
|
double value;
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
poly::store_and_swap<double>(user_data + kValueOffset, value);
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct UnicodeSetting : public Setting {
|
||||||
|
UnicodeSetting(uint32_t setting_id, const std::wstring& value)
|
||||||
|
: Setting(setting_id, Type::WSTRING, 8), value(value) {}
|
||||||
|
std::wstring value;
|
||||||
|
size_t extra_size() const override {
|
||||||
|
return value.empty() ? 0 : 2 * (static_cast<int32_t>(value.size()) + 1);
|
||||||
|
}
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
int32_t length;
|
||||||
|
if (value.empty()) {
|
||||||
|
length = 0;
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kValueOffset, 0);
|
||||||
|
poly::store_and_swap<uint32_t>(user_data + kPointerOffset, 0);
|
||||||
|
} else {
|
||||||
|
length = 2 * (static_cast<int32_t>(value.size()) + 1);
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kValueOffset, length);
|
||||||
|
poly::store_and_swap<uint32_t>(user_data + kPointerOffset,
|
||||||
|
static_cast<uint32_t>(buffer_offset));
|
||||||
|
memcpy(buffer + buffer_offset, value.data(), length);
|
||||||
|
}
|
||||||
|
return buffer_offset + length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct FloatSetting : public Setting {
|
||||||
|
FloatSetting(uint32_t setting_id, float value)
|
||||||
|
: Setting(setting_id, Type::FLOAT, 4), value(value) {}
|
||||||
|
float value;
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
poly::store_and_swap<float>(user_data + kValueOffset, value);
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct BinarySetting : public Setting {
|
||||||
|
BinarySetting(uint32_t setting_id, const std::vector<uint8_t>& value)
|
||||||
|
: Setting(setting_id, Type::BINARY, 8), value(value) {}
|
||||||
|
std::vector<uint8_t> value;
|
||||||
|
size_t extra_size() const override {
|
||||||
|
return static_cast<int32_t>(value.size());
|
||||||
|
}
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
int32_t length;
|
||||||
|
if (value.empty()) {
|
||||||
|
length = 0;
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kValueOffset, 0);
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kPointerOffset, 0);
|
||||||
|
} else {
|
||||||
|
length = static_cast<int32_t>(value.size());
|
||||||
|
poly::store_and_swap<int32_t>(user_data + kValueOffset, length);
|
||||||
|
poly::store_and_swap<uint32_t>(user_data + kPointerOffset,
|
||||||
|
static_cast<uint32_t>(buffer_offset));
|
||||||
|
memcpy(buffer + buffer_offset, value.data(), length);
|
||||||
|
}
|
||||||
|
return buffer_offset + length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct DateTimeSetting : public Setting {
|
||||||
|
DateTimeSetting(uint32_t setting_id, int64_t value)
|
||||||
|
: Setting(setting_id, Type::DATETIME, 8), value(value) {}
|
||||||
|
int64_t value;
|
||||||
|
size_t Append(uint8_t* user_data, uint8_t* buffer, size_t buffer_offset) override {
|
||||||
|
buffer_offset = Setting::Append(user_data, buffer, buffer_offset);
|
||||||
|
poly::store_and_swap<int64_t>(user_data + kValueOffset, value);
|
||||||
|
return buffer_offset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
UserProfile();
|
||||||
|
|
||||||
|
uint64_t xuid() const { return xuid_; }
|
||||||
|
std::string name() const { return name_; }
|
||||||
|
uint32_t signin_state() const { return 1; }
|
||||||
|
|
||||||
|
void AddSetting(std::unique_ptr<Setting> setting);
|
||||||
|
Setting* GetSetting(uint32_t setting_id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t xuid_;
|
||||||
|
std::string name_;
|
||||||
|
std::vector<std::unique_ptr<Setting>> setting_list_;
|
||||||
|
std::unordered_map<uint32_t, Setting*> settings_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XBOXKRNL_USER_PROFILE_H_
|
|
@ -12,6 +12,7 @@
|
||||||
#include <xenia/kernel/kernel_state.h>
|
#include <xenia/kernel/kernel_state.h>
|
||||||
#include <xenia/kernel/xam_private.h>
|
#include <xenia/kernel/xam_private.h>
|
||||||
#include <xenia/kernel/objects/xenumerator.h>
|
#include <xenia/kernel/objects/xenumerator.h>
|
||||||
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
#include <xenia/kernel/util/shim_utils.h>
|
#include <xenia/kernel/util/shim_utils.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,8 +38,9 @@ SHIM_CALL XamUserGetXUID_shim(
|
||||||
xuid_ptr);
|
xuid_ptr);
|
||||||
|
|
||||||
if (user_index == 0) {
|
if (user_index == 0) {
|
||||||
|
const auto& user_profile = state->user_profile();
|
||||||
if (xuid_ptr) {
|
if (xuid_ptr) {
|
||||||
SHIM_SET_MEM_32(xuid_ptr, 0xBABEBABE);
|
SHIM_SET_MEM_64(xuid_ptr, user_profile->xuid());
|
||||||
}
|
}
|
||||||
SHIM_SET_RETURN_32(0);
|
SHIM_SET_RETURN_32(0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,7 +61,8 @@ SHIM_CALL XamUserGetSigninState_shim(
|
||||||
// This should keep games from asking us to sign in and also keep them
|
// This should keep games from asking us to sign in and also keep them
|
||||||
// from initializing the network.
|
// from initializing the network.
|
||||||
if (user_index == 0) {
|
if (user_index == 0) {
|
||||||
SHIM_SET_RETURN_64(1);
|
const auto& user_profile = state->user_profile();
|
||||||
|
SHIM_SET_RETURN_64(user_profile->signin_state());
|
||||||
} else {
|
} else {
|
||||||
SHIM_SET_RETURN_64(0);
|
SHIM_SET_RETURN_64(0);
|
||||||
}
|
}
|
||||||
|
@ -77,13 +80,14 @@ SHIM_CALL XamUserGetSigninInfo_shim(
|
||||||
user_index, flags, info_ptr);
|
user_index, flags, info_ptr);
|
||||||
|
|
||||||
if (user_index == 0) {
|
if (user_index == 0) {
|
||||||
SHIM_SET_MEM_32(info_ptr + 0, 0xBABEBABE); // XUID
|
const auto& user_profile = state->user_profile();
|
||||||
SHIM_SET_MEM_32(info_ptr + 4, 1); // maybe zero?
|
SHIM_SET_MEM_64(info_ptr + 0, user_profile->xuid());
|
||||||
SHIM_SET_MEM_32(info_ptr + 8, 1); // signin state, same as above
|
SHIM_SET_MEM_32(info_ptr + 8, 0); // maybe zero?
|
||||||
SHIM_SET_MEM_32(info_ptr + 12, 0); // ?
|
SHIM_SET_MEM_32(info_ptr + 12, user_profile->signin_state());
|
||||||
SHIM_SET_MEM_32(info_ptr + 16, 0); // ?
|
SHIM_SET_MEM_32(info_ptr + 16, 0); // ?
|
||||||
char* buffer = (char*)SHIM_MEM_ADDR(info_ptr + 20);
|
SHIM_SET_MEM_32(info_ptr + 20, 0); // ?
|
||||||
xestrncpya(buffer, 0x10, "User0", 5);
|
char* buffer = (char*)SHIM_MEM_ADDR(info_ptr + 24);
|
||||||
|
strcpy(buffer, user_profile->name().data());
|
||||||
SHIM_SET_RETURN_32(0);
|
SHIM_SET_RETURN_32(0);
|
||||||
} else {
|
} else {
|
||||||
SHIM_SET_RETURN_32(X_ERROR_NO_SUCH_USER);
|
SHIM_SET_RETURN_32(X_ERROR_NO_SUCH_USER);
|
||||||
|
@ -102,8 +106,9 @@ SHIM_CALL XamUserGetName_shim(
|
||||||
user_index, buffer_ptr, buffer_len);
|
user_index, buffer_ptr, buffer_len);
|
||||||
|
|
||||||
if (user_index == 0) {
|
if (user_index == 0) {
|
||||||
|
const auto& user_profile = state->user_profile();
|
||||||
char* buffer = (char*)SHIM_MEM_ADDR(buffer_ptr);
|
char* buffer = (char*)SHIM_MEM_ADDR(buffer_ptr);
|
||||||
xestrncpya(buffer, buffer_len, "User0", 5);
|
strcpy(buffer, user_profile->name().data());
|
||||||
SHIM_SET_RETURN_32(0);
|
SHIM_SET_RETURN_32(0);
|
||||||
} else {
|
} else {
|
||||||
SHIM_SET_RETURN_32(X_ERROR_NO_SUCH_USER);
|
SHIM_SET_RETURN_32(X_ERROR_NO_SUCH_USER);
|
||||||
|
@ -136,42 +141,80 @@ SHIM_CALL XamUserReadProfileSettings_shim(
|
||||||
// Title ID = 0 means us.
|
// Title ID = 0 means us.
|
||||||
// 0xfffe07d1 = profile?
|
// 0xfffe07d1 = profile?
|
||||||
|
|
||||||
// TODO(benvanik): implement overlapped support
|
if (user_index) {
|
||||||
assert_zero(overlapped_ptr);
|
// Only support user 0.
|
||||||
|
SHIM_SET_RETURN_32(X_ERROR_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& user_profile = state->user_profile();
|
||||||
|
|
||||||
// First call asks for size (fill buffer_size_ptr).
|
// First call asks for size (fill buffer_size_ptr).
|
||||||
// Second call asks for buffer contents with that size.
|
// Second call asks for buffer contents with that size.
|
||||||
|
|
||||||
|
// http://cs.rin.ru/forum/viewtopic.php?f=38&t=60668&hilit=gfwl+live&start=195
|
||||||
// Result buffer is:
|
// Result buffer is:
|
||||||
// uint32_t setting_count
|
// uint32_t setting_count
|
||||||
// [repeated X_USER_PROFILE_SETTING structs]
|
// struct {
|
||||||
|
// uint32_t source;
|
||||||
|
// (4b pad)
|
||||||
|
// uint32_t user_index;
|
||||||
|
// (4b pad)
|
||||||
|
// uint32_t setting_id;
|
||||||
|
// (4b pad)
|
||||||
|
// <data>
|
||||||
|
// } settings[setting_count]
|
||||||
|
const size_t kSettingSize = 4 + 4 + 4 + 4 + 4 + 4 + 16;
|
||||||
|
|
||||||
typedef union {
|
// Compute required size.
|
||||||
struct {
|
uint32_t size_needed = 4 + 4 + setting_count * kSettingSize;
|
||||||
uint32_t id : 14;
|
for (uint32_t n = 0; n < setting_count; ++n) {
|
||||||
uint32_t unk : 2;
|
uint32_t setting_id = SHIM_MEM_32(setting_ids_ptr + n * 4);
|
||||||
uint32_t size : 12;
|
auto setting = user_profile->GetSetting(setting_id);
|
||||||
uint32_t type : 4;
|
if (setting) {
|
||||||
};
|
auto extra_size = static_cast<uint32_t>(setting->extra_size());;
|
||||||
uint32_t value;
|
size_needed += extra_size;
|
||||||
} x_profile_setting_t;
|
}
|
||||||
|
|
||||||
// Compute sizes.
|
|
||||||
uint32_t size_needed = 4;
|
|
||||||
for (uint32_t n = 0; n < setting_count; n++) {
|
|
||||||
x_profile_setting_t setting;
|
|
||||||
setting.value = SHIM_MEM_32(setting_ids_ptr + n * 4);
|
|
||||||
size_needed += setting.size;
|
|
||||||
}
|
}
|
||||||
SHIM_SET_MEM_32(buffer_size_ptr, size_needed);
|
SHIM_SET_MEM_32(buffer_size_ptr, size_needed);
|
||||||
if (buffer_size < size_needed) {
|
if (buffer_size < size_needed) {
|
||||||
|
if (overlapped_ptr) {
|
||||||
|
state->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
}
|
||||||
SHIM_SET_RETURN_32(X_ERROR_INSUFFICIENT_BUFFER);
|
SHIM_SET_RETURN_32(X_ERROR_INSUFFICIENT_BUFFER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(benvanik): read profile data.
|
SHIM_SET_MEM_32(buffer_ptr + 0, setting_count);
|
||||||
// For now, just return signed out.
|
SHIM_SET_MEM_32(buffer_ptr + 4, buffer_ptr + 8);
|
||||||
SHIM_SET_RETURN_32(X_ERROR_NOT_FOUND);
|
|
||||||
|
size_t buffer_offset = 4 + setting_count * kSettingSize;
|
||||||
|
size_t user_data_ptr = buffer_ptr + 8;
|
||||||
|
for (uint32_t n = 0; n < setting_count; ++n) {
|
||||||
|
uint32_t setting_id = SHIM_MEM_32(setting_ids_ptr + n * 4);
|
||||||
|
auto setting = user_profile->GetSetting(setting_id);
|
||||||
|
if (setting) {
|
||||||
|
SHIM_SET_MEM_32(user_data_ptr + 0, setting->is_title_specific() ? 2 : 1);
|
||||||
|
} else {
|
||||||
|
SHIM_SET_MEM_32(user_data_ptr + 0, 0);
|
||||||
|
}
|
||||||
|
SHIM_SET_MEM_32(user_data_ptr + 8, user_index);
|
||||||
|
SHIM_SET_MEM_32(user_data_ptr + 16, setting_id);
|
||||||
|
if (setting) {
|
||||||
|
buffer_offset = setting->Append(SHIM_MEM_ADDR(user_data_ptr + 24),
|
||||||
|
SHIM_MEM_ADDR(buffer_ptr),
|
||||||
|
buffer_offset);
|
||||||
|
} else {
|
||||||
|
memset(SHIM_MEM_ADDR(user_data_ptr + 24), 0, 16);
|
||||||
|
}
|
||||||
|
user_data_ptr += kSettingSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overlapped_ptr) {
|
||||||
|
state->CompleteOverlappedImmediate(overlapped_ptr, X_ERROR_SUCCESS);
|
||||||
|
SHIM_SET_RETURN_32(X_ERROR_IO_PENDING);
|
||||||
|
} else {
|
||||||
|
SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,12 @@ typedef uint32_t X_STATUS;
|
||||||
// Adding as needed.
|
// Adding as needed.
|
||||||
typedef uint32_t X_RESULT;
|
typedef uint32_t X_RESULT;
|
||||||
#define X_FACILITY_WIN32 7
|
#define X_FACILITY_WIN32 7
|
||||||
#define X_HRESULT_FROM_WIN32(x) ((X_RESULT)(x) <= 0 ? ((X_RESULT)(x)) : ((X_RESULT) (((x) & 0x0000FFFF) | (X_FACILITY_WIN32 << 16) | 0x80000000)))
|
#define X_HRESULT_FROM_WIN32(x) x //((X_RESULT)(x) <= 0 ? ((X_RESULT)(x)) : ((X_RESULT) (((x) & 0x0000FFFF) | (X_FACILITY_WIN32 << 16) | 0x80000000)))
|
||||||
#define X_ERROR_SUCCESS X_HRESULT_FROM_WIN32(0x00000000L)
|
#define X_ERROR_SUCCESS X_HRESULT_FROM_WIN32(0x00000000L)
|
||||||
#define X_ERROR_ACCESS_DENIED X_HRESULT_FROM_WIN32(0x00000005L)
|
#define X_ERROR_ACCESS_DENIED X_HRESULT_FROM_WIN32(0x00000005L)
|
||||||
#define X_ERROR_INVALID_HANDLE X_HRESULT_FROM_WIN32(0x00000006L)
|
#define X_ERROR_INVALID_HANDLE X_HRESULT_FROM_WIN32(0x00000006L)
|
||||||
#define X_ERROR_NO_MORE_FILES X_HRESULT_FROM_WIN32(0x00000018L)
|
#define X_ERROR_NO_MORE_FILES X_HRESULT_FROM_WIN32(0x00000018L)
|
||||||
|
#define X_ERROR_IO_PENDING X_HRESULT_FROM_WIN32(0x000003E5L)
|
||||||
#define X_ERROR_INSUFFICIENT_BUFFER X_HRESULT_FROM_WIN32(0x0000007AL)
|
#define X_ERROR_INSUFFICIENT_BUFFER X_HRESULT_FROM_WIN32(0x0000007AL)
|
||||||
#define X_ERROR_BAD_ARGUMENTS X_HRESULT_FROM_WIN32(0x000000A0L)
|
#define X_ERROR_BAD_ARGUMENTS X_HRESULT_FROM_WIN32(0x000000A0L)
|
||||||
#define X_ERROR_BUSY X_HRESULT_FROM_WIN32(0x000000AAL)
|
#define X_ERROR_BUSY X_HRESULT_FROM_WIN32(0x000000AAL)
|
||||||
|
@ -194,31 +195,35 @@ typedef enum _X_FILE_INFORMATION_CLASS {
|
||||||
|
|
||||||
inline void XOverlappedSetResult(void* ptr, uint32_t value) {
|
inline void XOverlappedSetResult(void* ptr, uint32_t value) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
p[0] = value;
|
poly::store_and_swap<uint32_t>(&p[0], value);
|
||||||
}
|
}
|
||||||
inline void XOverlappedSetLength(void* ptr, uint32_t value) {
|
inline void XOverlappedSetLength(void* ptr, uint32_t value) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
p[1] = value;
|
poly::store_and_swap<uint32_t>(&p[1], value);
|
||||||
|
}
|
||||||
|
inline uint32_t XOverlappedGetContext(void* ptr) {
|
||||||
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
|
return poly::load_and_swap<uint32_t>(&p[2]);
|
||||||
}
|
}
|
||||||
inline void XOverlappedSetContext(void* ptr, uint32_t value) {
|
inline void XOverlappedSetContext(void* ptr, uint32_t value) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
p[2] = value;
|
poly::store_and_swap<uint32_t>(&p[2], value);
|
||||||
}
|
}
|
||||||
inline void XOverlappedSetExtendedError(void* ptr, uint32_t value) {
|
inline void XOverlappedSetExtendedError(void* ptr, uint32_t value) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
p[7] = value;
|
poly::store_and_swap<uint32_t>(&p[7], value);
|
||||||
}
|
}
|
||||||
inline X_HANDLE XOverlappedGetEvent(void* ptr) {
|
inline X_HANDLE XOverlappedGetEvent(void* ptr) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
return p[4];
|
return poly::load_and_swap<uint32_t>(&p[4]);
|
||||||
}
|
}
|
||||||
inline uint32_t XOverlappedGetCompletionRoutine(void* ptr) {
|
inline uint32_t XOverlappedGetCompletionRoutine(void* ptr) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
return p[5];
|
return poly::load_and_swap<uint32_t>(&p[5]);
|
||||||
}
|
}
|
||||||
inline uint32_t XOverlappedGetCompletionContext(void* ptr) {
|
inline uint32_t XOverlappedGetCompletionContext(void* ptr) {
|
||||||
auto p = reinterpret_cast<uint32_t*>(ptr);
|
auto p = reinterpret_cast<uint32_t*>(ptr);
|
||||||
return p[6];
|
return poly::load_and_swap<uint32_t>(&p[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
class X_ANSI_STRING {
|
class X_ANSI_STRING {
|
||||||
|
|
Loading…
Reference in New Issue