summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp214
1 files changed, 210 insertions, 4 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index f0cd8471e..b37db918e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -18,6 +18,7 @@
18#include "core/core_timing.h" 18#include "core/core_timing.h"
19#include "core/hle/kernel/k_client_port.h" 19#include "core/hle/kernel/k_client_port.h"
20#include "core/hle/kernel/k_client_session.h" 20#include "core/hle/kernel/k_client_session.h"
21#include "core/hle/kernel/k_code_memory.h"
21#include "core/hle/kernel/k_event.h" 22#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_handle_table.h" 23#include "core/hle/kernel/k_handle_table.h"
23#include "core/hle/kernel/k_memory_block.h" 24#include "core/hle/kernel/k_memory_block.h"
@@ -1197,6 +1198,22 @@ constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
1197 } 1198 }
1198} 1199}
1199 1200
1201constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
1202 return perm == Svc::MemoryPermission::ReadWrite;
1203}
1204
1205constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
1206 return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
1207}
1208
1209constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
1210 return perm == Svc::MemoryPermission::None;
1211}
1212
1213constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
1214 return perm == Svc::MemoryPermission::None;
1215}
1216
1200} // Anonymous namespace 1217} // Anonymous namespace
1201 1218
1202static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, 1219static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address,
@@ -1306,6 +1323,195 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
1306 return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); 1323 return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm));
1307} 1324}
1308 1325
1326static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
1327 VAddr src_address, u64 size) {
1328 LOG_TRACE(Kernel_SVC,
1329 "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
1330 dst_address, process_handle, src_address, size);
1331
1332 // Validate the address/size.
1333 R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
1334 R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
1335 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1336 R_UNLESS(size > 0, ResultInvalidSize);
1337 R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
1338 R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
1339
1340 // Get the processes.
1341 KProcess* dst_process = system.CurrentProcess();
1342 KScopedAutoObject src_process =
1343 dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
1344 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
1345
1346 // Get the page tables.
1347 auto& dst_pt = dst_process->PageTable();
1348 auto& src_pt = src_process->PageTable();
1349
1350 // Validate that the mapping is in range.
1351 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
1352 R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
1353 ResultInvalidMemoryRegion);
1354
1355 // Create a new page group.
1356 KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address);
1357 KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages());
1358
1359 // Map the group.
1360 R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
1361 KMemoryPermission::UserReadWrite));
1362
1363 return ResultSuccess;
1364}
1365
1366static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
1367 VAddr src_address, u64 size) {
1368 LOG_TRACE(Kernel_SVC,
1369 "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
1370 dst_address, process_handle, src_address, size);
1371
1372 // Validate the address/size.
1373 R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
1374 R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
1375 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1376 R_UNLESS(size > 0, ResultInvalidSize);
1377 R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
1378 R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
1379
1380 // Get the processes.
1381 KProcess* dst_process = system.CurrentProcess();
1382 KScopedAutoObject src_process =
1383 dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
1384 R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
1385
1386 // Get the page tables.
1387 auto& dst_pt = dst_process->PageTable();
1388 auto& src_pt = src_process->PageTable();
1389
1390 // Validate that the mapping is in range.
1391 R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
1392 R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
1393 ResultInvalidMemoryRegion);
1394
1395 // Unmap the memory.
1396 R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
1397
1398 return ResultSuccess;
1399}
1400
1401static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
1402 LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}",
1403 static_cast<void*>(out), address, size);
1404 // Get kernel instance.
1405 auto& kernel = system.Kernel();
1406
1407 // Validate address / size.
1408 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1409 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1410 R_UNLESS(size > 0, ResultInvalidSize);
1411 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1412
1413 // Create the code memory.
1414
1415 KCodeMemory* code_mem = KCodeMemory::Create(kernel);
1416 R_UNLESS(code_mem != nullptr, ResultOutOfResource);
1417
1418 // Verify that the region is in range.
1419 R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size),
1420 ResultInvalidCurrentMemory);
1421
1422 // Initialize the code memory.
1423 R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
1424
1425 // Register the code memory.
1426 KCodeMemory::Register(kernel, code_mem);
1427
1428 // Add the code memory to the handle table.
1429 R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
1430
1431 code_mem->Close();
1432
1433 return ResultSuccess;
1434}
1435
1436static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
1437 VAddr address, size_t size, Svc::MemoryPermission perm) {
1438
1439 LOG_TRACE(Kernel_SVC,
1440 "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
1441 "permission=0x{:X}",
1442 code_memory_handle, operation, address, size, perm);
1443
1444 // Validate the address / size.
1445 R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
1446 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1447 R_UNLESS(size > 0, ResultInvalidSize);
1448 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1449
1450 // Get the code memory from its handle.
1451 KScopedAutoObject code_mem =
1452 system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle);
1453 R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
1454
1455 // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
1456 // This enables homebrew usage of these SVCs for JIT.
1457
1458 // Perform the operation.
1459 switch (static_cast<CodeMemoryOperation>(operation)) {
1460 case CodeMemoryOperation::Map: {
1461 // Check that the region is in range.
1462 R_UNLESS(
1463 system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
1464 ResultInvalidMemoryRegion);
1465
1466 // Check the memory permission.
1467 R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1468
1469 // Map the memory.
1470 R_TRY(code_mem->Map(address, size));
1471 } break;
1472 case CodeMemoryOperation::Unmap: {
1473 // Check that the region is in range.
1474 R_UNLESS(
1475 system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
1476 ResultInvalidMemoryRegion);
1477
1478 // Check the memory permission.
1479 R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1480
1481 // Unmap the memory.
1482 R_TRY(code_mem->Unmap(address, size));
1483 } break;
1484 case CodeMemoryOperation::MapToOwner: {
1485 // Check that the region is in range.
1486 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
1487 KMemoryState::GeneratedCode),
1488 ResultInvalidMemoryRegion);
1489
1490 // Check the memory permission.
1491 R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1492
1493 // Map the memory to its owner.
1494 R_TRY(code_mem->MapToOwner(address, size, perm));
1495 } break;
1496 case CodeMemoryOperation::UnmapFromOwner: {
1497 // Check that the region is in range.
1498 R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
1499 KMemoryState::GeneratedCode),
1500 ResultInvalidMemoryRegion);
1501
1502 // Check the memory permission.
1503 R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
1504
1505 // Unmap the memory from its owner.
1506 R_TRY(code_mem->UnmapFromOwner(address, size));
1507 } break;
1508 default:
1509 return ResultInvalidEnumValue;
1510 }
1511
1512 return ResultSuccess;
1513}
1514
1309static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, 1515static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
1310 VAddr page_info_address, Handle process_handle, 1516 VAddr page_info_address, Handle process_handle,
1311 VAddr address) { 1517 VAddr address) {
@@ -2600,8 +2806,8 @@ static const FunctionDef SVC_Table_64[] = {
2600 {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, 2806 {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
2601 {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, 2807 {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
2602 {0x4A, nullptr, "SetUnsafeLimit"}, 2808 {0x4A, nullptr, "SetUnsafeLimit"},
2603 {0x4B, nullptr, "CreateCodeMemory"}, 2809 {0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
2604 {0x4C, nullptr, "ControlCodeMemory"}, 2810 {0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
2605 {0x4D, nullptr, "SleepSystem"}, 2811 {0x4D, nullptr, "SleepSystem"},
2606 {0x4E, nullptr, "ReadWriteRegister"}, 2812 {0x4E, nullptr, "ReadWriteRegister"},
2607 {0x4F, nullptr, "SetProcessActivity"}, 2813 {0x4F, nullptr, "SetProcessActivity"},
@@ -2641,8 +2847,8 @@ static const FunctionDef SVC_Table_64[] = {
2641 {0x71, nullptr, "ManageNamedPort"}, 2847 {0x71, nullptr, "ManageNamedPort"},
2642 {0x72, nullptr, "ConnectToPort"}, 2848 {0x72, nullptr, "ConnectToPort"},
2643 {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"}, 2849 {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
2644 {0x74, nullptr, "MapProcessMemory"}, 2850 {0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
2645 {0x75, nullptr, "UnmapProcessMemory"}, 2851 {0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
2646 {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"}, 2852 {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
2647 {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"}, 2853 {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
2648 {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, 2854 {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},