summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp130
1 files changed, 67 insertions, 63 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fb824d710..8c3489ed3 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -225,6 +225,69 @@ struct Memory::Impl {
225 return string; 225 return string;
226 } 226 }
227 227
228 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
229 if (vaddr == 0) {
230 return;
231 }
232
233 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
234 // address space, marking the region as un/cached. The region is marked un/cached at a
235 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
236 // is different). This assumes the specified GPU address region is contiguous as well.
237
238 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
239 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
240 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
241
242 if (cached) {
243 // Switch page type to cached if now cached
244 switch (page_type) {
245 case Common::PageType::Unmapped:
246 // It is not necessary for a process to have this region mapped into its address
247 // space, for example, a system module need not have a VRAM mapping.
248 break;
249 case Common::PageType::Memory:
250 page_type = Common::PageType::RasterizerCachedMemory;
251 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
252 break;
253 case Common::PageType::RasterizerCachedMemory:
254 // There can be more than one GPU region mapped per CPU region, so it's common
255 // that this area is already marked as cached.
256 break;
257 default:
258 UNREACHABLE();
259 }
260 } else {
261 // Switch page type to uncached if now uncached
262 switch (page_type) {
263 case Common::PageType::Unmapped:
264 // It is not necessary for a process to have this region mapped into its address
265 // space, for example, a system module need not have a VRAM mapping.
266 break;
267 case Common::PageType::Memory:
268 // There can be more than one GPU region mapped per CPU region, so it's common
269 // that this area is already unmarked as cached.
270 break;
271 case Common::PageType::RasterizerCachedMemory: {
272 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
273 if (pointer == nullptr) {
274 // It's possible that this function has been called while updating the
275 // pagetable after unmapping a VMA. In that case the underlying VMA will no
276 // longer exist, and we should just leave the pagetable entry blank.
277 page_type = Common::PageType::Unmapped;
278 } else {
279 page_type = Common::PageType::Memory;
280 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
281 }
282 break;
283 }
284 default:
285 UNREACHABLE();
286 }
287 }
288 }
289 }
290
228 /** 291 /**
229 * Maps a region of pages as a specific type. 292 * Maps a region of pages as a specific type.
230 * 293 *
@@ -318,6 +381,10 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
318 return impl->ReadCString(vaddr, max_length); 381 return impl->ReadCString(vaddr, max_length);
319} 382}
320 383
384void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
385 impl->RasterizerMarkRegionCached(vaddr, size, cached);
386}
387
321void SetCurrentPageTable(Kernel::Process& process) { 388void SetCurrentPageTable(Kernel::Process& process) {
322 current_page_table = &process.VMManager().page_table; 389 current_page_table = &process.VMManager().page_table;
323 390
@@ -334,69 +401,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
334 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 401 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
335} 402}
336 403
337void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
338 if (vaddr == 0) {
339 return;
340 }
341
342 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address
343 // space, marking the region as un/cached. The region is marked un/cached at a granularity of
344 // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This
345 // assumes the specified GPU address region is contiguous as well.
346
347 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
348 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
349 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
350
351 if (cached) {
352 // Switch page type to cached if now cached
353 switch (page_type) {
354 case Common::PageType::Unmapped:
355 // It is not necessary for a process to have this region mapped into its address
356 // space, for example, a system module need not have a VRAM mapping.
357 break;
358 case Common::PageType::Memory:
359 page_type = Common::PageType::RasterizerCachedMemory;
360 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
361 break;
362 case Common::PageType::RasterizerCachedMemory:
363 // There can be more than one GPU region mapped per CPU region, so it's common that
364 // this area is already marked as cached.
365 break;
366 default:
367 UNREACHABLE();
368 }
369 } else {
370 // Switch page type to uncached if now uncached
371 switch (page_type) {
372 case Common::PageType::Unmapped:
373 // It is not necessary for a process to have this region mapped into its address
374 // space, for example, a system module need not have a VRAM mapping.
375 break;
376 case Common::PageType::Memory:
377 // There can be more than one GPU region mapped per CPU region, so it's common that
378 // this area is already unmarked as cached.
379 break;
380 case Common::PageType::RasterizerCachedMemory: {
381 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
382 if (pointer == nullptr) {
383 // It's possible that this function has been called while updating the pagetable
384 // after unmapping a VMA. In that case the underlying VMA will no longer exist,
385 // and we should just leave the pagetable entry blank.
386 page_type = Common::PageType::Unmapped;
387 } else {
388 page_type = Common::PageType::Memory;
389 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
390 }
391 break;
392 }
393 default:
394 UNREACHABLE();
395 }
396 }
397 }
398}
399
400u8 Read8(const VAddr addr) { 404u8 Read8(const VAddr addr) {
401 return Read<u8>(addr); 405 return Read<u8>(addr);
402} 406}