genode/repos/base-hw/src/core/include/spec/x86/fpu.h

146 lines
2.7 KiB
C++

/*
* \brief x86 FPU driver for core
* \author Adrian-Ken Rueegsegger
* \author Martin stein
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2016-01-19
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SPEC__X86__FPU_H_
#define _SPEC__X86__FPU_H_
/* Genode includes */
#include <base/stdint.h>
namespace Genode { class Fpu; }
class Genode::Fpu
{
public:
class Context
{
private:
friend class Fpu;
/*
* FXSAVE area providing storage for x87 FPU, MMX, XMM,
* and MXCSR registers.
*
* For further details see Intel SDM Vol. 2A,
* 'FXSAVE instruction'.
*/
char _fxsave_area[527];
/* 16-byte aligned start of FXSAVE area. */
char * _start = nullptr;
Fpu * _fpu = nullptr;
bool _init()
{
if (_start) return true;
_start = ((addr_t)_fxsave_area & 15)
? (char *)((addr_t)_fxsave_area & ~15) + 16
: _fxsave_area;
return false;
}
public:
~Context() { if (_fpu) _fpu->unset(*this); }
} __attribute__((aligned(16)));
private:
enum { MXCSR_DEFAULT = 0x1f80 };
Context * _context = nullptr;
/**
* Reset FPU
*
* Doesn't check for pending unmasked floating-point
* exceptions and explicitly sets the MXCSR to the
* default value.
*/
void _reset()
{
unsigned value = MXCSR_DEFAULT;
asm volatile ("fninit");
asm volatile ("ldmxcsr %0" : : "m" (value));
}
/**
* Load x87 FPU context
*/
void _load()
{
if (!_context->_init()) _reset();
else asm volatile ("fxrstor %0" : : "m" (*_context->_start));
}
/**
* Save x87 FPU context
*/
void _save() {
asm volatile ("fxsave %0" : "=m" (*_context->_start)); }
public:
/**
* Disable FPU by setting the TS flag in CR0.
*/
void disable();
/**
* Enable FPU by clearing the TS flag in CR0.
*/
void enable() { asm volatile ("clts"); }
/**
* Initialize all FPU-related CR flags
*
* Initialize FPU with SSE extensions by setting required CR0 and CR4
* bits to configure the FPU environment according to Intel SDM Vol.
* 3A, sections 9.2 and 9.6.
*/
void init();
/**
* Returns True if the FPU is enabled.
*/
bool enabled();
/**
* Switch to new context
*
* \param context next FPU context
*/
void switch_to(Context &context) {
if (_context != &context) disable(); }
/**
* Return whether to retry an FPU instruction after this call
*/
bool fault(Context &context);
/**
* Unset FPU context
*/
void unset(Context &context) {
if (_context == &context) _context = nullptr; }
};
#endif /* _SPEC__X86__FPU_H_ */