2015-05-13 02:38:29 +01:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2015-06-21 13:12:49 +01:00
|
|
|
#include <cstddef>
|
2016-06-27 18:42:42 +01:00
|
|
|
#include <string>
|
2015-05-13 02:38:29 +01:00
|
|
|
#include "common/common_types.h"
|
2019-03-02 20:20:28 +00:00
|
|
|
|
|
|
|
namespace Common {
|
|
|
|
struct PageTable;
|
|
|
|
}
|
2015-05-13 02:38:29 +01:00
|
|
|
|
2017-09-26 23:27:44 +01:00
|
|
|
namespace Kernel {
|
|
|
|
class Process;
|
|
|
|
}
|
2015-05-13 02:38:29 +01:00
|
|
|
|
|
|
|
namespace Memory {
|
|
|
|
|
2015-05-13 03:38:56 +01:00
|
|
|
/**
|
|
|
|
* Page size used by the ARM architecture. This is the smallest granularity with which memory can
|
|
|
|
* be mapped.
|
|
|
|
*/
|
2018-09-15 14:21:06 +01:00
|
|
|
constexpr std::size_t PAGE_BITS = 12;
|
2018-09-24 15:29:56 +01:00
|
|
|
constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS;
|
2018-02-12 21:53:32 +00:00
|
|
|
constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
|
2015-05-13 02:38:29 +01:00
|
|
|
|
|
|
|
/// Virtual user-space memory regions
|
|
|
|
enum : VAddr {
|
2018-09-25 01:01:45 +01:00
|
|
|
/// TLS (Thread-Local Storage) related.
|
2018-03-15 02:06:57 +00:00
|
|
|
TLS_ENTRY_SIZE = 0x200,
|
|
|
|
|
|
|
|
/// Application stack
|
2018-03-31 20:03:28 +01:00
|
|
|
DEFAULT_STACK_SIZE = 0x100000,
|
2018-03-15 02:06:57 +00:00
|
|
|
|
2018-06-22 07:47:59 +01:00
|
|
|
/// Kernel Virtual Address Range
|
|
|
|
KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
|
|
|
|
KERNEL_REGION_SIZE = 0x7FFFE00000,
|
|
|
|
KERNEL_REGION_END = KERNEL_REGION_VADDR + KERNEL_REGION_SIZE,
|
2015-05-13 02:38:29 +01:00
|
|
|
};
|
|
|
|
|
core/cpu_core_manager: Create threads separately from initialization.
Our initialization process is a little wonky than one would expect when
it comes to code flow. We initialize the CPU last, as opposed to
hardware, where the CPU obviously needs to be first, otherwise nothing
else would work, and we have code that adds checks to get around this.
For example, in the page table setting code, we check to see if the
system is turned on before we even notify the CPU instances of a page
table switch. This results in dead code (at the moment), because the
only time a page table switch will occur is when the system is *not*
running, preventing the emulated CPU instances from being notified of a
page table switch in a convenient manner (technically the code path
could be taken, but we don't emulate the process creation svc handlers
yet).
This moves the threads creation into its own member function of the core
manager and restores a little order (and predictability) to our
initialization process.
Previously, in the multi-threaded cases, we'd kick off several threads
before even the main kernel process was created and ready to execute (gross!).
Now the initialization process is like so:
Initialization:
1. Timers
2. CPU
3. Kernel
4. Filesystem stuff (kind of gross, but can be amended trivially)
5. Applet stuff (ditto in terms of being kind of gross)
6. Main process (will be moved into the loading step in a following
change)
7. Telemetry (this should be initialized last in the future).
8. Services (4 and 5 should ideally be alongside this).
9. GDB (gross. Uses namespace scope state. Needs to be refactored into a
class or booted altogether).
10. Renderer
11. GPU (will also have its threads created in a separate step in a
following change).
Which... isn't *ideal* per-se, however getting rid of the wonky
intertwining of CPU state initialization out of this mix gets rid of
most of the footguns when it comes to our initialization process.
2019-04-09 18:25:54 +01:00
|
|
|
/// Changes the currently active page table to that of
|
|
|
|
/// the given process instance.
|
|
|
|
void SetCurrentPageTable(Kernel::Process& process);
|
2017-07-22 03:17:57 +01:00
|
|
|
|
2017-09-26 23:27:44 +01:00
|
|
|
/// Determines if the given VAddr is valid for the specified process.
|
2018-08-06 02:31:56 +01:00
|
|
|
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
|
2018-08-06 02:36:44 +01:00
|
|
|
bool IsValidVirtualAddress(VAddr vaddr);
|
2018-06-22 07:47:59 +01:00
|
|
|
/// Determines if the given VAddr is a kernel address
|
2018-08-06 02:36:44 +01:00
|
|
|
bool IsKernelVirtualAddress(VAddr vaddr);
|
2017-09-26 23:27:44 +01:00
|
|
|
|
2015-05-13 02:38:29 +01:00
|
|
|
u8 Read8(VAddr addr);
|
|
|
|
u16 Read16(VAddr addr);
|
|
|
|
u32 Read32(VAddr addr);
|
|
|
|
u64 Read64(VAddr addr);
|
|
|
|
|
|
|
|
void Write8(VAddr addr, u8 data);
|
|
|
|
void Write16(VAddr addr, u16 data);
|
|
|
|
void Write32(VAddr addr, u32 data);
|
|
|
|
void Write64(VAddr addr, u64 data);
|
|
|
|
|
2018-09-15 14:21:06 +01:00
|
|
|
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
|
|
|
|
void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
|
2018-08-06 02:31:56 +01:00
|
|
|
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
2018-09-15 14:21:06 +01:00
|
|
|
std::size_t size);
|
|
|
|
void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
|
|
|
|
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
|
|
|
|
void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
|
2015-05-13 02:38:29 +01:00
|
|
|
|
2018-08-06 02:36:44 +01:00
|
|
|
u8* GetPointer(VAddr vaddr);
|
2015-05-13 02:38:29 +01:00
|
|
|
|
2018-08-06 02:36:44 +01:00
|
|
|
std::string ReadCString(VAddr vaddr, std::size_t max_length);
|
2016-06-27 18:42:42 +01:00
|
|
|
|
2018-03-25 03:21:14 +01:00
|
|
|
/**
|
|
|
|
* Mark each page touching the region as cached.
|
|
|
|
*/
|
2018-08-28 02:35:15 +01:00
|
|
|
void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
|
2018-03-25 03:21:14 +01:00
|
|
|
|
2017-07-22 03:17:57 +01:00
|
|
|
} // namespace Memory
|