aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--i386/i386/i386asm.sym2
-rw-r--r--i386/i386/pcb.c39
-rw-r--r--i386/i386/thread.h4
-rw-r--r--kern/thread.c3
-rw-r--r--x86_64/locore.S89
5 files changed, 116 insertions, 21 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;
diff --git a/kern/thread.c b/kern/thread.c
index 20c11024..a324eed7 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -1472,6 +1472,9 @@ kern_return_t thread_set_state(
if (flavor == i386_DEBUG_STATE && thread == current_thread())
/* This state can be set directly for the curren thread. */
return thread_setstatus(thread, flavor, new_state, new_state_count);
+ if (flavor == i386_FSGS_BASE_STATE && thread == current_thread())
+ /* This state can be set directly for the curren thread. */
+ return thread_setstatus(thread, flavor, new_state, new_state_count);
#endif
if (thread == THREAD_NULL || thread == current_thread())
diff --git a/x86_64/locore.S b/x86_64/locore.S
index 0d7cdd0e..366ef292 100644
--- a/x86_64/locore.S
+++ b/x86_64/locore.S
@@ -34,6 +34,7 @@
#include <i386/i386/trap.h>
#include <i386/i386/seg.h>
#include <i386/i386/ldt.h>
+#include <i386/i386/msr.h>
#include <i386/i386/i386asm.h>
#include <i386/i386/cpu_number.h>
#include <i386/i386/xen.h>
@@ -41,6 +42,46 @@
#define pusha pushq %rax ; pushq %rcx ; pushq %rdx ; pushq %rbx ; subq $8,%rsp ; pushq %rbp ; pushq %rsi ; pushq %rdi ; pushq %r8 ; pushq %r9 ; pushq %r10 ; pushq %r11 ; pushq %r12 ; pushq %r13 ; pushq %r14 ; pushq %r15
#define popa popq %r15 ; popq %r14 ; popq %r13 ; popq %r12 ; popq %r11 ; popq %r10 ; popq %r9 ; popq %r8 ; popq %rdi ; popq %rsi ; popq %rbp ; addq $8,%rsp ; popq %rbx ; popq %rdx ; popq %rcx ; popq %rax
+#ifdef USER32
+#define PUSH_FSGS \
+ pushq %fs ;\
+ pushq %gs ;\
+ subq $16,%rsp
+#else
+#define PUSH_FSGS \
+ subq $32,%rsp
+#endif
+
+#ifdef USER32
+#define POP_FSGS \
+ popq %gs ;\
+ popq %fs ;\
+ addq $16,%rsp
+#else
+#define POP_FSGS \
+ addq $32,%rsp
+#endif
+
+#ifdef USER32
+#define PUSH_FSGS_ISR \
+ pushq %fs ;\
+ pushq %gs
+#else
+#define PUSH_FSGS_ISR \
+ subq $16,%rsp
+#endif
+
+#ifdef USER32
+#define POP_FSGS_ISR \
+ popq %gs ;\
+ popq %fs
+#else
+#define POP_FSGS_ISR \
+ addq $16,%rsp
+#endif
+
+
+
/*
* Fault recovery.
*/
@@ -405,6 +446,11 @@ push_fs:
pushq %fs /* restore fs, */
push_gs:
pushq %gs /* restore gs. */
+#ifdef USER32
+push_gsbase:
+ pushq $0
+ pushq $0
+#endif
push_segregs:
movq %rax,R_TRAPNO(%rsp) /* set trap number */
movq %rdx,R_ERR(%rsp) /* set error code */
@@ -470,8 +516,7 @@ trap_push_segs:
pushq %rax
movq %es,%rax /* and the segment registers */
pushq %rax
- pushq %fs
- pushq %gs
+ PUSH_FSGS
/* Note that we have to load the segment registers
even if this is a trap from the kernel,
@@ -480,9 +525,10 @@ trap_push_segs:
mov %ss,%ax /* switch to kernel data segment */
mov %ax,%ds /* (same as kernel stack segment) */
mov %ax,%es
+#ifdef USER32
mov %ax,%fs
mov %ax,%gs
-
+#endif
trap_set_segs:
cld /* clear direction flag */
testl $(EFL_VM),R_EFLAGS(%rsp) /* in V86 mode? */
@@ -536,10 +582,17 @@ _return_to_user:
*/
_return_from_kernel:
+ addq $16,%rsp /* skip FS/GS base */
+#ifndef USER32
+_kret_popl_gs:
+_kret_popl_fs:
+ addq $16,%rsp /* skip FS/GS selector */
+#else
_kret_popl_gs:
popq %gs /* restore segment registers */
_kret_popl_fs:
popq %fs
+#endif
_kret_popl_es:
popq %rax
movq %rax,%es
@@ -695,14 +748,15 @@ ENTRY(all_intrs)
pushq %rdx
movq %es,%rdx
pushq %rdx
- pushq %fs
- pushq %gs
+ PUSH_FSGS_ISR
+
mov %ss,%dx /* switch to kernel segments */
mov %dx,%ds
mov %dx,%es
+#ifdef USER32
mov %dx,%fs
mov %dx,%gs
-
+#endif
CPU_NUMBER(%edx)
movq CX(EXT(int_stack_top),%edx),%rcx
@@ -741,8 +795,7 @@ LEXT(return_to_iret) /* ( label for kdb_kintr and hardclock) */
cmpq $0,CX(EXT(need_ast),%edx)
jnz ast_from_interrupt /* take it if so */
1:
- pop %gs /* restore segment regs */
- pop %fs
+ POP_FSGS_ISR
pop %rdx
mov %rdx,%es
pop %rdx
@@ -796,9 +849,7 @@ stack_overflowed:
* ss
*/
ast_from_interrupt:
- pop %gs /* restore all registers ... */
- pop %fs
- pop %rdx
+ POP_FSGS
mov %rdx,%es
pop %rdx
mov %rdx,%ds
@@ -818,14 +869,15 @@ ast_from_interrupt:
push %rdx
mov %es,%rdx
push %rdx
- push %fs
- push %gs
+ PUSH_FSGS
+
mov %ss,%dx /* switch to kernel segments */
mov %dx,%ds
mov %dx,%es
+#ifdef USER32
mov %dx,%fs
mov %dx,%gs
-
+#endif
CPU_NUMBER(%edx)
TIME_TRAP_UENTRY
@@ -947,14 +999,12 @@ kdb_from_iret_i: /* on interrupt stack */
push %rdx
mov %es,%rdx
push %rdx
- push %fs
- push %gs
+ PUSH_FSGS
movq %rsp,%rdx /* pass regs, */
movq $0,%rsi /* code, */
movq $-1,%rdi /* type to kdb */
call EXT(kdb_trap)
- pop %gs /* restore segment registers */
- pop %fs
+ POP_FSGS
pop %rdx
mov %rdx,%es
pop %rdx
@@ -1039,6 +1089,7 @@ ttd_from_iret_i: /* on interrupt stack */
push %rdx
push %fs
push %gs
+ ud2 // TEST it
movq %rsp,%rdx /* pass regs, */
movq $0,%rsi /* code, */
movq $-1,%rdi /* type to kdb */
@@ -1087,6 +1138,8 @@ syscall_entry_2:
pushq %rdx
pushq %fs
pushq %gs
+ pushq $0 // gsbase
+ pushq $0 // fsbase
mov %ss,%dx /* switch to kernel data segment */
mov %dx,%ds