x86: Dangerous read/write MSR interface

Provides a syscall interface for reading and writing arbitrary MSR values. This is
being introduced as an alternative to the DebugRun, as the main purpose of debug run
is for modifying the performance monitoring events via read/write MSR.
This commit is contained in:
Adrian Danis 2018-01-16 16:53:45 +11:00
parent 425ceb9cb3
commit eec02fd223
7 changed files with 89 additions and 0 deletions

View file

@ -26,6 +26,7 @@ between two same priority threads: the sender will be scheduled, rather than the
* Benchmarking support for armv8/aarch64 is now available.
* Additional x86 extra bootinfo type for retrieving frame buffer information from multiboot 2
* Debugging option to export x86 Performance-Monitoring Counters to user level
* Debugging option on x86 for syscall interface to read/write MSRs (this is an, equally dangerous, alternative to dangerous code injection)
= Upgrade notes =
* seL4_CapData_t should be replaced with just seL4_Word. Construction of badges should just be `x` instead of

View file

@ -51,6 +51,10 @@
<syscall name="BenchmarkGetThreadUtilisation" />
<syscall name="BenchmarkResetThreadUtilisation" />
</config>
<config condition="defined CONFIG_KERNEL_X86_DANGEROUS_MSR">
<syscall name="X86DangerousWRMSR"/>
<syscall name="X86DangerousRDMSR"/>
</config>
<!-- This is not a debug syscall, but it needs to not appear in the 'API' syscall list
so that the check of 'is this a valid syscall' can remain a simple range check.
Therefore we'll put this here and the arch code will handle it before

View file

@ -601,6 +601,25 @@ seL4_DebugRun(void (*userfn) (void *), void* userarg)
}
#endif
#if defined(CONFIG_KERNEL_X86_DANGEROUS_MSR)
LIBSEL4_INLINE_FUNC void
seL4_X86DangerousWRMSR(seL4_Uint32 msr, uint64_t value)
{
seL4_Uint32 value_low = value & 0xffffffff;
seL4_Uint32 value_high = value >> 32;
x86_sys_send(seL4_SysX86DangerousWRMSR, msr, 0, value_low, value_high);
}
LIBSEL4_INLINE_FUNC seL4_Uint64
seL4_X86DangerousRDMSR(seL4_Word msr)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word low, high;
x86_sys_recv(seL4_SysX86DangerousRDMSR, msr, &unused0, &unused1, &low, &high);
return ((seL4_Uint64)low) | ((seL4_Uint64)high << 32);
}
#endif
#ifdef CONFIG_ENABLE_BENCHMARKS
LIBSEL4_INLINE_FUNC seL4_Error
seL4_BenchmarkResetLog(void)

View file

@ -363,6 +363,26 @@ seL4_DebugHalt(void)
}
#endif
#if defined(CONFIG_KERNEL_X86_DANGEROUS_MSR)
LIBSEL4_INLINE_FUNC void
seL4_X86DangerousWRMSR(seL4_Uint32 msr, seL4_Uint64 value)
{
x64_sys_send(seL4_SysX86DangerousWRMSR, msr, 0, value, 0, 0, 0);
}
LIBSEL4_INLINE_FUNC seL4_Uint64
seL4_X86DangerousRDMSR(seL4_Uint32 msr)
{
seL4_Word unused0 = 0;
seL4_Word unused1 = 0;
seL4_Word unused2 = 0;
seL4_Word unused3 = 0;
seL4_Word unused4 = 0;
seL4_Word val;
x64_sys_recv(seL4_SysX86DangerousRDMSR, msr, &unused0, &unused1, &val, &unused2, &unused3, &unused4);
return val;
}
#endif
#if defined(CONFIG_DEBUG_BUILD)
LIBSEL4_INLINE_FUNC void
seL4_DebugSnapshot(void)

View file

@ -128,6 +128,34 @@ handleUnknownSyscall(word_t w)
}
#endif
#ifdef CONFIG_KERNEL_X86_DANGEROUS_MSR
if (w == SysX86DangerousWRMSR) {
uint64_t val;
uint32_t reg = getRegister(NODE_STATE(ksCurThread), capRegister);
if (CONFIG_WORD_SIZE == 32) {
val = (uint64_t)getSyscallArg(0, NULL) | ((uint64_t)getSyscallArg(1, NULL) << 32);
} else {
val = getSyscallArg(0, NULL);
}
x86_wrmsr(reg, val);
return EXCEPTION_NONE;
} else if (w == SysX86DangerousRDMSR) {
uint64_t val;
uint32_t reg = getRegister(NODE_STATE(ksCurThread), capRegister);
val = x86_rdmsr(reg);
int num = 1;
if (CONFIG_WORD_SIZE == 32) {
setMR(NODE_STATE(ksCurThread), NULL, 0, val & 0xffffffff);
setMR(NODE_STATE(ksCurThread), NULL, 1, val >> 32);
num++;
} else {
setMR(NODE_STATE(ksCurThread), NULL, 0, val);
}
setRegister(NODE_STATE(ksCurThread), msgInfoRegister, wordFromMessageInfo(seL4_MessageInfo_new(0, 0, 0, num)));
return EXCEPTION_NONE;
}
#endif
#ifdef CONFIG_ENABLE_BENCHMARKS
if (w == SysBenchmarkFlushCaches) {
arch_clean_invalidate_caches();

View file

@ -246,6 +246,14 @@ config_option(KernelExportPMCUser EXPORT_PMC_USER
DEPENDS "KernelArchX86;NOT KernelVerificationBuild"
)
config_option(KernelX86DangerousMSR KERNEL_X86_DANGEROUS_MSR
"rdmsr/wrmsr kernel interface. Provides a syscall interface for reading and writing arbitrary MSRs.
This is extremely dangerous as no checks are performed and exists
to aid debugging and benchmarking."
DEFAULT OFF
DEPENDS "KernelArchX86;NOT KernelVerificationBuild"
)
add_sources(
DEP "KernelArchX86"
PREFIX src/arch/x86

View file

@ -311,3 +311,12 @@ config EXPORT_PMC_USER
are counting. Nevertheless whilst this is useful for
evalulating performance this option opens timing and covert
channels.
config KERNEL_X86_DANGEROUS_MSR
bool "rdmsr/wrmsr kernel interface"
depends on ARCH_X86 && !VERIFICATION_BUILD
default n
help
Provides a syscall interface for reading and writing arbitrary MSRs.
This is extremely dangerous as no checks are performed and exists
to aid debugging and benchmarking