mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: implement CallSecureMonitor, some of GetInfo/GetSystemInfo
This commit is contained in:
parent
37f7afb426
commit
96d15b28c6
13 changed files with 264 additions and 33 deletions
|
@ -84,6 +84,10 @@ namespace ams::kern::arch::arm64 {
|
|||
return this->page_table.UnmapPages(addr, num_pages, state);
|
||||
}
|
||||
|
||||
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) {
|
||||
return this->page_table.MakeAndOpenPageGroup(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
|
||||
}
|
||||
|
||||
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
|
||||
return this->page_table.GetPhysicalAddress(out, address);
|
||||
}
|
||||
|
@ -96,12 +100,23 @@ namespace ams::kern::arch::arm64 {
|
|||
KProcessAddress GetAliasRegionStart() const { return this->page_table.GetAliasRegionStart(); }
|
||||
KProcessAddress GetStackRegionStart() const { return this->page_table.GetStackRegionStart(); }
|
||||
KProcessAddress GetKernelMapRegionStart() const { return this->page_table.GetKernelMapRegionStart(); }
|
||||
KProcessAddress GetAliasCodeRegionStart() const { return this->page_table.GetAliasCodeRegionStart(); }
|
||||
|
||||
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(); }
|
||||
size_t GetAliasCodeRegionSize() const { return this->page_table.GetAliasCodeRegionSize(); }
|
||||
|
||||
KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const {
|
||||
/* TODO: Better way to convert address type? */
|
||||
return this->page_table.GetHeapPhysicalAddress(address);
|
||||
}
|
||||
|
||||
KBlockInfoManager *GetBlockInfoManager() {
|
||||
return this->page_table.GetBlockInfoManager();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ namespace ams::kern::board::nintendo::nx {
|
|||
/* Power management. */
|
||||
static void SleepSystem();
|
||||
static NORETURN void StopSystem();
|
||||
|
||||
/* User access. */
|
||||
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
||||
};
|
||||
|
||||
}
|
|
@ -191,8 +191,6 @@ namespace ams::kern {
|
|||
KPageTableImpl &GetImpl() { return this->impl; }
|
||||
const KPageTableImpl &GetImpl() const { return this->impl; }
|
||||
|
||||
KBlockInfoManager *GetBlockInfoManager() const { return this->block_info_manager; }
|
||||
|
||||
bool IsLockedByCurrentThread() const { return this->general_lock.IsLockedByCurrentThread(); }
|
||||
|
||||
bool IsHeapPhysicalAddress(KPhysicalAddress phys_addr) {
|
||||
|
@ -245,6 +243,8 @@ namespace ams::kern {
|
|||
return this->GetImpl().GetPhysicalAddress(out, virt_addr);
|
||||
}
|
||||
|
||||
KBlockInfoManager *GetBlockInfoManager() const { return this->block_info_manager; }
|
||||
|
||||
Result SetMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm);
|
||||
Result SetProcessMemoryPermission(KProcessAddress addr, size_t size, ams::svc::MemoryPermission perm);
|
||||
Result SetHeapSize(KProcessAddress *out, size_t size);
|
||||
|
@ -270,18 +270,22 @@ namespace ams::kern {
|
|||
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 UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state);
|
||||
|
||||
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||
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; }
|
||||
KProcessAddress GetAliasCodeRegionStart() const { return this->alias_code_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; }
|
||||
size_t GetAliasCodeRegionSize() const { return this->alias_code_region_end - this->alias_code_region_start; }
|
||||
public:
|
||||
static ALWAYS_INLINE KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress addr) {
|
||||
return KMemoryLayout::GetLinearVirtualAddress(addr);
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace ams::kern {
|
|||
#define MESOSPHERE_UNUSED(...) ::ams::kern::UnusedImpl(__VA_ARGS__)
|
||||
|
||||
#ifdef MESOSPHERE_ENABLE_DEBUG_PRINT
|
||||
#define MESOSPHERE_PANIC(...) do { ::ams::kern::Panic(__FILE__, __LINE__, __VA_ARGS__); } while(0)
|
||||
#define MESOSPHERE_PANIC(...) do { ::ams::kern::Panic(__FILE__, __LINE__, ## __VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define MESOSPHERE_PANIC(...) do { MESOSPHERE_UNUSED(__VA_ARGS__); ::ams::kern::Panic(); } while(0)
|
||||
#endif
|
||||
|
|
|
@ -150,6 +150,15 @@ namespace ams::kern::arch::arm64 {
|
|||
HandleUserException(context, esr, far, afsr0, afsr1, data);
|
||||
}
|
||||
} else {
|
||||
MESOSPHERE_LOG("Unhandled Exception in Supervisor Mode\n");
|
||||
MESOSPHERE_LOG("Current Process = %s\n", GetCurrentProcess().GetName());
|
||||
|
||||
for (size_t i = 0; i < 31; i++) {
|
||||
MESOSPHERE_LOG("X[%02zu] = %016lx\n", i, context->x[i]);
|
||||
}
|
||||
MESOSPHERE_LOG("PC = %016lx\n", context->pc);
|
||||
MESOSPHERE_LOG("SP = %016lx\n", context->sp);
|
||||
|
||||
MESOSPHERE_PANIC("Unhandled Exception in Supervisor Mode\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -327,4 +327,53 @@ namespace ams::kern::board::nintendo::nx {
|
|||
while (true) { /* ... */ }
|
||||
}
|
||||
|
||||
/* User access. */
|
||||
void KSystemControl::CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
/* Get the function id for the current call. */
|
||||
u64 function_id = args->r[0];
|
||||
|
||||
MESOSPHERE_LOG("CallSecureMonitor(%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx);\n", args->r[0], args->r[1], args->r[2], args->r[3], args->r[4], args->r[5], args->r[6], args->r[7]);
|
||||
|
||||
/* We'll need to map in pages if arguments are pointers. Prepare page groups to do so. */
|
||||
auto &page_table = GetCurrentProcess().GetPageTable();
|
||||
auto *bim = page_table.GetBlockInfoManager();
|
||||
|
||||
constexpr size_t MaxMappedRegisters = 7;
|
||||
std::array<KPageGroup, MaxMappedRegisters> page_groups = { KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), };
|
||||
|
||||
for (size_t i = 0; i < MaxMappedRegisters; i++) {
|
||||
const size_t reg_id = i + 1;
|
||||
if (function_id & (1ul << (8 + reg_id))) {
|
||||
/* Create and open a new page group for the address. */
|
||||
KVirtualAddress virt_addr = args->r[reg_id];
|
||||
|
||||
if (R_SUCCEEDED(page_table.MakeAndOpenPageGroup(std::addressof(page_groups[i]), util::AlignDown(GetInteger(virt_addr), PageSize), 1, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||
/* Translate the virtual address to a physical address. */
|
||||
const auto it = page_groups[i].begin();
|
||||
MESOSPHERE_ASSERT(it != page_groups[i].end());
|
||||
MESOSPHERE_ASSERT(it->GetNumPages() == 1);
|
||||
|
||||
KPhysicalAddress phys_addr = page_table.GetHeapPhysicalAddress(it->GetAddress());
|
||||
|
||||
args->r[reg_id] = GetInteger(phys_addr) | (GetInteger(virt_addr) & (PageSize - 1));
|
||||
MESOSPHERE_LOG("Mapped arg %zu\n", reg_id);
|
||||
} else {
|
||||
/* If we couldn't map, we should clear the address. */
|
||||
MESOSPHERE_LOG("Failed to map arg %zu\n", reg_id);
|
||||
args->r[reg_id] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the secure monitor. */
|
||||
smc::CallSecureMonitorFromUser(args);
|
||||
|
||||
MESOSPHERE_LOG("Secure Monitor Returned: (%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx);\n", args->r[0], args->r[1], args->r[2], args->r[3], args->r[4], args->r[5], args->r[6], args->r[7]);
|
||||
|
||||
/* Make sure that we close any pages that we opened. */
|
||||
for (size_t i = 0; i < MaxMappedRegisters; i++) {
|
||||
page_groups[i].Close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -71,6 +71,42 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
void CallUserSecureMonitorFunction(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args->r[0];
|
||||
register u64 x1 asm("x1") = args->r[1];
|
||||
register u64 x2 asm("x2") = args->r[2];
|
||||
register u64 x3 asm("x3") = args->r[3];
|
||||
register u64 x4 asm("x4") = args->r[4];
|
||||
register u64 x5 asm("x5") = args->r[5];
|
||||
register u64 x6 asm("x6") = args->r[6];
|
||||
register u64 x7 asm("x7") = args->r[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
{
|
||||
/* Disable interrupts while making the call. */
|
||||
KScopedInterruptDisable intr_disable;
|
||||
__asm__ __volatile__("smc #0"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Restore the CoreLocalRegion into X18. */
|
||||
cpu::SetCoreLocalRegionAddress(cpu::GetTpidrEl1());
|
||||
}
|
||||
|
||||
/* Store arguments to output. */
|
||||
args->r[0] = x0;
|
||||
args->r[1] = x1;
|
||||
args->r[2] = x2;
|
||||
args->r[3] = x3;
|
||||
args->r[4] = x4;
|
||||
args->r[5] = x5;
|
||||
args->r[6] = x6;
|
||||
args->r[7] = x7;
|
||||
}
|
||||
|
||||
void CallPrivilegedSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
|
@ -188,4 +224,8 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
while (true) { /* ... */ }
|
||||
}
|
||||
|
||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
CallUserSecureMonitorFunction(args);
|
||||
}
|
||||
|
||||
}
|
|
@ -91,6 +91,8 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
|
||||
void NORETURN Panic(u32 color);
|
||||
|
||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
||||
|
||||
namespace init {
|
||||
|
||||
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||
|
|
|
@ -1020,4 +1020,27 @@ namespace ams::kern {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result KPageTableBase::MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) {
|
||||
/* Ensure that the page group isn't null. */
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
/* Make sure that the region we're mapping is valid for the table. */
|
||||
const size_t size = num_pages * PageSize;
|
||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(this->general_lock);
|
||||
|
||||
/* Check if state allows us to create the group. */
|
||||
R_TRY(this->CheckMemoryState(address, size, state_mask | KMemoryState_FlagReferenceCounted, state | KMemoryState_FlagReferenceCounted, perm_mask, perm, attr_mask, attr));
|
||||
|
||||
/* Create a new page group for the region. */
|
||||
R_TRY(this->MakePageGroup(*out, address, num_pages));
|
||||
|
||||
/* Open a new reference to the pages in the group. */
|
||||
out->Open();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,28 +21,112 @@ namespace ams::kern::svc {
|
|||
|
||||
namespace {
|
||||
|
||||
Result GetInfo(u64 *out, ams::svc::InfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||
MESOSPHERE_LOG("GetInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
|
||||
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetInfo returned %016lx\n", *out); };
|
||||
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_AliasRegionAddress:
|
||||
case ams::svc::InfoType_AliasRegionSize:
|
||||
case ams::svc::InfoType_HeapRegionAddress:
|
||||
case ams::svc::InfoType_HeapRegionSize:
|
||||
case ams::svc::InfoType_AslrRegionAddress:
|
||||
case ams::svc::InfoType_AslrRegionSize:
|
||||
case ams::svc::InfoType_StackRegionAddress:
|
||||
case ams::svc::InfoType_StackRegionSize:
|
||||
{
|
||||
/* These info types don't support non-zero subtypes. */
|
||||
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||
|
||||
/* Get the process from its handle. */
|
||||
KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject<KProcess>(handle);
|
||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
switch (info_type) {
|
||||
case ams::svc::InfoType_AliasRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AliasRegionSize:
|
||||
*out = process->GetPageTable().GetAliasRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetHeapRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_HeapRegionSize:
|
||||
*out = process->GetPageTable().GetHeapRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetAliasCodeRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_AslrRegionSize:
|
||||
*out = process->GetPageTable().GetAliasCodeRegionSize();
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionAddress:
|
||||
*out = GetInteger(process->GetPageTable().GetStackRegionStart());
|
||||
break;
|
||||
case ams::svc::InfoType_StackRegionSize:
|
||||
*out = process->GetPageTable().GetStackRegionSize();
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return svc::ResultInvalidEnumValue();
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetSystemInfo(u64 *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, u64 info_subtype) {
|
||||
MESOSPHERE_LOG("GetSystemInfo(%p, %u, %08x, %lu) was called\n", out, static_cast<u32>(info_type), static_cast<u32>(handle), info_subtype);
|
||||
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetSystemInfo returned %016lx\n", *out); };
|
||||
|
||||
switch (info_type) {
|
||||
case ams::svc::SystemInfoType_InitialProcessIdRange:
|
||||
{
|
||||
R_UNLESS(handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle());
|
||||
switch (static_cast<ams::svc::InitialProcessIdRangeInfo>(info_subtype)) {
|
||||
case ams::svc::InitialProcessIdRangeInfo_Minimum:
|
||||
MESOSPHERE_ABORT_UNLESS(GetInitialProcessIdMin() <= GetInitialProcessIdMax());
|
||||
*out = GetInitialProcessIdMin();
|
||||
break;
|
||||
case ams::svc::InitialProcessIdRangeInfo_Maximum:
|
||||
MESOSPHERE_ABORT_UNLESS(GetInitialProcessIdMin() <= GetInitialProcessIdMax());
|
||||
*out = GetInitialProcessIdMax();
|
||||
break;
|
||||
default:
|
||||
return svc::ResultInvalidCombination();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return svc::ResultInvalidEnumValue();
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result GetInfo64(uint64_t *out, ams::svc::InfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcGetInfo64 was called.");
|
||||
return GetInfo(out, info_type, handle, info_subtype);
|
||||
}
|
||||
|
||||
Result GetSystemInfo64(uint64_t *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcGetSystemInfo64 was called.");
|
||||
return GetSystemInfo(out, info_type, handle, info_subtype);
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result GetInfo64From32(uint64_t *out, ams::svc::InfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcGetInfo64From32 was called.");
|
||||
return GetInfo(out, info_type, handle, info_subtype);
|
||||
}
|
||||
|
||||
Result GetSystemInfo64From32(uint64_t *out, ams::svc::SystemInfoType info_type, ams::svc::Handle handle, uint64_t info_subtype) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcGetSystemInfo64From32 was called.");
|
||||
return GetSystemInfo(out, info_type, handle, info_subtype);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace ams::kern::svc {
|
|||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
void CallSecureMonitor64(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
MESOSPHERE_PANIC("Stubbed SvcCallSecureMonitor64 was called.");
|
||||
KSystemControl::CallSecureMonitorFromUser(args);
|
||||
}
|
||||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
|
|
@ -28,13 +28,15 @@ namespace ams::svc {
|
|||
using Handle = u32;
|
||||
#endif
|
||||
|
||||
static constexpr size_t MaxWaitSynchronizationHandleCount = 0x40;
|
||||
constexpr inline size_t MaxWaitSynchronizationHandleCount = 0x40;
|
||||
|
||||
enum PseudoHandle : Handle {
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
};
|
||||
|
||||
constexpr inline Handle InvalidHandle = Handle(0);
|
||||
|
||||
constexpr ALWAYS_INLINE bool operator==(const Handle &lhs, const PseudoHandle &rhs) {
|
||||
return static_cast<Handle>(lhs) == static_cast<Handle>(rhs);
|
||||
}
|
||||
|
|
|
@ -100,22 +100,22 @@ _ZN3ams4kern4arch5arm6414KThreadContext21RestoreFpuRegisters64ERKS3_:
|
|||
msr fpsr, x1
|
||||
|
||||
/* Restore the FPU registers. */
|
||||
ldp q0, q1, [sp, #(16 * 0 + 0x80)]
|
||||
ldp q2, q3, [sp, #(16 * 2 + 0x80)]
|
||||
ldp q4, q5, [sp, #(16 * 4 + 0x80)]
|
||||
ldp q6, q7, [sp, #(16 * 6 + 0x80)]
|
||||
ldp q8, q9, [sp, #(16 * 8 + 0x80)]
|
||||
ldp q10, q11, [sp, #(16 * 10 + 0x80)]
|
||||
ldp q12, q13, [sp, #(16 * 12 + 0x80)]
|
||||
ldp q14, q15, [sp, #(16 * 14 + 0x80)]
|
||||
ldp q16, q17, [sp, #(16 * 16 + 0x80)]
|
||||
ldp q18, q19, [sp, #(16 * 18 + 0x80)]
|
||||
ldp q20, q21, [sp, #(16 * 20 + 0x80)]
|
||||
ldp q22, q23, [sp, #(16 * 22 + 0x80)]
|
||||
ldp q24, q25, [sp, #(16 * 24 + 0x80)]
|
||||
ldp q26, q27, [sp, #(16 * 26 + 0x80)]
|
||||
ldp q28, q29, [sp, #(16 * 28 + 0x80)]
|
||||
ldp q30, q31, [sp, #(16 * 30 + 0x80)]
|
||||
ldp q0, q1, [x0, #(16 * 0 + 0x80)]
|
||||
ldp q2, q3, [x0, #(16 * 2 + 0x80)]
|
||||
ldp q4, q5, [x0, #(16 * 4 + 0x80)]
|
||||
ldp q6, q7, [x0, #(16 * 6 + 0x80)]
|
||||
ldp q8, q9, [x0, #(16 * 8 + 0x80)]
|
||||
ldp q10, q11, [x0, #(16 * 10 + 0x80)]
|
||||
ldp q12, q13, [x0, #(16 * 12 + 0x80)]
|
||||
ldp q14, q15, [x0, #(16 * 14 + 0x80)]
|
||||
ldp q16, q17, [x0, #(16 * 16 + 0x80)]
|
||||
ldp q18, q19, [x0, #(16 * 18 + 0x80)]
|
||||
ldp q20, q21, [x0, #(16 * 20 + 0x80)]
|
||||
ldp q22, q23, [x0, #(16 * 22 + 0x80)]
|
||||
ldp q24, q25, [x0, #(16 * 24 + 0x80)]
|
||||
ldp q26, q27, [x0, #(16 * 26 + 0x80)]
|
||||
ldp q28, q29, [x0, #(16 * 28 + 0x80)]
|
||||
ldp q30, q31, [x0, #(16 * 30 + 0x80)]
|
||||
|
||||
ret
|
||||
|
||||
|
@ -131,13 +131,13 @@ _ZN3ams4kern4arch5arm6414KThreadContext21RestoreFpuRegisters32ERKS3_:
|
|||
msr fpsr, x1
|
||||
|
||||
/* Restore the FPU registers. */
|
||||
ldp q0, q1, [sp, #(16 * 0 + 0x80)]
|
||||
ldp q2, q3, [sp, #(16 * 2 + 0x80)]
|
||||
ldp q4, q5, [sp, #(16 * 4 + 0x80)]
|
||||
ldp q6, q7, [sp, #(16 * 6 + 0x80)]
|
||||
ldp q8, q9, [sp, #(16 * 8 + 0x80)]
|
||||
ldp q10, q11, [sp, #(16 * 10 + 0x80)]
|
||||
ldp q12, q13, [sp, #(16 * 12 + 0x80)]
|
||||
ldp q14, q15, [sp, #(16 * 14 + 0x80)]
|
||||
ldp q0, q1, [x0, #(16 * 0 + 0x80)]
|
||||
ldp q2, q3, [x0, #(16 * 2 + 0x80)]
|
||||
ldp q4, q5, [x0, #(16 * 4 + 0x80)]
|
||||
ldp q6, q7, [x0, #(16 * 6 + 0x80)]
|
||||
ldp q8, q9, [x0, #(16 * 8 + 0x80)]
|
||||
ldp q10, q11, [x0, #(16 * 10 + 0x80)]
|
||||
ldp q12, q13, [x0, #(16 * 12 + 0x80)]
|
||||
ldp q14, q15, [x0, #(16 * 14 + 0x80)]
|
||||
|
||||
ret
|
||||
|
|
Loading…
Reference in a new issue