kern: finish KProcess::Initialize() for KIPs

This commit is contained in:
Michael Scire 2020-02-19 06:46:59 -08:00
parent d9c3908caf
commit b857153964
6 changed files with 209 additions and 5 deletions

View file

@ -47,8 +47,32 @@ namespace ams::kern::arch::arm64 {
return this->page_table.MapPageGroup(addr, pg, state, perm); return this->page_table.MapPageGroup(addr, pg, state, perm);
} }
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, state, perm);
}
Result UnmapPages(KProcessAddress addr, size_t num_pages, KMemoryState state) {
return this->page_table.UnmapPages(addr, num_pages, state);
}
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
return this->page_table.GetPhysicalAddress(out, address);
}
bool CanContain(KProcessAddress addr, size_t size) const { return this->page_table.CanContain(addr, size); } bool CanContain(KProcessAddress addr, size_t size) const { return this->page_table.CanContain(addr, size); }
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->page_table.CanContain(addr, size, state); } bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->page_table.CanContain(addr, size, state); }
KProcessAddress GetAddressSpaceStart() const { return this->page_table.GetAddressSpaceStart(); }
KProcessAddress GetHeapRegionStart() const { return this->page_table.GetHeapRegionStart(); }
KProcessAddress GetAliasRegionStart() const { return this->page_table.GetAliasRegionStart(); }
KProcessAddress GetStackRegionStart() const { return this->page_table.GetStackRegionStart(); }
KProcessAddress GetKernelMapRegionStart() const { return this->page_table.GetKernelMapRegionStart(); }
size_t GetAddressSpaceSize() const { return this->page_table.GetAddressSpaceSize(); }
size_t GetHeapRegionSize() const { return this->page_table.GetHeapRegionSize(); }
size_t GetAliasRegionSize() const { return this->page_table.GetAliasRegionSize(); }
size_t GetStackRegionSize() const { return this->page_table.GetStackRegionSize(); }
size_t GetKernelMapRegionSize() const { return this->page_table.GetKernelMapRegionSize(); }
}; };
} }

View file

@ -250,10 +250,26 @@ namespace ams::kern {
return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm); return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start, region_num_pages, state, perm);
} }
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
return this->MapPages(out_addr, num_pages, alignment, phys_addr, true, this->GetRegionAddress(state), this->GetRegionSize(state) / PageSize, state, perm);
}
Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state); Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state);
Result MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm); Result MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
Result MapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm); Result MapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state, KMemoryPermission perm);
Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state); Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state);
public:
KProcessAddress GetAddressSpaceStart() const { return this->address_space_start; }
KProcessAddress GetHeapRegionStart() const { return this->heap_region_start; }
KProcessAddress GetAliasRegionStart() const { return this->alias_region_start; }
KProcessAddress GetStackRegionStart() const { return this->stack_region_start; }
KProcessAddress GetKernelMapRegionStart() const { return this->kernel_map_region_start; }
size_t GetAddressSpaceSize() const { return this->address_space_end - this->address_space_start; }
size_t GetHeapRegionSize() const { return this->heap_region_end - this->heap_region_start; }
size_t GetAliasRegionSize() const { return this->alias_region_end - this->alias_region_start; }
size_t GetStackRegionSize() const { return this->stack_region_end - this->stack_region_start; }
size_t GetKernelMapRegionSize() const { return this->kernel_map_region_end - this->kernel_map_region_start; }
public: public:
static ALWAYS_INLINE KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress addr) { static ALWAYS_INLINE KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress addr) {
return KMemoryLayout::GetLinearVirtualAddress(addr); return KMemoryLayout::GetLinearVirtualAddress(addr);

View file

@ -135,6 +135,12 @@ namespace ams::kern {
return this->pinned_threads[core_id]; return this->pinned_threads[core_id];
} }
constexpr KProcessPageTable &GetPageTable() { return this->page_table; }
constexpr const KProcessPageTable &GetPageTable() const { return this->page_table; }
Result CreateThreadLocalRegion(KProcessAddress *out);
void *GetThreadLocalRegionPointer(KProcessAddress addr);
void SetPreemptionState(); void SetPreemptionState();
public: public:
/* Overridden parent functions. */ /* Overridden parent functions. */

View file

