mirror of
https://github.com/PabloMK7/citra.git
synced 2024-11-16 20:07:16 +01:00
kernel: pass ref to shared memory
This commit is contained in:
parent
2a411bb501
commit
87426b29ff
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/applets/erreula.h"
|
#include "core/hle/applets/erreula.h"
|
||||||
#include "core/hle/service/apt/apt.h"
|
#include "core/hle/service/apt/apt.h"
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
|||||||
// Allocate a heap block of the required size for this applet.
|
// Allocate a heap block of the required size for this applet.
|
||||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet(
|
||||||
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||||
"ErrEula Memory");
|
"ErrEula Memory");
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/applets/mii_selector.h"
|
#include "core/hle/applets/mii_selector.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
@ -37,7 +38,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
|||||||
// Allocate a heap block of the required size for this applet.
|
// Allocate a heap block of the required size for this applet.
|
||||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet(
|
||||||
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||||
"MiiSelector Memory");
|
"MiiSelector Memory");
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/applets/mint.h"
|
#include "core/hle/applets/mint.h"
|
||||||
#include "core/hle/service/apt/apt.h"
|
#include "core/hle/service/apt/apt.h"
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ ResultCode Mint::ReceiveParameter(const Service::APT::MessageParameter& paramete
|
|||||||
// Allocate a heap block of the required size for this applet.
|
// Allocate a heap block of the required size for this applet.
|
||||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet(
|
||||||
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||||
"Mint Memory");
|
"Mint Memory");
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/applets/swkbd.h"
|
#include "core/hle/applets/swkbd.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
@ -41,7 +42,7 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
|||||||
// Allocate a heap block of the required size for this applet.
|
// Allocate a heap block of the required size for this applet.
|
||||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||||
// Create a SharedMemory that directly points to this heap block.
|
// Create a SharedMemory that directly points to this heap block.
|
||||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
framebuffer_memory = Core::System::GetInstance().Kernel().CreateSharedMemoryForApplet(
|
||||||
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
heap_memory, 0, capture_info.size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||||
"SoftwareKeyboard Memory");
|
"SoftwareKeyboard Memory");
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ class ServerPort;
|
|||||||
class ClientSession;
|
class ClientSession;
|
||||||
class ServerSession;
|
class ServerSession;
|
||||||
class ResourceLimitList;
|
class ResourceLimitList;
|
||||||
|
class SharedMemory;
|
||||||
|
|
||||||
enum class ResetType {
|
enum class ResetType {
|
||||||
OneShot,
|
OneShot,
|
||||||
@ -32,6 +33,25 @@ enum class ResetType {
|
|||||||
Pulse,
|
Pulse,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Permissions for mapped shared memory blocks
|
||||||
|
enum class MemoryPermission : u32 {
|
||||||
|
None = 0,
|
||||||
|
Read = (1u << 0),
|
||||||
|
Write = (1u << 1),
|
||||||
|
ReadWrite = (Read | Write),
|
||||||
|
Execute = (1u << 2),
|
||||||
|
ReadExecute = (Read | Execute),
|
||||||
|
WriteExecute = (Write | Execute),
|
||||||
|
ReadWriteExecute = (Read | Write | Execute),
|
||||||
|
DontCare = (1u << 28)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MemoryRegion : u16 {
|
||||||
|
APPLICATION = 1,
|
||||||
|
SYSTEM = 2,
|
||||||
|
BASE = 3,
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using SharedPtr = boost::intrusive_ptr<T>;
|
using SharedPtr = boost::intrusive_ptr<T>;
|
||||||
|
|
||||||
@ -122,6 +142,41 @@ public:
|
|||||||
ResourceLimitList& ResourceLimit();
|
ResourceLimitList& ResourceLimit();
|
||||||
const ResourceLimitList& ResourceLimit() const;
|
const ResourceLimitList& ResourceLimit() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a shared memory object.
|
||||||
|
* @param owner_process Process that created this shared memory object.
|
||||||
|
* @param size Size of the memory block. Must be page-aligned.
|
||||||
|
* @param permissions Permission restrictions applied to the process which created the block.
|
||||||
|
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||||
|
* block.
|
||||||
|
* @param address The address from which to map the Shared Memory.
|
||||||
|
* @param region If the address is 0, the shared memory will be allocated in this region of the
|
||||||
|
* linear heap.
|
||||||
|
* @param name Optional object name, used for debugging purposes.
|
||||||
|
*/
|
||||||
|
SharedPtr<SharedMemory> CreateSharedMemory(SharedPtr<Process> owner_process, u32 size,
|
||||||
|
MemoryPermission permissions,
|
||||||
|
MemoryPermission other_permissions,
|
||||||
|
VAddr address = 0,
|
||||||
|
MemoryRegion region = MemoryRegion::BASE,
|
||||||
|
std::string name = "Unknown");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
||||||
|
* @param heap_block Heap block of the HLE applet.
|
||||||
|
* @param offset The offset into the heap block that the SharedMemory will map.
|
||||||
|
* @param size Size of the memory block. Must be page-aligned.
|
||||||
|
* @param permissions Permission restrictions applied to the process which created the block.
|
||||||
|
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||||
|
* block.
|
||||||
|
* @param name Optional object name, used for debugging purposes.
|
||||||
|
*/
|
||||||
|
SharedPtr<SharedMemory> CreateSharedMemoryForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
||||||
|
u32 offset, u32 size,
|
||||||
|
MemoryPermission permissions,
|
||||||
|
MemoryPermission other_permissions,
|
||||||
|
std::string name = "Unknown Applet");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ResourceLimitList> resource_limits;
|
std::unique_ptr<ResourceLimitList> resource_limits;
|
||||||
};
|
};
|
||||||
|
@ -26,12 +26,6 @@ struct AddressMapping {
|
|||||||
bool unk_flag;
|
bool unk_flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MemoryRegion : u16 {
|
|
||||||
APPLICATION = 1,
|
|
||||||
SYSTEM = 2,
|
|
||||||
BASE = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
union ProcessFlags {
|
union ProcessFlags {
|
||||||
u16 raw;
|
u16 raw;
|
||||||
|
|
||||||
|
@ -11,14 +11,15 @@
|
|||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
SharedMemory::SharedMemory() {}
|
SharedMemory::SharedMemory(KernelSystem& system) {}
|
||||||
SharedMemory::~SharedMemory() {}
|
SharedMemory::~SharedMemory() {}
|
||||||
|
|
||||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size,
|
SharedPtr<SharedMemory> KernelSystem::CreateSharedMemory(SharedPtr<Process> owner_process, u32 size,
|
||||||
MemoryPermission permissions,
|
MemoryPermission permissions,
|
||||||
MemoryPermission other_permissions, VAddr address,
|
MemoryPermission other_permissions,
|
||||||
MemoryRegion region, std::string name) {
|
VAddr address, MemoryRegion region,
|
||||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
std::string name) {
|
||||||
|
SharedPtr<SharedMemory> shared_memory(new SharedMemory(*this));
|
||||||
|
|
||||||
shared_memory->owner_process = owner_process;
|
shared_memory->owner_process = owner_process;
|
||||||
shared_memory->name = std::move(name);
|
shared_memory->name = std::move(name);
|
||||||
@ -74,12 +75,10 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
|||||||
return shared_memory;
|
return shared_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
SharedPtr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
||||||
u32 offset, u32 size,
|
std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, MemoryPermission permissions,
|
||||||
MemoryPermission permissions,
|
MemoryPermission other_permissions, std::string name) {
|
||||||
MemoryPermission other_permissions,
|
SharedPtr<SharedMemory> shared_memory(new SharedMemory(*this));
|
||||||
std::string name) {
|
|
||||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
|
||||||
|
|
||||||
shared_memory->owner_process = nullptr;
|
shared_memory->owner_process = nullptr;
|
||||||
shared_memory->name = std::move(name);
|
shared_memory->name = std::move(name);
|
||||||
|
@ -12,55 +12,8 @@
|
|||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// Permissions for mapped shared memory blocks
|
|
||||||
enum class MemoryPermission : u32 {
|
|
||||||
None = 0,
|
|
||||||
Read = (1u << 0),
|
|
||||||
Write = (1u << 1),
|
|
||||||
ReadWrite = (Read | Write),
|
|
||||||
Execute = (1u << 2),
|
|
||||||
ReadExecute = (Read | Execute),
|
|
||||||
WriteExecute = (Write | Execute),
|
|
||||||
ReadWriteExecute = (Read | Write | Execute),
|
|
||||||
DontCare = (1u << 28)
|
|
||||||
};
|
|
||||||
|
|
||||||
class SharedMemory final : public Object {
|
class SharedMemory final : public Object {
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* Creates a shared memory object.
|
|
||||||
* @param owner_process Process that created this shared memory object.
|
|
||||||
* @param size Size of the memory block. Must be page-aligned.
|
|
||||||
* @param permissions Permission restrictions applied to the process which created the block.
|
|
||||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
|
||||||
* block.
|
|
||||||
* @param address The address from which to map the Shared Memory.
|
|
||||||
* @param region If the address is 0, the shared memory will be allocated in this region of the
|
|
||||||
* linear heap.
|
|
||||||
* @param name Optional object name, used for debugging purposes.
|
|
||||||
*/
|
|
||||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size,
|
|
||||||
MemoryPermission permissions,
|
|
||||||
MemoryPermission other_permissions, VAddr address = 0,
|
|
||||||
MemoryRegion region = MemoryRegion::BASE,
|
|
||||||
std::string name = "Unknown");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
|
||||||
* @param heap_block Heap block of the HLE applet.
|
|
||||||
* @param offset The offset into the heap block that the SharedMemory will map.
|
|
||||||
* @param size Size of the memory block. Must be page-aligned.
|
|
||||||
* @param permissions Permission restrictions applied to the process which created the block.
|
|
||||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
|
||||||
* block.
|
|
||||||
* @param name Optional object name, used for debugging purposes.
|
|
||||||
*/
|
|
||||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
|
||||||
u32 offset, u32 size,
|
|
||||||
MemoryPermission permissions,
|
|
||||||
MemoryPermission other_permissions,
|
|
||||||
std::string name = "Unknown Applet");
|
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "SharedMemory";
|
return "SharedMemory";
|
||||||
}
|
}
|
||||||
@ -125,8 +78,10 @@ public:
|
|||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedMemory();
|
explicit SharedMemory(KernelSystem& kernel);
|
||||||
~SharedMemory() override;
|
~SharedMemory() override;
|
||||||
|
|
||||||
|
friend class KernelSystem;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -1105,9 +1105,9 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
|
|||||||
if (addr == 0 && g_current_process->flags.shared_device_mem)
|
if (addr == 0 && g_current_process->flags.shared_device_mem)
|
||||||
region = g_current_process->flags.memory_region;
|
region = g_current_process->flags.memory_region;
|
||||||
|
|
||||||
shared_memory =
|
shared_memory = Core::System::GetInstance().Kernel().CreateSharedMemory(
|
||||||
SharedMemory::Create(g_current_process, size, static_cast<MemoryPermission>(my_permission),
|
g_current_process, size, static_cast<MemoryPermission>(my_permission),
|
||||||
static_cast<MemoryPermission>(other_permission), addr, region);
|
static_cast<MemoryPermission>(other_permission), addr, region);
|
||||||
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory)));
|
CASCADE_RESULT(*out_handle, g_handle_table.Create(std::move(shared_memory)));
|
||||||
|
|
||||||
LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
|
LOG_WARNING(Kernel_SVC, "called addr=0x{:08X}", addr);
|
||||||
|
@ -855,9 +855,9 @@ Module::Module(Core::System& system) : system(system) {
|
|||||||
|
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
shared_font_mem =
|
shared_font_mem =
|
||||||
Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
system.Kernel().CreateSharedMemory(nullptr, 0x332000, // 3272 KB
|
||||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
|
MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
|
||||||
Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||||
|
|
||||||
lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
|
lock = system.Kernel().CreateMutex(false, "APT_U:Lock");
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@ void CSND_SND::Initialize(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
mutex = system.Kernel().CreateMutex(false, "CSND:mutex");
|
mutex = system.Kernel().CreateMutex(false, "CSND:mutex");
|
||||||
shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite,
|
shared_memory = system.Kernel().CreateSharedMemory(
|
||||||
MemoryPermission::ReadWrite, 0,
|
nullptr, size, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0,
|
||||||
Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
|
Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
@ -786,9 +786,9 @@ GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 2), system
|
|||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite,
|
shared_memory = system.Kernel().CreateSharedMemory(
|
||||||
MemoryPermission::ReadWrite, 0,
|
nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0,
|
||||||
Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
|
Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
|
||||||
|
|
||||||
first_initialization = true;
|
first_initialization = true;
|
||||||
};
|
};
|
||||||
|
@ -359,9 +359,9 @@ std::shared_ptr<Module> Module::Interface::GetModule() const {
|
|||||||
Module::Module(Core::System& system) : system(system) {
|
Module::Module(Core::System& system) : system(system) {
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
shared_mem =
|
shared_mem = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
|
||||||
SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
|
MemoryPermission::Read, 0, MemoryRegion::BASE,
|
||||||
0, MemoryRegion::BASE, "HID:SharedMemory");
|
"HID:SharedMemory");
|
||||||
|
|
||||||
// Create event handles
|
// Create event handles
|
||||||
event_pad_or_touch_1 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch1");
|
event_pad_or_touch_1 = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventPadOrTouch1");
|
||||||
|
@ -149,9 +149,9 @@ IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) {
|
|||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
// Note: these two kernel objects are even available before Initialize service function is
|
// Note: these two kernel objects are even available before Initialize service function is
|
||||||
// called.
|
// called.
|
||||||
shared_memory =
|
shared_memory = system.Kernel().CreateSharedMemory(nullptr, 0x1000, MemoryPermission::ReadWrite,
|
||||||
SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
|
MemoryPermission::Read, 0,
|
||||||
0, MemoryRegion::BASE, "IRRST:SharedMemory");
|
MemoryRegion::BASE, "IRRST:SharedMemory");
|
||||||
update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent");
|
update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent");
|
||||||
|
|
||||||
update_callback_id =
|
update_callback_id =
|
||||||
|
Loading…
Reference in New Issue
Block a user