summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
blob: a48d0c11edc27f4b97f69bdaecaf736fe53259c6 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include <random>

#include "common/common_sizes.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
#include "core/hle/kernel/k_trace.h"

namespace Kernel::Board::Nintendo::Nx {

namespace impl {

constexpr inline const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
constexpr inline const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
constexpr inline const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;

} // namespace impl

constexpr inline const std::size_t RequiredNonSecureSystemMemorySize =
    impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
    impl::RequiredNonSecureSystemMemorySizeMisc;

namespace {

u32 GetMemoryModeForInit() {
    return 0x01;
}

u32 GetMemorySizeForInit() {
    return 0;
}

Smc::MemoryArrangement GetMemoryArrangeForInit() {
    switch (GetMemoryModeForInit() & 0x3F) {
    case 0x01:
    default:
        return Smc::MemoryArrangement_4GB;
    case 0x02:
        return Smc::MemoryArrangement_4GBForAppletDev;
    case 0x03:
        return Smc::MemoryArrangement_4GBForSystemDev;
    case 0x11:
        return Smc::MemoryArrangement_6GB;
    case 0x12:
        return Smc::MemoryArrangement_6GBForAppletDev;
    case 0x21:
        return Smc::MemoryArrangement_8GB;
    }
}
} // namespace

// Initialization.
size_t KSystemControl::Init::GetIntendedMemorySize() {
    switch (GetMemorySizeForInit()) {
    case Smc::MemorySize_4GB:
    default: // All invalid modes should go to 4GB.
        return Size_4_GB;
    case Smc::MemorySize_6GB:
        return Size_6_GB;
    case Smc::MemorySize_8GB:
        return Size_8_GB;
    }
}

PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
    return base_address;
}

bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
    return true;
}

std::size_t KSystemControl::Init::GetApplicationPoolSize() {
    // Get the base pool size.
    const size_t base_pool_size = []() -> size_t {
        switch (GetMemoryArrangeForInit()) {
        case Smc::MemoryArrangement_4GB:
        default:
            return Size_3285_MB;
        case Smc::MemoryArrangement_4GBForAppletDev:
            return Size_2048_MB;
        case Smc::MemoryArrangement_4GBForSystemDev:
            return Size_3285_MB;
        case Smc::MemoryArrangement_6GB:
            return Size_4916_MB;
        case Smc::MemoryArrangement_6GBForAppletDev:
            return Size_3285_MB;
        case Smc::MemoryArrangement_8GB:
            return Size_4916_MB;
        }
    }();

    // Return (possibly) adjusted size.
    return base_pool_size;
}

size_t KSystemControl::Init::GetAppletPoolSize() {
    // Get the base pool size.
    const size_t base_pool_size = []() -> size_t {
        switch (GetMemoryArrangeForInit()) {
        case Smc::MemoryArrangement_4GB:
        default:
            return Size_507_MB;
        case Smc::MemoryArrangement_4GBForAppletDev:
            return Size_1554_MB;
        case Smc::MemoryArrangement_4GBForSystemDev:
            return Size_448_MB;
        case Smc::MemoryArrangement_6GB:
            return Size_562_MB;
        case Smc::MemoryArrangement_6GBForAppletDev:
            return Size_2193_MB;
        case Smc::MemoryArrangement_8GB:
            return Size_2193_MB;
        }
    }();

    // Return (possibly) adjusted size.
    constexpr size_t ExtraSystemMemoryForAtmosphere = Size_33_MB;
    return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}

size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
    // Verify that our minimum is at least as large as Nintendo's.
    constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
    static_assert(MinimumSize >= 0x29C8000);

    return MinimumSize;
}

namespace {
template <typename F>
u64 GenerateUniformRange(u64 min, u64 max, F f) {
    // Handle the case where the difference is too large to represent.
    if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
        return f();
    }

    // Iterate until we get a value in range.
    const u64 range_size = ((max + 1) - min);
    const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
    while (true) {
        if (const u64 rnd = f(); rnd < effective_max) {
            return min + (rnd % range_size);
        }
    }
}

} // Anonymous namespace

u64 KSystemControl::GenerateRandomU64() {
    static std::random_device device;
    static std::mt19937 gen(device());
    static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
    return distribution(gen);
}

u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
    return GenerateUniformRange(min, max, GenerateRandomU64);
}

} // namespace Kernel::Board::Nintendo::Nx