summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.cpp8
-rw-r--r--Kernel/Process.h6
-rw-r--r--Kernel/Scheduler.cpp2
-rw-r--r--Kernel/Scheduler.h1
-rw-r--r--Kernel/i386.cpp26
-rw-r--r--Kernel/i386.h11
-rw-r--r--Kernel/init.cpp4
-rw-r--r--LibGUI/GButton.cpp1
8 files changed, 50 insertions, 9 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 2582637591..37fdd3a226 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -258,6 +258,9 @@ Process* Process::fork(RegisterDump& regs)
child->m_tss.gs = regs.gs;
child->m_tss.ss = regs.ss_if_crossRing;
+ child->m_fpu_state = m_fpu_state;
+ child->m_has_used_fpu = m_has_used_fpu;
+
#ifdef FORK_DEBUG
dbgprintf("fork: child will begin executing at %w:%x with stack %w:%x\n", child->m_tss.cs, child->m_tss.eip, child->m_tss.ss, child->m_tss.esp);
#endif
@@ -588,6 +591,8 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
, m_tty(tty)
, m_ppid(ppid)
{
+ memset(&m_fpu_state, 0, sizeof(FPUState));
+
m_gids.set(m_gid);
if (fork_parent) {
@@ -698,6 +703,9 @@ Process::~Process()
ProcFS::the().remove_process(*this);
system.nprocess--;
+ if (g_last_fpu_process == this)
+ g_last_fpu_process = nullptr;
+
if (selector())
gdt_free_entry(selector());
diff --git a/Kernel/Process.h b/Kernel/Process.h
index 87321a6660..1949ba08d0 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -268,6 +268,10 @@ public:
bool wakeup_requested() { return m_wakeup_requested; }
void request_wakeup() { m_wakeup_requested = true; }
+ FPUState& fpu_state() { return m_fpu_state; }
+ bool has_used_fpu() const { return m_has_used_fpu; }
+ void set_has_used_fpu(bool b) { m_has_used_fpu = b; }
+
private:
friend class MemoryManager;
friend class Scheduler;
@@ -303,6 +307,7 @@ private:
dword m_wakeupTime { 0 };
TSS32 m_tss;
TSS32 m_tss_to_resume_kernel;
+ FPUState m_fpu_state;
struct FileDescriptorAndFlags {
operator bool() const { return !!descriptor; }
void clear() { descriptor = nullptr; flags = 0; }
@@ -372,6 +377,7 @@ private:
int m_next_window_id { 1 };
dword m_wakeup_requested { false };
+ bool m_has_used_fpu { false };
};
extern Process* current;
diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp
index 54d137421b..444c7d50ae 100644
--- a/Kernel/Scheduler.cpp
+++ b/Kernel/Scheduler.cpp
@@ -8,6 +8,7 @@
static const dword time_slice = 5; // *10 = 50ms
Process* current;
+Process* g_last_fpu_process;
static Process* s_colonel_process;
static bool s_in_yield;
@@ -299,6 +300,7 @@ void Scheduler::initialize()
initialize_redirection();
s_colonel_process = Process::create_kernel_process("colonel", nullptr);
current = nullptr;
+ g_last_fpu_process = nullptr;
s_in_yield = false;
load_task_register(s_redirection.selector);
}
diff --git a/Kernel/Scheduler.h b/Kernel/Scheduler.h
index 466de2bbe4..813939f5bb 100644
--- a/Kernel/Scheduler.h
+++ b/Kernel/Scheduler.h
@@ -6,6 +6,7 @@ class Process;
struct RegisterDump;
extern Process* current;
+extern Process* g_last_fpu_process;
class Scheduler {
public:
diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp
index 4a0d1faeb8..5b7268fc85 100644
--- a/Kernel/i386.cpp
+++ b/Kernel/i386.cpp
@@ -6,6 +6,7 @@
#include "MemoryManager.h"
#include "IRQHandler.h"
#include "PIC.h"
+#include "Scheduler.h"
//#define PAGE_FAULT_DEBUG
@@ -150,13 +151,31 @@ void exception_6_handler(RegisterDump& regs)
current->crash();
}
-// 7: FPU exception
+// 7: FPU not available exception
EH_ENTRY_NO_CODE(7);
void exception_7_handler(RegisterDump& regs)
{
(void)regs;
+
+ asm volatile("clts");
+ if (g_last_fpu_process == current)
+ return;
+ if (g_last_fpu_process) {
+ asm volatile("fnsave %0":"=m"(g_last_fpu_process->fpu_state()));
+ } else {
+ asm volatile("fnclex");
+ }
+ g_last_fpu_process = current;
+
+ if (current->has_used_fpu()) {
+ asm volatile("frstor %0"::"m"(current->fpu_state()));
+ } else {
+ asm volatile("fninit");
+ current->set_has_used_fpu(true);
+ }
+
#ifdef FPU_EXCEPTION_DEBUG
- kprintf("%s FPU exception: %u(%s)\n", current->isRing0() ? "Kernel" : "Process", current->pid(), current->name().characters());
+ kprintf("%s FPU not available exception: %u(%s)\n", current->isRing0() ? "Kernel" : "Process", current->pid(), current->name().characters());
word ss;
dword esp;
@@ -173,9 +192,6 @@ void exception_7_handler(RegisterDump& regs)
kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi);
#endif
-
- // FIXME: Do stuff.
- asm volatile("clts");
}
diff --git a/Kernel/i386.h b/Kernel/i386.h
index d48c7b481e..0b7ff5dbeb 100644
--- a/Kernel/i386.h
+++ b/Kernel/i386.h
@@ -202,6 +202,17 @@ struct RegisterDumpWithExceptionCode {
word ss_if_crossRing;
} PACKED;
+struct FPUState {
+ dword cwd;
+ dword swd;
+ dword twd;
+ dword fip;
+ dword fcs;
+ dword foo;
+ dword fos;
+ dword st[20];
+};
+
inline constexpr dword pageBaseOf(dword address)
{
return address & 0xfffff000;
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index 0e1f835d8f..4df345664e 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -138,10 +138,6 @@ void init()
gdt_init();
idt_init();
-#ifndef NO_FPU
- asm volatile("fninit");
-#endif
-
VFS::initialize_globals();
vfs = new VFS;
diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp
index 3eea022f3a..cee19019d0 100644
--- a/LibGUI/GButton.cpp
+++ b/LibGUI/GButton.cpp
@@ -42,6 +42,7 @@ void GButton::paint_event(GPaintEvent&)
} else {
// Base
painter.fill_rect({ 3, 3, width() - 5, height() - 5 }, button_color);
+ painter.fill_rect_with_gradient({ 3, 3, width() - 5, height() - 5 }, button_color, Color::White);
// White highlight
painter.draw_line({ 1, 1 }, { width() - 2, 1 }, highlight_color);