summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/process.cpp')
-rw-r--r--src/core/hle/kernel/process.cpp185
1 files changed, 124 insertions, 61 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index bf727901d..36724569f 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -10,15 +10,18 @@
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/core.h" 12#include "core/core.h"
13#include "core/device_memory.h"
13#include "core/file_sys/program_metadata.h" 14#include "core/file_sys/program_metadata.h"
14#include "core/hle/kernel/code_set.h" 15#include "core/hle/kernel/code_set.h"
15#include "core/hle/kernel/errors.h" 16#include "core/hle/kernel/errors.h"
16#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/memory/memory_block_manager.h"
19#include "core/hle/kernel/memory/page_table.h"
20#include "core/hle/kernel/memory/slab_heap.h"
17#include "core/hle/kernel/process.h" 21#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/resource_limit.h" 22#include "core/hle/kernel/resource_limit.h"
19#include "core/hle/kernel/scheduler.h" 23#include "core/hle/kernel/scheduler.h"
20#include "core/hle/kernel/thread.h" 24#include "core/hle/kernel/thread.h"
21#include "core/hle/kernel/vm_manager.h"
22#include "core/memory.h" 25#include "core/memory.h"
23#include "core/settings.h" 26#include "core/settings.h"
24 27
@@ -31,10 +34,8 @@ namespace {
31 * @param kernel The kernel instance to create the main thread under. 34 * @param kernel The kernel instance to create the main thread under.
32 * @param priority The priority to give the main thread 35 * @param priority The priority to give the main thread
33 */ 36 */
34void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { 37void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority, VAddr stack_top) {
35 const auto& vm_manager = owner_process.VMManager(); 38 const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
36 const VAddr entry_point = vm_manager.GetCodeRegionBaseAddress();
37 const VAddr stack_top = vm_manager.GetTLSIORegionEndAddress();
38 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, 39 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0,
39 owner_process.GetIdealCore(), stack_top, owner_process); 40 owner_process.GetIdealCore(), stack_top, owner_process);
40 41
@@ -109,7 +110,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
109 110
110 std::shared_ptr<Process> process = std::make_shared<Process>(system); 111 std::shared_ptr<Process> process = std::make_shared<Process>(system);
111 process->name = std::move(name); 112 process->name = std::move(name);
112 process->resource_limit = kernel.GetSystemResourceLimit(); 113 process->resource_limit = ResourceLimit::Create(kernel);
113 process->status = ProcessStatus::Created; 114 process->status = ProcessStatus::Created;
114 process->program_id = 0; 115 process->program_id = 0;
115 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() 116 process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -130,7 +131,14 @@ std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
130} 131}
131 132
132u64 Process::GetTotalPhysicalMemoryAvailable() const { 133u64 Process::GetTotalPhysicalMemoryAvailable() const {
133 return vm_manager.GetTotalPhysicalMemoryAvailable(); 134 const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
135 page_table->GetTotalHeapSize() + image_size + main_thread_stack_size};
136
137 if (capacity < memory_usage_capacity) {
138 return capacity;
139 }
140
141 return memory_usage_capacity;
134} 142}
135 143
136u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const { 144u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
@@ -138,8 +146,7 @@ u64 Process::GetTotalPhysicalMemoryAvailableWithoutSystemResource() const {
138} 146}
139 147
140u64 Process::GetTotalPhysicalMemoryUsed() const { 148u64 Process::GetTotalPhysicalMemoryUsed() const {
141 return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size + 149 return image_size + main_thread_stack_size + page_table->GetTotalHeapSize();
142 GetSystemResourceUsage();
143} 150}
144 151
145u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const { 152u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
@@ -212,33 +219,82 @@ ResultCode Process::ClearSignalState() {
212 return RESULT_SUCCESS; 219 return RESULT_SUCCESS;
213} 220}
214 221
215ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 222ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
223 std::size_t code_size) {
216 program_id = metadata.GetTitleID(); 224 program_id = metadata.GetTitleID();
217 ideal_core = metadata.GetMainThreadCore(); 225 ideal_core = metadata.GetMainThreadCore();
218 is_64bit_process = metadata.Is64BitProgram(); 226 is_64bit_process = metadata.Is64BitProgram();
219 system_resource_size = metadata.GetSystemResourceSize(); 227 system_resource_size = metadata.GetSystemResourceSize();
228 image_size = code_size;
229
230 // Initialize proces address space
231 if (const ResultCode result{
232 page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000,
233 code_size, Memory::MemoryManager::Pool::Application)};
234 result.IsError()) {
235 return result;
236 }
220 237
221 vm_manager.Reset(metadata.GetAddressSpaceType()); 238 // Map process code region
239 if (const ResultCode result{page_table->MapProcessCode(
240 page_table->GetCodeRegionStart(), code_size / Memory::PageSize,
241 Memory::MemoryState::Code, Memory::MemoryPermission::None)};
242 result.IsError()) {
243 return result;
244 }
222 245
223 const auto& caps = metadata.GetKernelCapabilities(); 246 // Initialize process capabilities
224 const auto capability_init_result = 247 const auto& caps{metadata.GetKernelCapabilities()};
225 capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); 248 if (const ResultCode result{
226 if (capability_init_result.IsError()) { 249 capabilities.InitializeForUserProcess(caps.data(), caps.size(), *page_table)};
227 return capability_init_result; 250 result.IsError()) {
251 return result;
228 } 252 }
229 253
254 // Set memory usage capacity
255 switch (metadata.GetAddressSpaceType()) {
256 case FileSys::ProgramAddressSpaceType::Is32Bit:
257 case FileSys::ProgramAddressSpaceType::Is36Bit:
258 case FileSys::ProgramAddressSpaceType::Is39Bit:
259 memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart();
260 break;
261
262 case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
263 memory_usage_capacity = page_table->GetHeapRegionEnd() - page_table->GetHeapRegionStart() +
264 page_table->GetAliasRegionEnd() - page_table->GetAliasRegionStart();
265 break;
266
267 default:
268 UNREACHABLE();
269 }
270
271 // Set initial resource limits
272 resource_limit->SetLimitValue(
273 ResourceType::PhysicalMemory,
274 kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
275 resource_limit->SetLimitValue(ResourceType::Threads, 608);
276 resource_limit->SetLimitValue(ResourceType::Events, 700);
277 resource_limit->SetLimitValue(ResourceType::TransferMemory, 128);
278 resource_limit->SetLimitValue(ResourceType::Sessions, 894);
279 ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size));
280
281 // Create TLS region
282 tls_region_address = CreateTLSRegion();
283
230 return handle_table.SetSize(capabilities.GetHandleTableSize()); 284 return handle_table.SetSize(capabilities.GetHandleTableSize());
231} 285}
232 286
233void Process::Run(s32 main_thread_priority, u64 stack_size) { 287void Process::Run(s32 main_thread_priority, u64 stack_size) {
234 AllocateMainThreadStack(stack_size); 288 AllocateMainThreadStack(stack_size);
235 tls_region_address = CreateTLSRegion();
236 289
237 vm_manager.LogLayout(); 290 const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size};
291 ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError());
238 292
239 ChangeStatus(ProcessStatus::Running); 293 ChangeStatus(ProcessStatus::Running);
240 294
241 SetupMainThread(*this, kernel, main_thread_priority); 295 SetupMainThread(*this, kernel, main_thread_priority, main_thread_stack_top);
296 resource_limit->Reserve(ResourceType::Threads, 1);
297 resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size);
242} 298}
243 299
244void Process::PrepareForTermination() { 300void Process::PrepareForTermination() {
@@ -282,28 +338,33 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) {
282} 338}
283 339
284VAddr Process::CreateTLSRegion() { 340VAddr Process::CreateTLSRegion() {
285 auto tls_page_iter = FindTLSPageWithAvailableSlots(tls_pages); 341 if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)};
342 tls_page_iter != tls_pages.cend()) {
343 return *tls_page_iter->ReserveSlot();
344 }
286 345
287 if (tls_page_iter == tls_pages.cend()) { 346 Memory::Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()};
288 const auto region_address = 347 ASSERT(tls_page_ptr);
289 vm_manager.FindFreeRegion(vm_manager.GetTLSIORegionBaseAddress(),
290 vm_manager.GetTLSIORegionEndAddress(), Memory::PAGE_SIZE);
291 ASSERT(region_address.Succeeded());
292 348
293 const auto map_result = vm_manager.MapMemoryBlock( 349 const VAddr start{page_table->GetKernelMapRegionStart()};
294 *region_address, std::make_shared<PhysicalMemory>(Memory::PAGE_SIZE), 0, 350 const VAddr size{page_table->GetKernelMapRegionEnd() - start};
295 Memory::PAGE_SIZE, MemoryState::ThreadLocal); 351 const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)};
296 ASSERT(map_result.Succeeded()); 352 const VAddr tls_page_addr{
353 page_table
354 ->AllocateAndMapMemory(1, Memory::PageSize, true, start, size / Memory::PageSize,
355 Memory::MemoryState::ThreadLocal,
356 Memory::MemoryPermission::ReadAndWrite, tls_map_addr)
357 .ValueOr(0)};
297 358
298 tls_pages.emplace_back(*region_address); 359 ASSERT(tls_page_addr);
299 360
300 const auto reserve_result = tls_pages.back().ReserveSlot(); 361 std::memset(tls_page_ptr, 0, Memory::PageSize);
301 ASSERT(reserve_result.has_value()); 362 tls_pages.emplace_back(tls_page_addr);
302 363
303 return *reserve_result; 364 const auto reserve_result{tls_pages.back().ReserveSlot()};
304 } 365 ASSERT(reserve_result.has_value());
305 366
306 return *tls_page_iter->ReserveSlot(); 367 return *reserve_result;
307} 368}
308 369
309void Process::FreeTLSRegion(VAddr tls_address) { 370void Process::FreeTLSRegion(VAddr tls_address) {
@@ -320,28 +381,22 @@ void Process::FreeTLSRegion(VAddr tls_address) {
320 iter->ReleaseSlot(tls_address); 381 iter->ReleaseSlot(tls_address);
321} 382}
322 383
323void Process::LoadModule(CodeSet module_, VAddr base_addr) { 384void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
324 code_memory_size += module_.memory.size(); 385 const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
325 386 Memory::MemoryPermission permission) {
326 const auto memory = std::make_shared<PhysicalMemory>(std::move(module_.memory)); 387 page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission);
327
328 const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions,
329 MemoryState memory_state) {
330 const auto vma = vm_manager
331 .MapMemoryBlock(segment.addr + base_addr, memory, segment.offset,
332 segment.size, memory_state)
333 .Unwrap();
334 vm_manager.Reprotect(vma, permissions);
335 }; 388 };
336 389
337 // Map CodeSet segments 390 system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size());
338 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::Code); 391
339 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeData); 392 ReprotectSegment(code_set.CodeSegment(), Memory::MemoryPermission::ReadAndExecute);
340 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData); 393 ReprotectSegment(code_set.RODataSegment(), Memory::MemoryPermission::Read);
394 ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite);
341} 395}
342 396
343Process::Process(Core::System& system) 397Process::Process(Core::System& system)
344 : SynchronizationObject{system.Kernel()}, vm_manager{system}, 398 : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>(
399 system)},
345 address_arbiter{system}, mutex{system}, system{system} {} 400 address_arbiter{system}, mutex{system}, system{system} {}
346 401
347Process::~Process() = default; 402Process::~Process() = default;
@@ -364,16 +419,24 @@ void Process::ChangeStatus(ProcessStatus new_status) {
364 Signal(); 419 Signal();
365} 420}
366 421
367void Process::AllocateMainThreadStack(u64 stack_size) { 422ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {
423 ASSERT(stack_size);
424
368 // The kernel always ensures that the given stack size is page aligned. 425 // The kernel always ensures that the given stack size is page aligned.
369 main_thread_stack_size = Common::AlignUp(stack_size, Memory::PAGE_SIZE); 426 main_thread_stack_size = Common::AlignUp(stack_size, Memory::PageSize);
370 427
371 // Allocate and map the main thread stack 428 const VAddr start{page_table->GetStackRegionStart()};
372 const VAddr mapping_address = vm_manager.GetTLSIORegionEndAddress() - main_thread_stack_size; 429 const std::size_t size{page_table->GetStackRegionEnd() - start};
373 vm_manager 430
374 .MapMemoryBlock(mapping_address, std::make_shared<PhysicalMemory>(main_thread_stack_size), 431 CASCADE_RESULT(main_thread_stack_top,
375 0, main_thread_stack_size, MemoryState::Stack) 432 page_table->AllocateAndMapMemory(
376 .Unwrap(); 433 main_thread_stack_size / Memory::PageSize, Memory::PageSize, false, start,
434 size / Memory::PageSize, Memory::MemoryState::Stack,
435 Memory::MemoryPermission::ReadAndWrite));
436
437 main_thread_stack_top += main_thread_stack_size;
438
439 return RESULT_SUCCESS;
377} 440}
378 441
379} // namespace Kernel 442} // namespace Kernel