aboutsummaryrefslogtreecommitdiff
path: root/i386
diff options
context:
space:
mode:
authorLuca Dariz <luca@orpolo.org>2023-04-19 21:47:03 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2023-05-01 03:30:18 +0200
commit31dd30a94a682955c3c9e2f42252b4a07687067a (patch)
tree66be830d547a1e9cbd1b9b7bbc0378398be089d8 /i386
parent660bc8ab3813737b3857648b7ec60d88494aeed1 (diff)
downloadgnumach-31dd30a94a682955c3c9e2f42252b4a07687067a.tar.gz
gnumach-31dd30a94a682955c3c9e2f42252b4a07687067a.tar.bz2
gnumach-31dd30a94a682955c3c9e2f42252b4a07687067a.zip
add setting gs/fsbase
* i386/i386/i386asm.sym: add offsets for asm * i386/i386/pcb.c: switch FSBASE/GSBASE on context switch and implement accessors in thread setstatus/getstatus * i386/i386/thread.h: add new state to thread saved state * kern/thread.c: add i386_FSGS_BASE_STATE handler * x86_64/locore.S: fix fs/gs handling, skipping the base address and avoid resetting it by manually re-loading fs/gs Message-Id: <20230419194703.410575-5-luca@orpolo.org>
Diffstat (limited to 'i386')
-rw-r--r--i386/i386/i386asm.sym2
-rw-r--r--i386/i386/pcb.c39
-rw-r--r--i386/i386/thread.h4
3 files changed, 42 insertions, 3 deletions
diff --git a/i386/i386/i386asm.sym b/i386/i386/i386asm.sym
index 1b9b40bb..fd0be557 100644
--- a/i386/i386/i386asm.sym
+++ b/i386/i386/i386asm.sym
@@ -108,6 +108,8 @@ offset i386_saved_state r r12
offset i386_saved_state r r13
offset i386_saved_state r r14
offset i386_saved_state r r15
+offset i386_saved_state r fsbase
+offset i386_saved_state r gsbase
#endif
offset i386_interrupt_state i eip
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index 61125fe8..8a9e3bf4 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -51,6 +51,7 @@
#include "eflags.h"
#include "gdt.h"
#include "ldt.h"
+#include "msr.h"
#include "ktss.h"
#include "pcb.h"
@@ -372,7 +373,10 @@ thread_t switch_context(
* Load the rest of the user state for the new thread
*/
switch_ktss(new->pcb);
-
+#if defined(__x86_64__) && !defined(USER32)
+ wrmsr(MSR_REG_FSBASE, new->pcb->iss.fsbase);
+ wrmsr(MSR_REG_GSBASE, new->pcb->iss.gsbase);
+#endif
return Switch_context(old, continuation, new);
}
@@ -667,7 +671,23 @@ kern_return_t thread_setstatus(
return ret;
break;
}
-
+#if defined(__x86_64__) && !defined(USER32)
+ case i386_FSGS_BASE_STATE:
+ {
+ struct i386_fsgs_base_state *state;
+ if (count < i386_FSGS_BASE_STATE_COUNT)
+ return KERN_INVALID_ARGUMENT;
+
+ state = (struct i386_fsgs_base_state *) tstate;
+ thread->pcb->iss.fsbase = state->fs_base;
+ thread->pcb->iss.gsbase = state->gs_base;
+ if (thread == current_thread()) {
+ wrmsr(MSR_REG_FSBASE, state->fs_base);
+ wrmsr(MSR_REG_GSBASE, state->gs_base);
+ }
+ break;
+ }
+#endif
default:
return(KERN_INVALID_ARGUMENT);
}
@@ -843,7 +863,20 @@ kern_return_t thread_getstatus(
*count = i386_DEBUG_STATE_COUNT;
break;
}
-
+#if defined(__x86_64__) && !defined(USER32)
+ case i386_FSGS_BASE_STATE:
+ {
+ struct i386_fsgs_base_state *state;
+ if (*count < i386_FSGS_BASE_STATE_COUNT)
+ return KERN_INVALID_ARGUMENT;
+
+ state = (struct i386_fsgs_base_state *) tstate;
+ state->fs_base = thread->pcb->iss.fsbase;
+ state->fs_base = thread->pcb->iss.gsbase;
+ *count = i386_FSGS_BASE_STATE_COUNT;
+ break;
+ }
+#endif
default:
return(KERN_INVALID_ARGUMENT);
}
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index 933b43d8..b5fc5ffb 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -51,6 +51,10 @@
*/
struct i386_saved_state {
+#ifdef __x86_64__
+ unsigned long fsbase;
+ unsigned long gsbase;
+#endif
unsigned long gs;
unsigned long fs;
unsigned long es;