[kernel] Add MXCSR handling, mask SIMD exceptions

Now threads inherit their MXCSR (sans exception state bits) SIMD
settings from their creator. By default, all exceptions are masked, and
both "to zero" flags are set.
This commit is contained in:
Justin C. Miller
2023-05-21 14:48:27 -07:00
parent f215b98f74
commit da14fd123e
7 changed files with 68 additions and 9 deletions

View File

@@ -118,6 +118,19 @@ cpu_early_init(cpu_data *cpu)
.set(xcr0::SSE); .set(xcr0::SSE);
set_xcr0(xcr0_val); set_xcr0(xcr0_val);
// Set initial floating point state
const util::bitset32 mxcsr_val {
mxcsr::DAZ,
mxcsr::IM,
mxcsr::DM,
mxcsr::ZM,
mxcsr::OM,
mxcsr::UM,
mxcsr::PM,
mxcsr::FTZ,
};
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
// Install the GS base pointint to the cpu_data // Install the GS base pointint to the cpu_data
wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu)); wrmsr(msr::ia32_gs_base, reinterpret_cast<uintptr_t>(cpu));
} }
@@ -234,3 +247,13 @@ cpu_init(cpu_data *cpu, bool bsp)
xsave_enable(); xsave_enable();
} }
/// Set up initial per-thread CPU state. Called once from initialize_user_cpu in
/// syscall.s, the first code run after a thread comes out of task_switch for the
/// very first time.
extern "C" void
cpu_initialize_thread_state()
{
const util::bitset32 &mxcsr_val = obj::thread::current().m_mxcsr;
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
}

View File

@@ -142,6 +142,8 @@ extern "C" {
uint64_t set_xcr0(uint64_t val); uint64_t set_xcr0(uint64_t val);
cpu_data * _current_gsbase(); cpu_data * _current_gsbase();
void cpu_initialize_thread_state();
} }
/// Do early initialization of the BSP CPU. /// Do early initialization of the BSP CPU.

View File

@@ -145,6 +145,30 @@ isr_handler(cpu_state *regs)
} }
break; break;
case isr::isrSIMDFPE: {
uint32_t mxcsr = 0;
asm volatile ("stmxcsr %0" : "=m"(mxcsr));
util::format({message, sizeof(message)},
"SIMD Exception; MXCSR[%s%s%s%s%s%s%s%s%s%s%s%s%s%s rc:%d]",
(mxcsr & 0x0001) ? " IE" : "",
(mxcsr & 0x0002) ? " DE" : "",
(mxcsr & 0x0004) ? " ZE" : "",
(mxcsr & 0x0008) ? " OE" : "",
(mxcsr & 0x0010) ? " UE" : "",
(mxcsr & 0x0020) ? " PE" : "",
(mxcsr & 0x0040) ? " DAZ" : "",
(mxcsr & 0x0080) ? " IM" : "",
(mxcsr & 0x0100) ? " DM" : "",
(mxcsr & 0x0200) ? " ZM" : "",
(mxcsr & 0x0400) ? " OM" : "",
(mxcsr & 0x0800) ? " UM" : "",
(mxcsr & 0x1000) ? " PM" : "",
(mxcsr & 0x8000) ? " FTZ" : "",
((mxcsr >> 13) & 0x3));
kassert(false, message, regs);
}
break;
case isr::isrSpurious: case isr::isrSpurious:
// No EOI for the spurious interrupt // No EOI for the spurious interrupt
return; return;

View File

@@ -34,6 +34,15 @@ thread::thread(process &parent, uint8_t pri, uintptr_t rsp0) :
m_tcb.rsp0 = rsp0; m_tcb.rsp0 = rsp0;
m_creator = current_cpu().thread; m_creator = current_cpu().thread;
asm volatile ( "stmxcsr %0" : "=m"(m_mxcsr) );
m_mxcsr
.clear(mxcsr::IE)
.clear(mxcsr::DE)
.clear(mxcsr::ZE)
.clear(mxcsr::OE)
.clear(mxcsr::UE)
.clear(mxcsr::PE);
} }
thread::~thread() thread::~thread()

View File

@@ -7,10 +7,10 @@
#include <util/linked_list.h> #include <util/linked_list.h>
#include <util/spinlock.h> #include <util/spinlock.h>
#include "cpu.h"
#include "objects/kobject.h" #include "objects/kobject.h"
#include "wait_queue.h" #include "wait_queue.h"
struct cpu_data;
struct page_table; struct page_table;
namespace obj { namespace obj {
@@ -176,6 +176,7 @@ private:
thread(const thread &other) = delete; thread(const thread &other) = delete;
thread(const thread &&other) = delete; thread(const thread &&other) = delete;
friend class process; friend class process;
friend void ::cpu_initialize_thread_state();
/// Constructor. Used when a kernel stack already exists. /// Constructor. Used when a kernel stack already exists.
/// \arg parent The process which owns this thread /// \arg parent The process which owns this thread
@@ -195,6 +196,7 @@ private:
thread *m_creator; thread *m_creator;
state m_state; state m_state;
util::bitset32 m_mxcsr;
uint64_t m_wake_value; uint64_t m_wake_value;
uint64_t m_wake_timeout; uint64_t m_wake_timeout;

View File

@@ -16,10 +16,11 @@ STAR_HIGH equ \
; IA32_FMASK - Mask off interrupts in syscalls ; IA32_FMASK - Mask off interrupts in syscalls
FMASK_VAL equ 0x200 FMASK_VAL equ 0x200
extern __counter_syscall_enter extern __counter_syscall_enter ; syscall.cpp.cog
extern __counter_syscall_sysret extern __counter_syscall_sysret ;
extern syscall_registry extern syscall_registry ;
extern syscall_invalid extern syscall_invalid ;
extern cpu_initialize_thread_state ; cpu.cpp
global syscall_handler_prelude: function hidden (syscall_handler_prelude.end - syscall_handler_prelude) global syscall_handler_prelude: function hidden (syscall_handler_prelude.end - syscall_handler_prelude)
@@ -79,6 +80,8 @@ syscall_handler_prelude:
global initialize_user_cpu: function hidden (initialize_user_cpu.end - initialize_user_cpu) global initialize_user_cpu: function hidden (initialize_user_cpu.end - initialize_user_cpu)
initialize_user_cpu: initialize_user_cpu:
call cpu_initialize_thread_state
mov rax, 0xaaaaaaaa mov rax, 0xaaaaaaaa
mov rdx, 0xdddddddd mov rdx, 0xdddddddd
mov r8, 0x08080808 mov r8, 0x08080808

View File

@@ -66,8 +66,6 @@ namespace {
template <> template <>
class bitset<64> class bitset<64>
{ {
static constexpr unsigned num_elems = 1;
template <typename T> template <typename T>
static constexpr uint64_t bit_or(T b) { return 1ull << uint64_t(b); } static constexpr uint64_t bit_or(T b) { return 1ull << uint64_t(b); }
@@ -127,8 +125,6 @@ private:
template <> template <>
class bitset<32> class bitset<32>
{ {
static constexpr unsigned num_elems = 1;
template <typename T> template <typename T>
static constexpr uint32_t bit_or(T b) { return 1u << uint32_t(b); } static constexpr uint32_t bit_or(T b) { return 1u << uint32_t(b); }