summaryrefslogtreecommitdiffstats
path: root/src/core/mem_map.cpp
blob: 66d95ed27cd97a586370e221cf1326d9d2cc84e1 (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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include <map>

#include "common/common_types.h"
#include "common/logging/log.h"

#include "core/hle/config_mem.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/result.h"
#include "core/hle/shared_page.h"
#include "core/mem_map.h"
#include "core/memory.h"
#include "core/memory_setup.h"

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Memory {

u8* g_exefs_code;  ///< ExeFS:/.code is loaded here
u8* g_heap;        ///< Application heap (main memory)
u8* g_shared_mem;  ///< Shared memory
u8* g_heap_linear; ///< Linear heap
u8* g_vram;        ///< Video memory (VRAM) pointer
u8* g_dsp_mem;     ///< DSP memory
u8* g_tls_mem;     ///< TLS memory

namespace {

struct MemoryArea {
    u8** ptr;
    u32 base;
    u32 size;
    const char* name;
};

// We don't declare the IO regions in here since its handled by other means.
static MemoryArea memory_areas[] = {
    {&g_exefs_code,  PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"},
    {&g_heap,        HEAP_VADDR,          HEAP_SIZE,              "Heap"},
    {&g_shared_mem,  SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE,     "Shared Memory"},
    {&g_heap_linear, LINEAR_HEAP_VADDR,   LINEAR_HEAP_SIZE,       "Linear Heap"},
    {&g_vram,        VRAM_VADDR,          VRAM_SIZE,              "VRAM"},
    {&g_dsp_mem,     DSP_RAM_VADDR,       DSP_RAM_SIZE,           "DSP RAM"},
    {&g_tls_mem,     TLS_AREA_VADDR,      TLS_AREA_SIZE,          "TLS Area"},
};

/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
struct MemoryBlock {
    MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) {
    }
    u32 handle;
    u32 base_address;
    u32 address;
    u32 size;
    u32 operation;
    u32 permissions;

    const u32 GetVirtualAddress() const{
        return base_address + address;
    }
};

static std::map<u32, MemoryBlock> heap_map;
static std::map<u32, MemoryBlock> heap_linear_map;

}

u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
    MemoryBlock block;

    block.base_address  = HEAP_VADDR;
    block.size          = size;
    block.operation     = operation;
    block.permissions   = permissions;

    if (heap_map.size() > 0) {
        const MemoryBlock last_block = heap_map.rbegin()->second;
        block.address = last_block.address + last_block.size;
    }
    heap_map[block.GetVirtualAddress()] = block;

    return block.GetVirtualAddress();
}

u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
    MemoryBlock block;

    block.base_address  = LINEAR_HEAP_VADDR;
    block.size          = size;
    block.operation     = operation;
    block.permissions   = permissions;

    if (heap_linear_map.size() > 0) {
        const MemoryBlock last_block = heap_linear_map.rbegin()->second;
        block.address = last_block.address + last_block.size;
    }
    heap_linear_map[block.GetVirtualAddress()] = block;

    return block.GetVirtualAddress();
}

PAddr VirtualToPhysicalAddress(const VAddr addr) {
    if (addr == 0) {
        return 0;
    } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
        return addr - VRAM_VADDR + VRAM_PADDR;
    } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
        return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
    } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
        return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
    } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
        return addr - IO_AREA_VADDR + IO_AREA_PADDR;
    }

    LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
    // To help with debugging, set bit on address so that it's obviously invalid.
    return addr | 0x80000000;
}

VAddr PhysicalToVirtualAddress(const PAddr addr) {
    if (addr == 0) {
        return 0;
    } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
        return addr - VRAM_PADDR + VRAM_VADDR;
    } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
        return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR;
    } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
        return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
    } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
        return addr - IO_AREA_PADDR + IO_AREA_VADDR;
    }

    LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
    // To help with debugging, set bit on address so that it's obviously invalid.
    return addr | 0x80000000;
}

// TODO(yuriks): Move this into Process
static Kernel::VMManager address_space;

void Init() {
    using namespace Kernel;

    InitMemoryMap();

    for (MemoryArea& area : memory_areas) {
        auto block = std::make_shared<std::vector<u8>>(area.size);
        *area.ptr = block->data(); // TODO(yuriks): Remove
        address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
    }

    auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
            (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
    address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);

    auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
            (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
    address_space.Reprotect(shared_page_vma, VMAPermission::Read);

    LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap);
}

void Shutdown() {
    heap_map.clear();
    heap_linear_map.clear();

    address_space.Reset();

    for (MemoryArea& area : memory_areas) {
        *area.ptr = nullptr;
    }

    LOG_DEBUG(HW_Memory, "shutdown OK");
}

} // namespace