summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/svc/svc_shared_memory.cpp
blob: 012b1ae2bce20c31b0761fb69370a24fa546f8ae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/svc.h"

namespace Kernel::Svc {
namespace {

constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) {
    switch (perm) {
    case MemoryPermission::Read:
    case MemoryPermission::ReadWrite:
        return true;
    default:
        return false;
    }
}

[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(MemoryPermission perm) {
    return IsValidSharedMemoryPermission(perm) || perm == MemoryPermission::DontCare;
}

} // namespace

Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u64 size,
                       Svc::MemoryPermission map_perm) {
    LOG_TRACE(Kernel_SVC,
              "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
              shmem_handle, address, size, map_perm);

    // Validate the address/size.
    R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
    R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
    R_UNLESS(size > 0, ResultInvalidSize);
    R_UNLESS((address < address + size), ResultInvalidCurrentMemory);

    // Validate the permission.
    R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);

    // Get the current process.
    auto& process = GetCurrentProcess(system.Kernel());
    auto& page_table = process.GetPageTable();

    // Get the shared memory.
    KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
    R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);

    // Verify that the mapping is in range.
    R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);

    // Add the shared memory to the process.
    R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));

    // Ensure that we clean up the shared memory if we fail to map it.
    ON_RESULT_FAILURE {
        process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
    };

    // Map the shared memory.
    R_RETURN(shmem->Map(process, address, size, map_perm));
}

Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u64 size) {
    // Validate the address/size.
    R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
    R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
    R_UNLESS(size > 0, ResultInvalidSize);
    R_UNLESS((address < address + size), ResultInvalidCurrentMemory);

    // Get the current process.
    auto& process = GetCurrentProcess(system.Kernel());
    auto& page_table = process.GetPageTable();

    // Get the shared memory.
    KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
    R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);

    // Verify that the mapping is in range.
    R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);

    // Unmap the shared memory.
    R_TRY(shmem->Unmap(process, address, size));

    // Remove the shared memory from the process.
    process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);

    R_SUCCEED();
}

Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size,
                          MemoryPermission owner_perm, MemoryPermission remote_perm) {
    UNIMPLEMENTED();
    R_THROW(ResultNotImplemented);
}

Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size,
                         MemoryPermission map_perm) {
    R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
}

Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address,
                           uint64_t size) {
    R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
}

Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size,
                            MemoryPermission owner_perm, MemoryPermission remote_perm) {
    R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
}

Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
                               uint32_t size, MemoryPermission map_perm) {
    R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
}

Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
                                 uint32_t size) {
    R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
}

Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size,
                                  MemoryPermission owner_perm, MemoryPermission remote_perm) {
    R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
}

} // namespace Kernel::Svc