@ -42,6 +42,19 @@ namespace ams::kern {
constexpr explicit KThreadLocalPage() : KThreadLocalPage(Null<KProcessAddress>) { /* ... */ } constexpr explicit KThreadLocalPage() : KThreadLocalPage(Null<KProcessAddress>) { /* ... */ }
constexpr ALWAYS_INLINE KProcessAddress GetAddress() const { return this->virt_addr; } constexpr ALWAYS_INLINE KProcessAddress GetAddress() const { return this->virt_addr; }
static constexpr ALWAYS_INLINE int Compare(const KThreadLocalPage &lhs, const KThreadLocalPage &rhs) {
const KProcessAddress lval = lhs.GetAddress();
const KProcessAddress rval = rhs.GetAddress();
if (lval < rval) {
return -1;
} else if (lval == rval) {
return 0;
} else {
return 1;
}
}
private: private:
constexpr ALWAYS_INLINE KProcessAddress GetRegionAddress(size_t i) { constexpr ALWAYS_INLINE KProcessAddress GetRegionAddress(size_t i) {
return this->GetAddress() + i * ams::svc::ThreadLocalRegionSize; return this->GetAddress() + i * ams::svc::ThreadLocalRegionSize;
@ -63,6 +76,8 @@ namespace ams::kern {
KProcessAddress Reserve(); KProcessAddress Reserve();
void Release(KProcessAddress addr); void Release(KProcessAddress addr);
void *GetPointer() const;
bool IsAllUsed() const { bool IsAllUsed() const {
for (size_t i = 0; i < RegionsPerPage; i++) { for (size_t i = 0; i < RegionsPerPage; i++) {
if (this->is_region_free[i]) { if (this->is_region_free[i]) {

View file

@ -30,7 +30,76 @@ namespace ams::kern {
} }
Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params) { Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params) {
MESOSPHERE_TODO_IMPLEMENT(); /* TODO: Validate intended kernel version. */
/* How should we do this? */
/* Create and clear the process local region. */
R_TRY(this->CreateThreadLocalRegion(std::addressof(this->plr_address)));
std::memset(this->GetThreadLocalRegionPointer(this->plr_address), 0, ams::svc::ThreadLocalRegionSize);
/* Copy in the name from parameters. */
static_assert(sizeof(params.name) < sizeof(this->name));
std::memcpy(this->name, params.name, sizeof(params.name));
this->name[sizeof(params.name)] = 0;
/* Set misc fields. */
this->state = State_Created;
this->main_thread_stack_size = 0;
this->creation_time = KHardwareTimer::GetTick();
this->used_kernel_memory_size = 0;
this->ideal_core_id = 0;
this->flags = params.flags;
this->version = params.version;
this->program_id = params.program_id;
this->code_address = params.code_address;
this->code_size = params.code_num_pages * PageSize;
this->is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
this->is_jit_debug = false;
/* Set thread fields. */
for (size_t i = 0; i < cpu::NumCores; i++) {
this->running_threads[i] = nullptr;
this->running_thread_idle_counts[i] = 0;
this->pinned_threads[i] = nullptr;
}
/* Set max memory based on address space type. */
switch ((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask)) {
case ams::svc::CreateProcessFlag_AddressSpace32Bit:
case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated:
case ams::svc::CreateProcessFlag_AddressSpace64Bit:
this->max_process_memory = this->page_table.GetHeapRegionSize();
break;
case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
this->max_process_memory = this->page_table.GetHeapRegionSize() + this->page_table.GetAliasRegionSize();
break;
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
/* Generate random entropy. */
KSystemControl::GenerateRandomBytes(this->entropy, sizeof(this->entropy));
/* Clear remaining fields. */
this->num_threads = 0;
this->peak_num_threads = 0;
this->num_created_threads = 0;
this->num_process_switches = 0;
this->num_thread_switches = 0;
this->num_fpu_switches = 0;
this->num_supervisor_calls = 0;
this->num_ipc_messages = 0;
this->is_signaled = false;
this->attached_object = nullptr;
this->exception_thread = nullptr;
this->is_suspended = false;
this->memory_release_hint = 0;
this->schedule_count = 0;
/* We're initialized! */
this->is_initialized = true;
return ResultSuccess();
} }
Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool) { Result KProcess::Initialize(const ams::svc::CreateProcessParameter &params, const KPageGroup &pg, const u32 *caps, s32 num_caps, KResourceLimit *res_limit, KMemoryManager::Pool pool) {
@ -40,7 +109,7 @@ namespace ams::kern {
/* Set members. */ /* Set members. */
this->memory_pool = pool; this->memory_pool = pool;
this->resource_limit = resource_limit; this->resource_limit = res_limit;
this->system_resource_address = Null<KVirtualAddress>; this->system_resource_address = Null<KVirtualAddress>;
this->system_resource_num_pages = 0; this->system_resource_num_pages = 0;
@ -87,6 +156,72 @@ namespace ams::kern {
MESOSPHERE_TODO_IMPLEMENT(); MESOSPHERE_TODO_IMPLEMENT();
} }
Result KProcess::CreateThreadLocalRegion(KProcessAddress *out) {
KThreadLocalPage *tlp = nullptr;
KProcessAddress tlr = Null<KProcessAddress>;
/* See if we can get a region from a partially used TLP. */
{
KScopedSchedulerLock sl;
if (auto it = this->partially_used_tlp_tree.begin(); it != partially_used_tlp_tree.end()) {
tlr = it->Reserve();
MESOSPHERE_ABORT_UNLESS(tlr != Null<KProcessAddress>);
if (it->IsAllUsed()) {
tlp = std::addressof(*it);
this->partially_used_tlp_tree.erase(it);
this->fully_used_tlp_tree.insert(*tlp);
}
*out = tlr;
return ResultSuccess();
}
}
/* Allocate a new page. */
tlp = KThreadLocalPage::Allocate();
R_UNLESS(tlp != nullptr, svc::ResultOutOfMemory());
auto tlp_guard = SCOPE_GUARD { KThreadLocalPage::Free(tlp); };
/* Initialize the new page. */
R_TRY(tlp->Initialize(this));
/* Reserve a TLR. */
tlr = tlp->Reserve();
MESOSPHERE_ABORT_UNLESS(tlr != Null<KProcessAddress>);
/* Insert into our tree. */
{
KScopedSchedulerLock sl;
if (tlp->IsAllUsed()) {
this->fully_used_tlp_tree.insert(*tlp);
} else {
this->partially_used_tlp_tree.insert(*tlp);
}
}
/* We succeeded! */
tlp_guard.Cancel();
*out = tlr;
return ResultSuccess();
}
void *KProcess::GetThreadLocalRegionPointer(KProcessAddress addr) {
KThreadLocalPage *tlp = nullptr;
{
KScopedSchedulerLock sl;
if (auto it = this->partially_used_tlp_tree.find(KThreadLocalPage(util::AlignDown(GetInteger(addr), PageSize))); it != this->partially_used_tlp_tree.end()) {
tlp = std::addressof(*it);
} else if (auto it = this->fully_used_tlp_tree.find(KThreadLocalPage(util::AlignDown(GetInteger(addr), PageSize))); it != this->fully_used_tlp_tree.end()) {
tlp = std::addressof(*it);
} else {
return nullptr;
}
}
return static_cast<u8 *>(tlp->GetPointer()) + (GetInteger(addr) & (PageSize - 1));
}
void KProcess::SetPreemptionState() { void KProcess::SetPreemptionState() {
MESOSPHERE_TODO_IMPLEMENT(); MESOSPHERE_TODO_IMPLEMENT();
} }

View file

@ -29,7 +29,7 @@ namespace ams::kern {
auto page_buf_guard = SCOPE_GUARD { KPageBuffer::Free(page_buf); }; auto page_buf_guard = SCOPE_GUARD { KPageBuffer::Free(page_buf); };
/* Map the address in. */ /* Map the address in. */
MESOSPHERE_TODO("R_TRY(this->owner->GetPageTable().Map(...));"); R_TRY(this->owner->GetPageTable().MapPages(std::addressof(this->virt_addr), 1, PageSize, page_buf->GetPhysicalAddress(), KMemoryState_ThreadLocal, KMemoryPermission_UserReadWrite));
/* We succeeded. */ /* We succeeded. */
page_buf_guard.Cancel(); page_buf_guard.Cancel();
@ -41,10 +41,10 @@ namespace ams::kern {
/* Get the physical address of the page. */ /* Get the physical address of the page. */
KPhysicalAddress phys_addr = Null<KPhysicalAddress>; KPhysicalAddress phys_addr = Null<KPhysicalAddress>;
MESOSPHERE_TODO("MESOSPHERE_ABORT_UNLESS(this->owner->GetPageTable().GetPhysicalAddress(&phys_addr, this->GetAddress()));"); MESOSPHERE_ABORT_UNLESS(this->owner->GetPageTable().GetPhysicalAddress(&phys_addr, this->GetAddress()));
/* Unmap the page. */ /* Unmap the page. */
MESOSPHERE_TODO("R_TRY(this->owner->GetPageTable().Unmap(...);"); R_TRY(this->owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState_ThreadLocal));
/* Free the page. */ /* Free the page. */
KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(phys_addr)); KPageBuffer::Free(KPageBuffer::FromPhysicalAddress(phys_addr));
@ -70,4 +70,12 @@ namespace ams::kern {
this->is_region_free[this->GetRegionIndex(addr)] = true; this->is_region_free[this->GetRegionIndex(addr)] = true;
} }
void *KThreadLocalPage::GetPointer() const {
MESOSPHERE_ASSERT_THIS();
KPhysicalAddress phys_addr;
MESOSPHERE_ABORT_UNLESS(this->owner->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), this->GetAddress()));
return static_cast<void *>(KPageBuffer::FromPhysicalAddress(phys_addr));
}
} }