bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 5/5] add setting gs/fsbase


From: Luca Dariz
Subject: [PATCH 5/5] add setting gs/fsbase
Date: Wed, 19 Apr 2023 21:47:03 +0200

* 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
---
 i386/i386/i386asm.sym |  2 +
 i386/i386/pcb.c       | 39 +++++++++++++++++--
 i386/i386/thread.h    |  4 ++
 kern/thread.c         |  3 ++
 x86_64/locore.S       | 89 ++++++++++++++++++++++++++++++++++---------
 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 392d38f8..f0cea804 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 1b17d921..ba0400a3 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
-- 
2.30.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]