Kernel: reimplement memory management on physical FCRAM (#4392)
* Kernel: reimplement memory management on physical FCRAM * Kernel/Process: Unmap does not care the source memory permission What game usually does is after mapping the memory, they reprotect the source memory as no permission to avoid modification there * Kernel/SharedMemory: zero initialize new-allocated memory * Process/Thread: zero new TLS entry * Kernel: fix a bug where code segments memory usage are accumulated twice It is added to both misc and heap (done inside HeapAlloc), which results a doubled number reported by svcGetProcessInfo. While we are on it, we just merge the three number misc, heap and linear heap usage together, as there is no where they are distinguished. Question: is TLS page also added to this number? * Kernel/SharedMemory: add more object info on mapping error * Process: lower log level; SharedMemory: store phys offset * VMManager: add helper function to retrieve backing block list for a range
This commit is contained in:
@@ -50,13 +50,7 @@ void KernelSystem::MemoryInit(u32 mem_type) {
|
||||
// the sizes specified in the memory_region_sizes table.
|
||||
VAddr base = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
memory_regions[i].base = base;
|
||||
memory_regions[i].size = memory_region_sizes[mem_type][i];
|
||||
memory_regions[i].used = 0;
|
||||
memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
|
||||
// Reserve enough space for this region of FCRAM.
|
||||
// We do not want this block of memory to be relocated when allocating from it.
|
||||
memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size);
|
||||
memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]);
|
||||
|
||||
base += memory_regions[i].size;
|
||||
}
|
||||
@@ -164,4 +158,75 @@ void KernelSystem::MapSharedPages(VMManager& address_space) {
|
||||
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
|
||||
}
|
||||
|
||||
void MemoryRegionInfo::Reset(u32 base, u32 size) {
|
||||
this->base = base;
|
||||
this->size = size;
|
||||
used = 0;
|
||||
free_blocks.clear();
|
||||
|
||||
// mark the entire region as free
|
||||
free_blocks.insert(Interval::right_open(base, base + size));
|
||||
}
|
||||
|
||||
MemoryRegionInfo::IntervalSet MemoryRegionInfo::HeapAllocate(u32 size) {
|
||||
IntervalSet result;
|
||||
u32 rest = size;
|
||||
|
||||
// Try allocating from the higher address
|
||||
for (auto iter = free_blocks.rbegin(); iter != free_blocks.rend(); ++iter) {
|
||||
ASSERT(iter->bounds() == boost::icl::interval_bounds::right_open());
|
||||
if (iter->upper() - iter->lower() >= rest) {
|
||||
// Requested size is fulfilled with this block
|
||||
result += Interval(iter->upper() - rest, iter->upper());
|
||||
rest = 0;
|
||||
break;
|
||||
}
|
||||
result += *iter;
|
||||
rest -= iter->upper() - iter->lower();
|
||||
}
|
||||
|
||||
if (rest != 0) {
|
||||
// There is no enough free space
|
||||
return {};
|
||||
}
|
||||
|
||||
free_blocks -= result;
|
||||
used += size;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MemoryRegionInfo::LinearAllocate(u32 offset, u32 size) {
|
||||
Interval interval(offset, offset + size);
|
||||
if (!boost::icl::contains(free_blocks, interval)) {
|
||||
// The requested range is already allocated
|
||||
return false;
|
||||
}
|
||||
free_blocks -= interval;
|
||||
used += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<u32> MemoryRegionInfo::LinearAllocate(u32 size) {
|
||||
// Find the first sufficient continuous block from the lower address
|
||||
for (const auto& interval : free_blocks) {
|
||||
ASSERT(interval.bounds() == boost::icl::interval_bounds::right_open());
|
||||
if (interval.upper() - interval.lower() >= size) {
|
||||
Interval allocated(interval.lower(), interval.lower() + size);
|
||||
free_blocks -= allocated;
|
||||
used += size;
|
||||
return allocated.lower();
|
||||
}
|
||||
}
|
||||
|
||||
// No sufficient block found
|
||||
return {};
|
||||
}
|
||||
|
||||
void MemoryRegionInfo::Free(u32 offset, u32 size) {
|
||||
Interval interval(offset, offset + size);
|
||||
ASSERT(!boost::icl::intersects(free_blocks, interval)); // must be allocated blocks
|
||||
free_blocks += interval;
|
||||
used -= size;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
Reference in New Issue
Block a user