mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
thermosphere: fpu register cache
This commit is contained in:
parent
5a445e9394
commit
c7eaf71896
7 changed files with 94 additions and 109 deletions
|
@ -18,8 +18,6 @@
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "barrier.h"
|
|
||||||
#include "execute_function.h"
|
|
||||||
|
|
||||||
struct ExceptionStackFrame;
|
struct ExceptionStackFrame;
|
||||||
typedef struct ALIGN(64) CoreCtx {
|
typedef struct ALIGN(64) CoreCtx {
|
||||||
|
@ -47,21 +45,14 @@ typedef struct ALIGN(64) CoreCtx {
|
||||||
u64 totalTimeInHypervisor; // @0x50. cntvoff_el2 is updated to that value.
|
u64 totalTimeInHypervisor; // @0x50. cntvoff_el2 is updated to that value.
|
||||||
u64 emulPtimerCval; // @0x58. When setting cntp_cval_el0 and on interrupt
|
u64 emulPtimerCval; // @0x58. When setting cntp_cval_el0 and on interrupt
|
||||||
|
|
||||||
// "Execute function"
|
|
||||||
ExecutedFunction executedFunction; // @0x60
|
|
||||||
void *executedFunctionArgs; // @0x68
|
|
||||||
Barrier executedFunctionBarrier; // @0x70
|
|
||||||
u32 executedFunctionSrcCore; // @0x74
|
|
||||||
bool executedFunctionSync; // @0x78. Receiver fills it
|
|
||||||
|
|
||||||
// Cache stuff
|
// Cache stuff
|
||||||
u32 setWayCounter; // @0x7C
|
u32 setWayCounter; // @0x7C
|
||||||
} CoreCtx;
|
} CoreCtx;
|
||||||
|
|
||||||
static_assert(offsetof(CoreCtx, warmboot) == 0x1E, "Wrong definition for CoreCtx");
|
/*static_assert(offsetof(CoreCtx, warmboot) == 0x1E, "Wrong definition for CoreCtx");
|
||||||
static_assert(offsetof(CoreCtx, emulPtimerCval) == 0x58, "Wrong definition for CoreCtx");
|
static_assert(offsetof(CoreCtx, emulPtimerCval) == 0x58, "Wrong definition for CoreCtx");
|
||||||
static_assert(offsetof(CoreCtx, executedFunctionSync) == 0x78, "Wrong definition for CoreCtx");
|
static_assert(offsetof(CoreCtx, executedFunctionSync) == 0x78, "Wrong definition for CoreCtx");
|
||||||
static_assert(offsetof(CoreCtx, setWayCounter) == 0x7C, "Wrong definition for CoreCtx");
|
static_assert(offsetof(CoreCtx, setWayCounter) == 0x7C, "Wrong definition for CoreCtx");*/
|
||||||
|
|
||||||
extern CoreCtx g_coreCtxs[4];
|
extern CoreCtx g_coreCtxs[4];
|
||||||
register CoreCtx *currentCoreCtx asm("x18");
|
register CoreCtx *currentCoreCtx asm("x18");
|
||||||
|
|
|
@ -35,6 +35,14 @@
|
||||||
public:\
|
public:\
|
||||||
static cl &GetInstance() { return instance; }
|
static cl &GetInstance() { return instance; }
|
||||||
|
|
||||||
|
#define SINGLETON_WITH_ATTRS(cl, attrs) \
|
||||||
|
NON_COPYABLE(cl);\
|
||||||
|
NON_MOVEABLE(cl);\
|
||||||
|
private:\
|
||||||
|
attrs static cl instance;\
|
||||||
|
public:\
|
||||||
|
static cl &GetInstance() { return instance; }
|
||||||
|
|
||||||
//FIXME
|
//FIXME
|
||||||
#ifndef ENSURE
|
#ifndef ENSURE
|
||||||
#define ENSURE(...)
|
#define ENSURE(...)
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fpu.h"
|
|
||||||
#include "core_ctx.h"
|
|
||||||
|
|
||||||
static FpuRegisterCache TEMPORARY g_fpuRegisterCache = { 0 };
|
|
||||||
|
|
||||||
// fpu_regs_load_store.s
|
|
||||||
void fpuLoadRegistersFromCache(const FpuRegisterCache *cache);
|
|
||||||
void fpuStoreRegistersToCache(FpuRegisterCache *cache);
|
|
||||||
|
|
||||||
FpuRegisterCache *fpuGetRegisterCache(void)
|
|
||||||
{
|
|
||||||
g_fpuRegisterCache.coreId = currentCoreCtx->coreId;
|
|
||||||
return &g_fpuRegisterCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
FpuRegisterCache *fpuReadRegisters(void)
|
|
||||||
{
|
|
||||||
FpuRegisterCache *cache = &g_fpuRegisterCache;
|
|
||||||
if (!cache->valid) {
|
|
||||||
fpuStoreRegistersToCache(cache);
|
|
||||||
cache->valid = true;
|
|
||||||
}
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpuCommitRegisters(void)
|
|
||||||
{
|
|
||||||
FpuRegisterCache *cache = &g_fpuRegisterCache;
|
|
||||||
cache->dirty = true;
|
|
||||||
|
|
||||||
// Because the caller rewrote the entire cache in the event it didn't read it before:
|
|
||||||
cache->valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpuCleanInvalidateRegisterCache(void)
|
|
||||||
{
|
|
||||||
FpuRegisterCache *cache = &g_fpuRegisterCache;
|
|
||||||
if (cache->dirty && cache->coreId == currentCoreCtx->coreId) {
|
|
||||||
fpuLoadRegistersFromCache(cache);
|
|
||||||
cache->dirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cache->valid = false;
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "spinlock.h"
|
|
||||||
typedef struct FpuRegisterCache {
|
|
||||||
u128 q[32];
|
|
||||||
u64 fpsr;
|
|
||||||
u64 fpcr;
|
|
||||||
u32 coreId;
|
|
||||||
bool valid;
|
|
||||||
bool dirty;
|
|
||||||
} FpuRegisterCache;
|
|
||||||
|
|
||||||
// Only for the current core:
|
|
||||||
|
|
||||||
FpuRegisterCache *fpuGetRegisterCache(void);
|
|
||||||
FpuRegisterCache *fpuReadRegisters(void);
|
|
||||||
void fpuCommitRegisters(void);
|
|
||||||
void fpuCleanInvalidateRegisterCache(void);
|
|
81
thermosphere/src/hvisor_fpu_register_cache.hpp
Normal file
81
thermosphere/src/hvisor_fpu_register_cache.hpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "defines.hpp"
|
||||||
|
#include "core_ctx.h"
|
||||||
|
|
||||||
|
namespace ams::hvisor {
|
||||||
|
|
||||||
|
class FpuRegisterCache final {
|
||||||
|
SINGLETON_WITH_ATTRS(FpuRegisterCache, TEMPORARY);
|
||||||
|
private:
|
||||||
|
struct Storage {
|
||||||
|
u128 q[32];
|
||||||
|
u64 fpsr;
|
||||||
|
u64 fpcr;
|
||||||
|
};
|
||||||
|
static_assert(std::is_standard_layout_v<Storage>);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void ReloadRegisters(const Storage *storage);
|
||||||
|
static void DumpRegisters(Storage *storage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Storage m_storage{};
|
||||||
|
u32 m_coreId = 0;
|
||||||
|
bool m_valid = false;
|
||||||
|
bool m_dirty = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr void TakeOwnership()
|
||||||
|
{
|
||||||
|
if (m_coreId != currentCoreCtx->coreId) {
|
||||||
|
m_valid = false;
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
m_coreId = currentCoreCtx->coreId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadRegisters()
|
||||||
|
{
|
||||||
|
if (!m_valid) {
|
||||||
|
DumpRegisters(&m_storage);
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void CommitRegisters()
|
||||||
|
{
|
||||||
|
m_dirty = true;
|
||||||
|
// Because the caller rewrote the entire cache in the event it didn't read it before:
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanInvalidate()
|
||||||
|
{
|
||||||
|
if (m_dirty && m_coreId == currentCoreCtx->coreId) {
|
||||||
|
ReloadRegisters(&m_storage);
|
||||||
|
m_dirty = false;
|
||||||
|
}
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
constexpr FpuRegisterCache() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -35,7 +35,7 @@
|
||||||
\op q30, q31, [x0], 0x20
|
\op q30, q31, [x0], 0x20
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
FUNCTION fpuLoadRegistersFromCache
|
FUNCTION _ZN3ams3hyp16FpuRegisterCache15ReloadRegistersEPKNS1_7StorageE
|
||||||
dmb ish
|
dmb ish
|
||||||
LDSTORE_QREGS ldp
|
LDSTORE_QREGS ldp
|
||||||
ldp x1, x2, [x0]
|
ldp x1, x2, [x0]
|
||||||
|
@ -46,7 +46,7 @@ FUNCTION fpuLoadRegistersFromCache
|
||||||
ret
|
ret
|
||||||
END_FUNCTION
|
END_FUNCTION
|
||||||
|
|
||||||
FUNCTION fpuStoreRegistersToCache
|
FUNCTION _ZN3ams3hyp16FpuRegisterCache13DumpRegistersEPNS1_7StorageE
|
||||||
dsb ish
|
dsb ish
|
||||||
isb
|
isb
|
||||||
LDSTORE_QREGS stp
|
LDSTORE_QREGS stp
|
|
@ -25,7 +25,7 @@
|
||||||
namespace ams::hvisor {
|
namespace ams::hvisor {
|
||||||
|
|
||||||
class VirtualGic final : public IInterruptTask {
|
class VirtualGic final : public IInterruptTask {
|
||||||
SINGLETON(VirtualGic);
|
SINGLETON_WITH_ATTRS(VirtualGic, TEMPORARY);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// For convenience, although they're already defined in irq manager header:
|
// For convenience, although they're already defined in irq manager header:
|
||||||
|
|
Loading…
Reference in a new issue