summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp319
1 files changed, 293 insertions, 26 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 48916df17..257d4bb83 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1,4 +1,4 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
@@ -12,6 +12,7 @@
12#include <utility> 12#include <utility>
13 13
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/common_sizes.h"
15#include "common/logging/log.h" 16#include "common/logging/log.h"
16#include "common/microprofile.h" 17#include "common/microprofile.h"
17#include "common/thread.h" 18#include "common/thread.h"
@@ -269,44 +270,310 @@ struct KernelCore::Impl {
269 } 270 }
270 271
271 void InitializeMemoryLayout() { 272 void InitializeMemoryLayout() {
272 // Initialize memory layout 273 KMemoryLayout memory_layout;
273 constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()}; 274
275 // Insert the root region for the virtual memory tree, from which all other regions will
276 // derive.
277 memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
278 KernelVirtualAddressSpaceBase,
279 KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
280
281 // Insert the root region for the physical memory tree, from which all other regions will
282 // derive.
283 memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
284 KernelPhysicalAddressSpaceBase,
285 KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
286
287 // Save start and end for ease of use.
288 const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
289 const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
290
291 // Setup the containing kernel region.
292 constexpr size_t KernelRegionSize = Size_1_GB;
293 constexpr size_t KernelRegionAlign = Size_1_GB;
294 constexpr VAddr kernel_region_start =
295 Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
296 size_t kernel_region_size = KernelRegionSize;
297 if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
298 kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
299 }
300 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
301 kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
302
303 // Setup the code region.
304 constexpr size_t CodeRegionAlign = PageSize;
305 constexpr VAddr code_region_start =
306 Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
307 constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
308 constexpr size_t code_region_size = code_region_end - code_region_start;
309 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
310 code_region_start, code_region_size, KMemoryRegionType_KernelCode));
311
312 // Setup board-specific device physical regions.
313 Init::SetupDevicePhysicalMemoryRegions(memory_layout);
314
315 // Determine the amount of space needed for the misc region.
316 size_t misc_region_needed_size;
317 {
318 // Each core has a one page stack for all three stack types (Main, Idle, Exception).
319 misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
320
321 // Account for each auto-map device.
322 for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
323 if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
324 // Check that the region is valid.
325 ASSERT(region.GetEndAddress() != 0);
326
327 // Account for the region.
328 misc_region_needed_size +=
329 PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
330 Common::AlignDown(region.GetAddress(), PageSize));
331 }
332 }
333
334 // Multiply the needed size by three, to account for the need for guard space.
335 misc_region_needed_size *= 3;
336 }
337
338 // Decide on the actual size for the misc region.
339 constexpr size_t MiscRegionAlign = KernelAslrAlignment;
340 constexpr size_t MiscRegionMinimumSize = Size_32_MB;
341 const size_t misc_region_size = Common::AlignUp(
342 std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
343 ASSERT(misc_region_size > 0);
344
345 // Setup the misc region.
346 const VAddr misc_region_start =
347 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
348 misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
349 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
350 misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
351
352 // Setup the stack region.
353 constexpr size_t StackRegionSize = Size_14_MB;
354 constexpr size_t StackRegionAlign = KernelAslrAlignment;
355 const VAddr stack_region_start =
356 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
357 StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
358 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
359 stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
360
361 // Determine the size of the resource region.
362 const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
363
364 // Determine the size of the slab region.
365 const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
366 ASSERT(slab_region_size <= resource_region_size);
367
368 // Setup the slab region.
369 const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
370 const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
371 const PAddr slab_start_phys_addr = code_end_phys_addr;
372 const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
373 constexpr size_t SlabRegionAlign = KernelAslrAlignment;
374 const size_t slab_region_needed_size =
375 Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
376 Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
377 const VAddr slab_region_start =
378 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
379 slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
380 (code_end_phys_addr % SlabRegionAlign);
381 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
382 slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
383
384 // Setup the temp region.
385 constexpr size_t TempRegionSize = Size_128_MB;
386 constexpr size_t TempRegionAlign = KernelAslrAlignment;
387 const VAddr temp_region_start =
388 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
389 TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
390 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
391 KMemoryRegionType_KernelTemp));
392
393 // Automatically map in devices that have auto-map attributes.
394 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
395 // We only care about kernel regions.
396 if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
397 continue;
398 }
399
400 // Check whether we should map the region.
401 if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
402 continue;
403 }
404
405 // If this region has already been mapped, no need to consider it.
406 if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
407 continue;
408 }
409
410 // Check that the region is valid.
411 ASSERT(region.GetEndAddress() != 0);
412
413 // Set the attribute to note we've mapped this region.
414 region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
415
416 // Create a virtual pair region and insert it into the tree.
417 const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
418 const size_t map_size =
419 Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
420 const VAddr map_virt_addr =
421 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
422 map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
423 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
424 map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
425 region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
426 }
427
428 Init::SetupDramPhysicalMemoryRegions(memory_layout);
429
430 // Insert a physical region for the kernel code region.
431 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
432 code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
433
434 // Insert a physical region for the kernel slab region.
435 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
436 slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
437
438 // Determine size available for kernel page table heaps, requiring > 8 MB.
439 const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
440 const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
441 ASSERT(page_table_heap_size / Size_4_MB > 2);
442
443 // Insert a physical region for the kernel page table heap region
444 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
445 slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
446
447 // All DRAM regions that we haven't tagged by this point will be mapped under the linear
448 // mapping. Tag them.
449 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
450 if (region.GetType() == KMemoryRegionType_Dram) {
451 // Check that the region is valid.
452 ASSERT(region.GetEndAddress() != 0);
453
454 // Set the linear map attribute.
455 region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
456 }
457 }
458
459 // Get the linear region extents.
460 const auto linear_extents =
461 memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
462 KMemoryRegionAttr_LinearMapped);
463 ASSERT(linear_extents.GetEndAddress() != 0);
464
465 // Setup the linear mapping region.
466 constexpr size_t LinearRegionAlign = Size_1_GB;
467 const PAddr aligned_linear_phys_start =
468 Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
469 const size_t linear_region_size =
470 Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
471 aligned_linear_phys_start;
472 const VAddr linear_region_start =
473 memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
474 linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
475
476 const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
477
478 // Map and create regions for all the linearly-mapped data.
479 {
480 PAddr cur_phys_addr = 0;
481 u64 cur_size = 0;
482 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
483 if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
484 continue;
485 }
486
487 ASSERT(region.GetEndAddress() != 0);
488
489 if (cur_size == 0) {
490 cur_phys_addr = region.GetAddress();
491 cur_size = region.GetSize();
492 } else if (cur_phys_addr + cur_size == region.GetAddress()) {
493 cur_size += region.GetSize();
494 } else {
495 const VAddr cur_virt_addr = cur_phys_addr + linear_region_phys_to_virt_diff;
496 cur_phys_addr = region.GetAddress();
497 cur_size = region.GetSize();
498 }
499
500 const VAddr region_virt_addr =
501 region.GetAddress() + linear_region_phys_to_virt_diff;
502 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
503 region_virt_addr, region.GetSize(),
504 GetTypeForVirtualLinearMapping(region.GetType())));
505 region.SetPairAddress(region_virt_addr);
506
507 KMemoryRegion* virt_region =
508 memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
509 ASSERT(virt_region != nullptr);
510 virt_region->SetPairAddress(region.GetAddress());
511 }
512 }
513
514 // Insert regions for the initial page table region.
515 ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
516 resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
517 ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
518 resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
519 KMemoryRegionType_VirtualDramKernelInitPt));
520
521 // All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
522 // some pool partition. Tag them.
523 for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
524 if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
525 region.SetType(KMemoryRegionType_DramPoolPartition);
526 }
527 }
528
529 // Setup all other memory regions needed to arrange the pool partitions.
530 Init::SetupPoolPartitionMemoryRegions(memory_layout);
531
532 // Cache all linear regions in their own trees for faster access, later.
533 memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
534 linear_region_start);
535
536 const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
537 const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
538 const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
539
540 // Initialize memory managers
541 memory_manager = std::make_unique<KMemoryManager>();
542 memory_manager->InitializeManager(KMemoryManager::Pool::Application,
543 application_pool.GetAddress(),
544 application_pool.GetEndAddress());
545 memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
546 applet_pool.GetEndAddress());
547 memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
548 system_pool.GetEndAddress());
549
550 // Setup memory regions for emulated processes
551 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
274 constexpr std::size_t hid_size{0x40000}; 552 constexpr std::size_t hid_size{0x40000};
275 constexpr std::size_t font_size{0x1100000}; 553 constexpr std::size_t font_size{0x1100000};
276 constexpr std::size_t irs_size{0x8000}; 554 constexpr std::size_t irs_size{0x8000};
277 constexpr std::size_t time_size{0x1000}; 555 constexpr std::size_t time_size{0x1000};
278 constexpr PAddr hid_addr{layout.System().GetAddress()};
279 constexpr PAddr font_pa{layout.System().GetAddress() + hid_size};
280 constexpr PAddr irs_addr{layout.System().GetAddress() + hid_size + font_size};
281 constexpr PAddr time_addr{layout.System().GetAddress() + hid_size + font_size + irs_size};
282 556
283 // Initialize memory manager 557 const PAddr hid_phys_addr{system_pool.GetAddress()};
284 memory_manager = std::make_unique<KMemoryManager>(); 558 const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
285 memory_manager->InitializeManager(KMemoryManager::Pool::Application, 559 const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
286 layout.Application().GetAddress(), 560 const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
287 layout.Application().GetLastAddress());
288 memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
289 layout.Applet().GetAddress(),
290 layout.Applet().GetLastAddress());
291 memory_manager->InitializeManager(KMemoryManager::Pool::System,
292 layout.System().GetAddress(),
293 layout.System().GetLastAddress());
294 561
295 hid_shared_mem = Kernel::KSharedMemory::Create( 562 hid_shared_mem = Kernel::KSharedMemory::Create(
296 system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize}, 563 system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
297 KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size, 564 KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
298 "HID:SharedMemory"); 565 "HID:SharedMemory");
299 font_shared_mem = Kernel::KSharedMemory::Create( 566 font_shared_mem = Kernel::KSharedMemory::Create(
300 system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize}, 567 system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
301 KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size, 568 KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
302 "Font:SharedMemory"); 569 "Font:SharedMemory");
303 irs_shared_mem = Kernel::KSharedMemory::Create( 570 irs_shared_mem = Kernel::KSharedMemory::Create(
304 system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize}, 571 system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
305 KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size, 572 KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
306 "IRS:SharedMemory"); 573 "IRS:SharedMemory");
307 time_shared_mem = Kernel::KSharedMemory::Create( 574 time_shared_mem = Kernel::KSharedMemory::Create(
308 system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize}, 575 system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
309 KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size, 576 KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
310 "Time:SharedMemory"); 577 "Time:SharedMemory");
311 578
312 // Allocate slab heaps 579 // Allocate slab heaps