diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/applets/erreula.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/applets/mii_selector.cpp | 10 | ||||
| -rw-r--r-- | src/core/hle/applets/mii_selector.h | 57 | ||||
| -rw-r--r-- | src/core/hle/applets/mint.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/applets/swkbd.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/lock.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/lock.h | 18 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.cpp | 229 | ||||
| -rw-r--r-- | src/core/hle/service/apt/apt.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/dsp_dsp.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 44 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/ir/ir_rst.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.cpp | 165 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.h | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.h | 30 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_connection.cpp | 79 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_connection.h | 51 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 8 |
22 files changed, 605 insertions, 152 deletions
diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp index 75d7fd9fc..518f371f5 100644 --- a/src/core/hle/applets/erreula.cpp +++ b/src/core/hle/applets/erreula.cpp @@ -31,8 +31,8 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Kernel::SharedMemory::CreateForApplet( - heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, "ErrEula Memory"); + heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + "ErrEula Memory"); // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp index 89f08daa2..f225c23a5 100644 --- a/src/core/hle/applets/mii_selector.cpp +++ b/src/core/hle/applets/mii_selector.cpp @@ -38,8 +38,8 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Kernel::SharedMemory::CreateForApplet( - heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, "MiiSelector Memory"); + heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + "MiiSelector Memory"); // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; @@ -66,7 +66,7 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa // continue. MiiResult result; memset(&result, 0, sizeof(result)); - result.result_code = 0; + result.return_code = 0; // Let the application know that we're closing Service::APT::MessageParameter message; @@ -82,5 +82,5 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa } void MiiSelector::Update() {} -} -} // namespace +} // namespace Applets +} // namespace HLE diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h index ec00e29d2..136ce8948 100644 --- a/src/core/hle/applets/mii_selector.h +++ b/src/core/hle/applets/mii_selector.h @@ -16,51 +16,46 @@ namespace HLE { namespace Applets { struct MiiConfig { - u8 unk_000; - u8 unk_001; - u8 unk_002; - u8 unk_003; - u8 unk_004; + u8 enable_cancel_button; + u8 enable_guest_mii; + u8 show_on_top_screen; + INSERT_PADDING_BYTES(5); + u16 title[0x40]; + INSERT_PADDING_BYTES(4); + u8 show_guest_miis; INSERT_PADDING_BYTES(3); - u16 unk_008; - INSERT_PADDING_BYTES(0x82); - u8 unk_08C; - INSERT_PADDING_BYTES(3); - u16 unk_090; + u32 initially_selected_mii_index; + u8 guest_mii_whitelist[6]; + u8 user_mii_whitelist[0x64]; INSERT_PADDING_BYTES(2); - u32 unk_094; - u16 unk_098; - u8 unk_09A[0x64]; - u8 unk_0FE; - u8 unk_0FF; - u32 unk_100; + u32 magic_value; }; - static_assert(sizeof(MiiConfig) == 0x104, "MiiConfig structure has incorrect size"); #define ASSERT_REG_POSITION(field_name, position) \ static_assert(offsetof(MiiConfig, field_name) == position, \ "Field " #field_name " has invalid position") -ASSERT_REG_POSITION(unk_008, 0x08); -ASSERT_REG_POSITION(unk_08C, 0x8C); -ASSERT_REG_POSITION(unk_090, 0x90); -ASSERT_REG_POSITION(unk_094, 0x94); -ASSERT_REG_POSITION(unk_0FE, 0xFE); +ASSERT_REG_POSITION(title, 0x08); +ASSERT_REG_POSITION(show_guest_miis, 0x8C); +ASSERT_REG_POSITION(initially_selected_mii_index, 0x90); +ASSERT_REG_POSITION(guest_mii_whitelist, 0x94); #undef ASSERT_REG_POSITION struct MiiResult { - u32 result_code; - u8 unk_04; - INSERT_PADDING_BYTES(7); - u8 unk_0C[0x60]; - u8 unk_6C[0x16]; + u32 return_code; + u32 is_guest_mii_selected; + u32 selected_guest_mii_index; + // TODO(mailwl): expand to Mii Format structure: https://www.3dbrew.org/wiki/Mii + u8 selected_mii_data[0x5C]; INSERT_PADDING_BYTES(2); + u16 mii_data_checksum; + u16 guest_mii_name[0xC]; }; static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size"); #define ASSERT_REG_POSITION(field_name, position) \ static_assert(offsetof(MiiResult, field_name) == position, \ "Field " #field_name " has invalid position") -ASSERT_REG_POSITION(unk_0C, 0x0C); -ASSERT_REG_POSITION(unk_6C, 0x6C); +ASSERT_REG_POSITION(selected_mii_data, 0x0C); +ASSERT_REG_POSITION(guest_mii_name, 0x6C); #undef ASSERT_REG_POSITION class MiiSelector final : public Applet { @@ -79,5 +74,5 @@ private: MiiConfig config; }; -} -} // namespace +} // namespace Applets +} // namespace HLE diff --git a/src/core/hle/applets/mint.cpp b/src/core/hle/applets/mint.cpp index 31a79ea17..50d79190b 100644 --- a/src/core/hle/applets/mint.cpp +++ b/src/core/hle/applets/mint.cpp @@ -31,8 +31,8 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Kernel::SharedMemory::CreateForApplet( - heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, "Mint Memory"); + heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + "Mint Memory"); // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp index fdf8807b0..0bc471a3a 100644 --- a/src/core/hle/applets/swkbd.cpp +++ b/src/core/hle/applets/swkbd.cpp @@ -41,8 +41,8 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con heap_memory = std::make_shared<std::vector<u8>>(capture_info.size); // Create a SharedMemory that directly points to this heap block. framebuffer_memory = Kernel::SharedMemory::CreateForApplet( - heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); + heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + "SoftwareKeyboard Memory"); // Send the response message with the newly created SharedMemory Service::APT::MessageParameter result; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 9cf288b08..73fab3981 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,7 @@ #include <string> #include <utility> #include <boost/smart_ptr/intrusive_ptr.hpp> +#include "common/assert.h" #include "common/common_types.h" namespace Kernel { @@ -84,6 +85,8 @@ public: case HandleType::ClientSession: return false; } + + UNREACHABLE(); } public: @@ -129,4 +132,4 @@ void Init(u32 system_mode); /// Shutdown the kernel void Shutdown(); -} // namespace +} // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f5f2eb2f7..b957c45dd 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -478,8 +478,6 @@ void Thread::BoostPriority(s32 priority) { } SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { - DEBUG_ASSERT(!GetCurrentThread()); - // Initialize new "main" thread auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, Memory::HEAP_VADDR_END); @@ -489,9 +487,7 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 - // Run new "main" thread - SwitchContext(thread.get()); - + // Note: The newly created thread will be run when the scheduler fires. return thread; } diff --git a/src/core/hle/lock.cpp b/src/core/hle/lock.cpp new file mode 100644 index 000000000..1c24c7ce9 --- /dev/null +++ b/src/core/hle/lock.cpp @@ -0,0 +1,11 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <core/hle/lock.h> + +namespace HLE { +std::recursive_mutex g_hle_lock; +} diff --git a/src/core/hle/lock.h b/src/core/hle/lock.h new file mode 100644 index 000000000..5c99fe996 --- /dev/null +++ b/src/core/hle/lock.h @@ -0,0 +1,18 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <mutex> + +namespace HLE { +/* + * Synchronizes access to the internal HLE kernel structures, it is acquired when a guest + * application thread performs a syscall. It should be acquired by any host threads that read or + * modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes + * to the emulated memory is not protected by this mutex, and should be avoided in any threads other + * than the CPU thread. + */ +extern std::recursive_mutex g_hle_lock; +} // namespace HLE diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 0109fa2b2..58d94768c 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -34,8 +34,6 @@ static bool shared_font_loaded = false; static bool shared_font_relocated = false; static Kernel::SharedPtr<Kernel::Mutex> lock; -static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event -static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event static u32 cpu_percent; ///< CPU time available to the running application @@ -44,32 +42,160 @@ static u8 unknown_ns_state_field; static ScreencapPostPermission screen_capture_post_permission; -/// Parameter data to be returned in the next call to Glance/ReceiveParameter +/// Parameter data to be returned in the next call to Glance/ReceiveParameter. +/// TODO(Subv): Use std::optional once we migrate to C++17. static boost::optional<MessageParameter> next_parameter; +enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; + +static constexpr size_t NumAppletSlot = 4; + +enum class AppletSlot : u8 { + Application, + SystemApplet, + HomeMenu, + LibraryApplet, + + // An invalid tag + Error, +}; + +union AppletAttributes { + u32 raw; + + BitField<0, 3, u32> applet_pos; + + AppletAttributes() : raw(0) {} + AppletAttributes(u32 attributes) : raw(attributes) {} +}; + +struct AppletSlotData { + AppletId applet_id; + AppletSlot slot; + bool registered; + AppletAttributes attributes; + Kernel::SharedPtr<Kernel::Event> notification_event; + Kernel::SharedPtr<Kernel::Event> parameter_event; +}; + +// Holds data about the concurrently running applets in the system. +static std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; + +// This overload returns nullptr if no applet with the specified id has been started. +static AppletSlotData* GetAppletSlotData(AppletId id) { + auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { + return &applet_slots[static_cast<size_t>(slot)]; + }; + + if (id == AppletId::Application) { + auto* slot = GetSlot(AppletSlot::Application); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + if (id == AppletId::AnySystemApplet) { + auto* system_slot = GetSlot(AppletSlot::SystemApplet); + if (system_slot->applet_id != AppletId::None) + return system_slot; + + // The Home Menu is also a system applet, but it lives in its own slot to be able to run + // concurrently with other system applets. + auto* home_slot = GetSlot(AppletSlot::HomeMenu); + if (home_slot->applet_id != AppletId::None) + return home_slot; + + return nullptr; + } + + if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { + auto* slot = GetSlot(AppletSlot::LibraryApplet); + if (slot->applet_id == AppletId::None) + return nullptr; + + u32 applet_pos = slot->attributes.applet_pos; + + if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) + return slot; + + if (id == AppletId::AnySysLibraryApplet && + applet_pos == static_cast<u32>(AppletPos::SysLibrary)) + return slot; + + return nullptr; + } + + if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { + auto* slot = GetSlot(AppletSlot::HomeMenu); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + for (auto& slot : applet_slots) { + if (slot.applet_id == id) + return &slot; + } + + return nullptr; +} + +static AppletSlotData* GetAppletSlotData(AppletAttributes attributes) { + // Mapping from AppletPos to AppletSlot + static constexpr std::array<AppletSlot, 6> applet_position_slots = { + AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, + AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; + + u32 applet_pos = attributes.applet_pos; + if (applet_pos >= applet_position_slots.size()) + return nullptr; + + AppletSlot slot = applet_position_slots[applet_pos]; + + if (slot == AppletSlot::Error) + return nullptr; + + return &applet_slots[static_cast<size_t>(slot)]; +} + void SendParameter(const MessageParameter& parameter) { next_parameter = parameter; - // Signal the event to let the application know that a new parameter is ready to be read - parameter_event->Signal(); + // Signal the event to let the receiver know that a new parameter is ready to be read + auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); + ASSERT(slot_data); + + slot_data->parameter_event->Signal(); } void Initialize(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 u32 app_id = rp.Pop<u32>(); - u32 flags = rp.Pop<u32>(); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); - rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).Unwrap(), - Kernel::g_handle_table.Create(parameter_event).Unwrap()); + u32 attributes = rp.Pop<u32>(); - // TODO(bunnei): Check if these events are cleared every time Initialize is called. - notification_event->Clear(); - parameter_event->Clear(); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes); + + auto* const slot_data = GetAppletSlotData(attributes); + + // Note: The real NS service does not check if the attributes value is valid before accessing + // the data in the array + ASSERT_MSG(slot_data, "Invalid application attributes"); + + if (slot_data->registered) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } - ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); - lock->Release(); + slot_data->applet_id = static_cast<AppletId>(app_id); + slot_data->attributes.raw = attributes; - LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(), + Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap()); } void GetSharedFont(Service::Interface* self) { @@ -120,7 +246,12 @@ void GetLockHandle(Service::Interface* self) { // this will cause the app to wait until parameter_event is signaled. u32 applet_attributes = rp.Pop<u32>(); IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); - rb.Push(RESULT_SUCCESS); // No error + rb.Push(RESULT_SUCCESS); // No error + + // TODO(Subv): The output attributes should have an AppletPos of either Library or System | + // Library (depending on the type of the last launched applet) if the input attributes' + // AppletPos has the Library bit set. + rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. rb.Push<u32>(0); // Least significant bit = power button state Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).Unwrap(); @@ -133,10 +264,22 @@ void GetLockHandle(Service::Interface* self) { void Enable(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 u32 attributes = rp.Pop<u32>(); + + LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); // No error - parameter_event->Signal(); // Let the application know that it has been started - LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); + + auto* const slot_data = GetAppletSlotData(attributes); + + if (!slot_data) { + rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + slot_data->registered = true; + + rb.Push(RESULT_SUCCESS); } void GetAppletManInfo(Service::Interface* self) { @@ -154,22 +297,27 @@ void GetAppletManInfo(Service::Interface* self) { void IsRegistered(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 - u32 app_id = rp.Pop<u32>(); + AppletId app_id = static_cast<AppletId>(rp.Pop<u32>()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error - // TODO(Subv): An application is considered "registered" if it has already called APT::Enable - // handle this properly once we implement multiprocess support. - bool is_registered = false; // Set to not registered by default + auto* const slot_data = GetAppletSlotData(app_id); + + // Check if an LLE applet was registered first, then fallback to HLE applets + bool is_registered = slot_data && slot_data->registered; - if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { - is_registered = HLE::Applets::IsLibraryAppletRunning(); - } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { - is_registered = true; // Set to registered + if (!is_registered) { + if (app_id == AppletId::AnyLibraryApplet) { + is_registered = HLE::Applets::IsLibraryAppletRunning(); + } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { + // The applet exists, set it as registered. + is_registered = true; + } } + rb.Push(is_registered); - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); + LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id)); } void InquireNotification(Service::Interface* self) { @@ -864,14 +1012,23 @@ void Init() { screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value - // TODO(bunnei): Check if these are created in Initialize or on APT process startup. - notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); - parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start"); + for (size_t slot = 0; slot < applet_slots.size(); ++slot) { + auto& slot_data = applet_slots[slot]; + slot_data.slot = static_cast<AppletSlot>(slot); + slot_data.applet_id = AppletId::None; + slot_data.attributes.raw = 0; + slot_data.registered = false; + slot_data.notification_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); + slot_data.parameter_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); + } // Initialize the parameter to wake up the application. next_parameter.emplace(); next_parameter->signal = static_cast<u32>(SignalType::Wakeup); next_parameter->destination_id = static_cast<u32>(AppletId::Application); + applet_slots[static_cast<size_t>(AppletSlot::Application)].parameter_event->Signal(); } void Shutdown() { @@ -879,8 +1036,12 @@ void Shutdown() { shared_font_loaded = false; shared_font_relocated = false; lock = nullptr; - notification_event = nullptr; - parameter_event = nullptr; + + for (auto& slot : applet_slots) { + slot.registered = false; + slot.notification_event = nullptr; + slot.parameter_event = nullptr; + } next_parameter = boost::none; diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 106754853..96b28b438 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -72,6 +72,8 @@ enum class SignalType : u32 { /// App Id's used by APT functions enum class AppletId : u32 { + None = 0, + AnySystemApplet = 0x100, HomeMenu = 0x101, AlternateMenu = 0x103, Camera = 0x110, @@ -83,6 +85,7 @@ enum class AppletId : u32 { Miiverse = 0x117, MiiversePost = 0x118, AmiiboSettings = 0x119, + AnySysLibraryApplet = 0x200, SoftwareKeyboard1 = 0x201, Ed1 = 0x202, PnoteApp = 0x204, @@ -119,8 +122,9 @@ enum class ScreencapPostPermission : u32 { namespace ErrCodes { enum { ParameterPresent = 2, + InvalidAppletSlot = 4, }; -} +} // namespace ErrCodes /// Send a parameter to the currently-running application, which will read it via ReceiveParameter void SendParameter(const MessageParameter& parameter); diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 7d746054f..42f8950f9 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -147,9 +147,10 @@ static void LoadComponent(Service::Interface* self) { LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(component_data.data(), component_data.size())); // Some versions of the firmware have the location of DSP structures listed here. - ASSERT(size > 0x37C); - LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, - Common::ComputeHash64(component_data.data() + 0x340, 60)); + if (size > 0x37C) { + LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, + Common::ComputeHash64(component_data.data() + 0x340, 60)); + } LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X", diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2014b8461..aa5d821f9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -7,8 +7,9 @@ #include <cmath> #include <memory> #include "common/logging/log.h" +#include "core/3ds.h" +#include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/emu_window.h" #include "core/frontend/input.h" #include "core/hle/ipc.h" #include "core/hle/kernel/event.h" @@ -18,7 +19,6 @@ #include "core/hle/service/hid/hid_spvr.h" #include "core/hle/service/hid/hid_user.h" #include "core/hle/service/service.h" -#include "video_core/video_core.h" namespace Service { namespace HID { @@ -50,10 +50,15 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234; constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; +constexpr float accelerometer_coef = 512.0f; // measured from hw test result +constexpr float gyroscope_coef = 14.375f; // got from hwtest GetGyroscopeLowRawToDpsCoefficient call + static std::atomic<bool> is_device_reload_pending; static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> buttons; static std::unique_ptr<Input::AnalogDevice> circle_pad; +static std::unique_ptr<Input::MotionDevice> motion_device; +static std::unique_ptr<Input::TouchDevice> touch_device; DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) { // 30 degree and 60 degree are angular thresholds for directions @@ -90,6 +95,8 @@ static void LoadInputDevices() { buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); circle_pad = Input::CreateDevice<Input::AnalogDevice>( Settings::values.analogs[Settings::NativeAnalog::CirclePad]); + motion_device = Input::CreateDevice<Input::MotionDevice>(Settings::values.motion_device); + touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); } static void UnloadInputDevices() { @@ -97,6 +104,8 @@ static void UnloadInputDevices() { button.reset(); } circle_pad.reset(); + motion_device.reset(); + touch_device.reset(); } static void UpdatePadCallback(u64 userdata, int cycles_late) { @@ -165,8 +174,10 @@ static void UpdatePadCallback(u64 userdata, int cycles_late) { // Get the current touch entry TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index]; bool pressed = false; - - std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState(); + float x, y; + std::tie(x, y, pressed) = touch_device->GetStatus(); + touch_entry.x = static_cast<u16>(x * Core::kScreenBottomWidth); + touch_entry.y = static_cast<u16>(y * Core::kScreenBottomHeight); touch_entry.valid.Assign(pressed ? 1 : 0); // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which @@ -193,10 +204,19 @@ static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) { mem->accelerometer.index = next_accelerometer_index; next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); + Math::Vec3<float> accel; + std::tie(accel, std::ignore) = motion_device->GetStatus(); + accel *= accelerometer_coef; + // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback + // The time stretch formula should be like + // stretched_vector = (raw_vector - gravity) * stretch_ratio + gravity + AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index]; - std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) = - VideoCore::g_emu_window->GetAccelerometerState(); + + accelerometer_entry.x = static_cast<s16>(accel.x); + accelerometer_entry.y = static_cast<s16>(accel.y); + accelerometer_entry.z = static_cast<s16>(accel.z); // Make up "raw" entry // TODO(wwylele): @@ -227,8 +247,14 @@ static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) { next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; - std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) = - VideoCore::g_emu_window->GetGyroscopeState(); + + Math::Vec3<float> gyro; + std::tie(std::ignore, gyro) = motion_device->GetStatus(); + double stretch = Core::System::GetInstance().perf_stats.GetLastFrameTimeScale(); + gyro *= gyroscope_coef * stretch; + gyroscope_entry.x = static_cast<s16>(gyro.x); + gyroscope_entry.y = static_cast<s16>(gyro.y); + gyroscope_entry.z = static_cast<s16>(gyro.z); // Make up "raw" entry mem->gyroscope.raw_entry.x = gyroscope_entry.x; @@ -326,7 +352,7 @@ void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; - f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient(); + f32 coef = gyroscope_coef; memcpy(&cmd_buff[2], &coef, 4); } diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 1ef972e70..ef25926b5 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -24,7 +24,7 @@ namespace HID { */ struct PadState { union { - u32 hex; + u32 hex{}; BitField<0, 1, u32> a; BitField<1, 1, u32> b; diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 837413f93..0912d5756 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -18,7 +18,7 @@ namespace Service { namespace IR { union PadState { - u32_le hex; + u32_le hex{}; BitField<14, 1, u32_le> zl; BitField<15, 1, u32_le> zr; diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 6dbdff044..893bbb1e7 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -4,6 +4,7 @@ #include <array> #include <cstring> +#include <mutex> #include <unordered_map> #include <vector> #include "common/common_types.h" @@ -15,8 +16,10 @@ #include "core/hle/result.h" #include "core/hle/service/nwm/nwm_uds.h" #include "core/hle/service/nwm/uds_beacon.h" +#include "core/hle/service/nwm/uds_connection.h" #include "core/hle/service/nwm/uds_data.h" #include "core/memory.h" +#include "network/network.h" namespace Service { namespace NWM { @@ -51,6 +54,135 @@ static NetworkInfo network_info; // Event that will generate and send the 802.11 beacon frames. static int beacon_broadcast_event; +// Mutex to synchronize access to the list of received beacons between the emulation thread and the +// network thread. +static std::mutex beacon_mutex; + +// Number of beacons to store before we start dropping the old ones. +// TODO(Subv): Find a more accurate value for this limit. +constexpr size_t MaxBeaconFrames = 15; + +// List of the last <MaxBeaconFrames> beacons received from the network. +static std::deque<Network::WifiPacket> received_beacons; + +/** + * Returns a list of received 802.11 beacon frames from the specified sender since the last call. + */ +std::deque<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) { + std::lock_guard<std::mutex> lock(beacon_mutex); + // TODO(Subv): Filter by sender. + return std::move(received_beacons); +} + +/// Sends a WifiPacket to the room we're currently connected to. +void SendPacket(Network::WifiPacket& packet) { + // TODO(Subv): Implement. +} + +// Inserts the received beacon frame in the beacon queue and removes any older beacons if the size +// limit is exceeded. +void HandleBeaconFrame(const Network::WifiPacket& packet) { + std::lock_guard<std::mutex> lock(beacon_mutex); + + received_beacons.emplace_back(packet); + + // Discard old beacons if the buffer is full. + if (received_beacons.size() > MaxBeaconFrames) + received_beacons.pop_front(); +} + +/* + * Returns an available index in the nodes array for the + * currently-hosted UDS network. + */ +static u16 GetNextAvailableNodeId() { + ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost), + "Can not accept clients if we're not hosting a network"); + + for (u16 index = 0; index < connection_status.max_nodes; ++index) { + if ((connection_status.node_bitmask & (1 << index)) == 0) + return index; + } + + // Any connection attempts to an already full network should have been refused. + ASSERT_MSG(false, "No available connection slots in the network"); +} + +/* + * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11 + * authentication frame with SEQ1. + */ +void StartConnectionSequence(const MacAddress& server) { + ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected)); + + // TODO(Subv): Handle timeout. + + // Send an authentication frame with SEQ1 + using Network::WifiPacket; + WifiPacket auth_request; + auth_request.channel = network_channel; + auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1); + auth_request.destination_address = server; + auth_request.type = WifiPacket::PacketType::Authentication; + + SendPacket(auth_request); +} + +/// Sends an Association Response frame to the specified mac address +void SendAssociationResponseFrame(const MacAddress& address) { + ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost)); + + using Network::WifiPacket; + WifiPacket assoc_response; + assoc_response.channel = network_channel; + // TODO(Subv): This will cause multiple clients to end up with the same association id, but + // we're not using that for anything. + u16 association_id = 1; + assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id, + network_info.network_id); + assoc_response.destination_address = address; + assoc_response.type = WifiPacket::PacketType::AssociationResponse; + + SendPacket(assoc_response); +} + +/* + * Handles the authentication request frame and sends the authentication response and association + * response frames. Once an Authentication frame with SEQ1 is received by the server, it responds + * with an Authentication frame containing SEQ2, and immediately sends an Association response frame + * containing the details of the access point and the assigned association id for the new client. + */ +void HandleAuthenticationFrame(const Network::WifiPacket& packet) { + // Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior + if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) { + ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost)); + + // Respond with an authentication response frame with SEQ2 + using Network::WifiPacket; + WifiPacket auth_request; + auth_request.channel = network_channel; + auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2); + auth_request.destination_address = packet.transmitter_address; + auth_request.type = WifiPacket::PacketType::Authentication; + + SendPacket(auth_request); + + SendAssociationResponseFrame(packet.transmitter_address); + } +} + +/// Callback to parse and handle a received wifi packet. +void OnWifiPacketReceived(const Network::WifiPacket& packet) { + switch (packet.type) { + case Network::WifiPacket::PacketType::Beacon: + HandleBeaconFrame(packet); + break; + case Network::WifiPacket::PacketType::Authentication: + HandleAuthenticationFrame(packet); + break; + } +} + /** * NWM_UDS::Shutdown service function * Inputs: @@ -111,8 +243,7 @@ static void RecvBeaconBroadcastData(Interface* self) { u32 total_size = sizeof(BeaconDataReplyHeader); // Retrieve all beacon frames that were received from the desired mac address. - std::deque<WifiPacket> beacons = - GetReceivedPackets(WifiPacket::PacketType::Beacon, mac_address); + auto beacons = GetReceivedBeacons(mac_address); BeaconDataReplyHeader data_reply_header{}; data_reply_header.total_entries = beacons.size(); @@ -193,6 +324,9 @@ static void InitializeWithVersion(Interface* self) { rb.Push(RESULT_SUCCESS); rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap()); + // TODO(Subv): Connect the OnWifiPacketReceived function to the wifi packet received callback of + // the room we're currently in. + LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X", sharedmem_size, version, sharedmem_handle); } @@ -610,32 +744,23 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) return; - // TODO(Subv): Actually send the beacon. std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info); + using Network::WifiPacket; + WifiPacket packet; + packet.type = WifiPacket::PacketType::Beacon; + packet.data = std::move(frame); + packet.destination_address = Network::BroadcastMac; + packet.channel = network_channel; + + SendPacket(packet); + // Start broadcasting the network, send a beacon frame every 102.4ms. CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late, beacon_broadcast_event, 0); } /* - * Returns an available index in the nodes array for the - * currently-hosted UDS network. - */ -static u32 GetNextAvailableNodeId() { - ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost), - "Can not accept clients if we're not hosting a network"); - - for (unsigned index = 0; index < connection_status.max_nodes; ++index) { - if ((connection_status.node_bitmask & (1 << index)) == 0) - return index; - } - - // Any connection attempts to an already full network should have been refused. - ASSERT_MSG(false, "No available connection slots in the network"); -} - -/* * Called when a client connects to an UDS network we're hosting, * updates the connection status and signals the update event. * @param network_node_id Network Node Id of the connecting client. diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index 141f49f9c..f1caaf974 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -42,6 +42,7 @@ using NodeList = std::vector<NodeInfo>; enum class NetworkStatus { NotConnected = 3, ConnectedAsHost = 6, + Connecting = 7, ConnectedAsClient = 9, ConnectedAsSpectator = 10, }; @@ -85,6 +86,17 @@ static_assert(offsetof(NetworkInfo, oui_value) == 0xC, "oui_value is at the wron static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset."); static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size."); +/// Additional block tag ids in the Beacon and Association Response frames +enum class TagId : u8 { + SSID = 0, + SupportedRates = 1, + DSParameterSet = 2, + TrafficIndicationMap = 5, + CountryInformation = 7, + ERPInformation = 42, + VendorSpecific = 221 +}; + class NWM_UDS final : public Interface { public: NWM_UDS(); diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp index 6332b404c..552eaf65e 100644 --- a/src/core/hle/service/nwm/uds_beacon.cpp +++ b/src/core/hle/service/nwm/uds_beacon.cpp @@ -325,8 +325,5 @@ std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeL return buffer; } -std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender) { - return {}; -} } // namespace NWM } // namespace Service diff --git a/src/core/hle/service/nwm/uds_beacon.h b/src/core/hle/service/nwm/uds_beacon.h index caacf4c6f..50cc76da2 100644 --- a/src/core/hle/service/nwm/uds_beacon.h +++ b/src/core/hle/service/nwm/uds_beacon.h @@ -17,17 +17,6 @@ namespace NWM { using MacAddress = std::array<u8, 6>; constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; -/// Additional block tag ids in the Beacon frames -enum class TagId : u8 { - SSID = 0, - SupportedRates = 1, - DSParameterSet = 2, - TrafficIndicationMap = 5, - CountryInformation = 7, - ERPInformation = 42, - VendorSpecific = 221 -}; - /** * Internal vendor-specific tag ids as stored inside * VendorSpecific blocks in the Beacon frames. @@ -135,20 +124,6 @@ struct BeaconData { static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); -/// Information about a received WiFi packet. -/// Acts as our own 802.11 header. -struct WifiPacket { - enum class PacketType { Beacon, Data }; - - PacketType type; ///< The type of 802.11 frame, Beacon / Data. - - /// Raw 802.11 frame data, starting at the management frame header for management frames. - std::vector<u8> data; - MacAddress transmitter_address; ///< Mac address of the transmitter. - MacAddress destination_address; ///< Mac address of the receiver. - u8 channel; ///< WiFi channel where this frame was transmitted. -}; - /** * Decrypts the beacon data buffer for the network described by `network_info`. */ @@ -161,10 +136,5 @@ void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer) */ std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes); -/** - * Returns a list of received 802.11 frames from the specified sender - * matching the type since the last call. - */ -std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender); } // namespace NWM } // namespace Service diff --git a/src/core/hle/service/nwm/uds_connection.cpp b/src/core/hle/service/nwm/uds_connection.cpp new file mode 100644 index 000000000..c8a76ec2a --- /dev/null +++ b/src/core/hle/service/nwm/uds_connection.cpp @@ -0,0 +1,79 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/nwm/nwm_uds.h" +#include "core/hle/service/nwm/uds_connection.h" +#include "fmt/format.h" + +namespace Service { +namespace NWM { + +// Note: These values were taken from a packet capture of an o3DS XL +// broadcasting a Super Smash Bros. 4 lobby. +constexpr u16 DefaultExtraCapabilities = 0x0431; + +std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq) { + AuthenticationFrame frame{}; + frame.auth_seq = static_cast<u16>(seq); + + std::vector<u8> data(sizeof(frame)); + std::memcpy(data.data(), &frame, sizeof(frame)); + + return data; +} + +AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body) { + AuthenticationFrame frame; + std::memcpy(&frame, body.data(), sizeof(frame)); + + return static_cast<AuthenticationSeq>(frame.auth_seq); +} + +/** + * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte character representation of the + * specified network id as the SSID value. + * @param network_id The network id to use. + * @returns A buffer with the SSID tag. + */ +static std::vector<u8> GenerateSSIDTag(u32 network_id) { + constexpr u8 SSIDSize = 8; + + struct { + u8 id = static_cast<u8>(TagId::SSID); + u8 size = SSIDSize; + } tag_header; + + std::vector<u8> buffer(sizeof(tag_header) + SSIDSize); + + std::memcpy(buffer.data(), &tag_header, sizeof(tag_header)); + + std::string network_name = fmt::format("{0:08X}", network_id); + + std::memcpy(buffer.data() + sizeof(tag_header), network_name.c_str(), SSIDSize); + + return buffer; +} + +std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id) { + AssociationResponseFrame frame{}; + frame.capabilities = DefaultExtraCapabilities; + frame.status_code = static_cast<u16>(status); + // The association id is ORed with this magic value (0xC000) + constexpr u16 AssociationIdMagic = 0xC000; + frame.assoc_id = association_id | AssociationIdMagic; + + std::vector<u8> data(sizeof(frame)); + std::memcpy(data.data(), &frame, sizeof(frame)); + + auto ssid_tag = GenerateSSIDTag(network_id); + data.insert(data.end(), ssid_tag.begin(), ssid_tag.end()); + + // TODO(Subv): Add the SupportedRates tag. + // TODO(Subv): Add the DSParameterSet tag. + // TODO(Subv): Add the ERPInformation tag. + return data; +} + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/service/nwm/uds_connection.h b/src/core/hle/service/nwm/uds_connection.h new file mode 100644 index 000000000..73f55a4fd --- /dev/null +++ b/src/core/hle/service/nwm/uds_connection.h @@ -0,0 +1,51 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NWM { + +/// Sequence number of the 802.11 authentication frames. +enum class AuthenticationSeq : u16 { SEQ1 = 1, SEQ2 = 2 }; + +enum class AuthAlgorithm : u16 { OpenSystem = 0 }; + +enum class AuthStatus : u16 { Successful = 0 }; + +enum class AssocStatus : u16 { Successful = 0 }; + +struct AuthenticationFrame { + u16_le auth_algorithm = static_cast<u16>(AuthAlgorithm::OpenSystem); + u16_le auth_seq; + u16_le status_code = static_cast<u16>(AuthStatus::Successful); +}; + +static_assert(sizeof(AuthenticationFrame) == 6, "AuthenticationFrame has wrong size"); + +struct AssociationResponseFrame { + u16_le capabilities; + u16_le status_code; + u16_le assoc_id; +}; + +static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame has wrong size"); + +/// Generates an 802.11 authentication frame, starting at the frame body. +std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq); + +/// Returns the sequence number from the body of an Authentication frame. +AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body); + +/// Generates an 802.11 association response frame with the specified status, association id and +/// network id, starting at the frame body. +std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id); + +} // namespace NWM +} // namespace Service diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index e4b803046..dfc36748c 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -31,6 +31,7 @@ #include "core/hle/kernel/timer.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" +#include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -1188,7 +1189,7 @@ struct FunctionDef { Func* func; const char* name; }; -} +} // namespace static const FunctionDef SVC_Table[] = { {0x00, nullptr, "Unknown"}, @@ -1332,6 +1333,9 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void CallSVC(u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); + // Lock the global kernel mutex when we enter the kernel HLE. + std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); + const FunctionDef* info = GetSVCInfo(immediate); if (info) { if (info->func) { @@ -1342,4 +1346,4 @@ void CallSVC(u32 immediate) { } } -} // namespace +} // namespace SVC |
