1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2019 Joyent, Inc.
  14  */
  15 
  16         .file   "retpoline.s"
  17 
  18 /*
  19  * This file implements the various hooks that are needed for retpolines and
  20  * return stack buffer (RSB) stuffing. For more information, please see the
  21  * 'Speculative Execution CPU Side Channel Security' section of the
  22  * uts/i86pc/os/cpuid.c big theory statement.
  23  */
  24 
  25 #include <sys/asm_linkage.h>
  26 #include <sys/x86_archext.h>
  27 
  28 #if defined(__amd64)
  29 
  30 /*
  31  * This macro generates the default retpoline entry point that the compiler
  32  * expects. It implements the expected retpoline form.
  33  */
  34 #define RETPOLINE_MKTHUNK(reg) \
  35         ENTRY(__x86_indirect_thunk_/**/reg)     \
  36         call    2f;                             \
  37 1:                                              \
  38         pause;                                  \
  39         lfence;                                 \
  40         jmp     1b;                             \
  41 2:                                              \
  42         movq    %/**/reg, (%rsp);               \
  43         ret;                                    \
  44         SET_SIZE(__x86_indirect_thunk_/**/reg)
  45 
  46 /*
  47  * This macro generates the default retpoline form. It exists in addition to the
  48  * thunk so if we need to restore the default retpoline behavior to the thunk
  49  * we can.
  50  */
  51 #define RETPOLINE_MKGENERIC(reg) \
  52         ENTRY(__x86_indirect_thunk_gen_/**/reg) \
  53         call    2f;                             \
  54 1:                                              \
  55         pause;                                  \
  56         lfence;                                 \
  57         jmp     1b;                             \
  58 2:                                              \
  59         movq    %/**/reg, (%rsp);               \
  60         ret;                                    \
  61         SET_SIZE(__x86_indirect_thunk_gen_/**/reg)
  62 
  63 /*
  64  * This macro generates the AMD optimized form of a retpoline which will be used
  65  * on systems where the lfence dispatch serializing behavior has been changed.
  66  */
  67 #define RETPOLINE_MKLFENCE(reg)                 \
  68         ENTRY(__x86_indirect_thunk_amd_/**/reg) \
  69         lfence;                                 \
  70         jmp     *%/**/reg;                      \
  71         SET_SIZE(__x86_indirect_thunk_amd_/**/reg)
  72 
  73 
  74 /*
  75  * This macro generates the no-op form of the retpoline which will be used if we
  76  * either need to disable retpolines because we have enhanced IBRS or because we
  77  * have been asked to disable mitigations.
  78  */
  79 #define RETPOLINE_MKJUMP(reg)                   \
  80         ENTRY(__x86_indirect_thunk_jmp_/**/reg) \
  81         jmp     *%/**/reg;                      \
  82         SET_SIZE(__x86_indirect_thunk_jmp_/**/reg)
  83 
  84         RETPOLINE_MKTHUNK(rax)
  85         RETPOLINE_MKTHUNK(rbx)
  86         RETPOLINE_MKTHUNK(rcx)
  87         RETPOLINE_MKTHUNK(rdx)
  88         RETPOLINE_MKTHUNK(rdi)
  89         RETPOLINE_MKTHUNK(rsi)
  90         RETPOLINE_MKTHUNK(rbp)
  91         RETPOLINE_MKTHUNK(r8)
  92         RETPOLINE_MKTHUNK(r9)
  93         RETPOLINE_MKTHUNK(r10)
  94         RETPOLINE_MKTHUNK(r11)
  95         RETPOLINE_MKTHUNK(r12)
  96         RETPOLINE_MKTHUNK(r13)
  97         RETPOLINE_MKTHUNK(r14)
  98         RETPOLINE_MKTHUNK(r15)
  99 
 100         RETPOLINE_MKGENERIC(rax)
 101         RETPOLINE_MKGENERIC(rbx)
 102         RETPOLINE_MKGENERIC(rcx)
 103         RETPOLINE_MKGENERIC(rdx)
 104         RETPOLINE_MKGENERIC(rdi)
 105         RETPOLINE_MKGENERIC(rsi)
 106         RETPOLINE_MKGENERIC(rbp)
 107         RETPOLINE_MKGENERIC(r8)
 108         RETPOLINE_MKGENERIC(r9)
 109         RETPOLINE_MKGENERIC(r10)
 110         RETPOLINE_MKGENERIC(r11)
 111         RETPOLINE_MKGENERIC(r12)
 112         RETPOLINE_MKGENERIC(r13)
 113         RETPOLINE_MKGENERIC(r14)
 114         RETPOLINE_MKGENERIC(r15)
 115 
 116         RETPOLINE_MKLFENCE(rax)
 117         RETPOLINE_MKLFENCE(rbx)
 118         RETPOLINE_MKLFENCE(rcx)
 119         RETPOLINE_MKLFENCE(rdx)
 120         RETPOLINE_MKLFENCE(rdi)
 121         RETPOLINE_MKLFENCE(rsi)
 122         RETPOLINE_MKLFENCE(rbp)
 123         RETPOLINE_MKLFENCE(r8)
 124         RETPOLINE_MKLFENCE(r9)
 125         RETPOLINE_MKLFENCE(r10)
 126         RETPOLINE_MKLFENCE(r11)
 127         RETPOLINE_MKLFENCE(r12)
 128         RETPOLINE_MKLFENCE(r13)
 129         RETPOLINE_MKLFENCE(r14)
 130         RETPOLINE_MKLFENCE(r15)
 131 
 132         RETPOLINE_MKJUMP(rax)
 133         RETPOLINE_MKJUMP(rbx)
 134         RETPOLINE_MKJUMP(rcx)
 135         RETPOLINE_MKJUMP(rdx)
 136         RETPOLINE_MKJUMP(rdi)
 137         RETPOLINE_MKJUMP(rsi)
 138         RETPOLINE_MKJUMP(rbp)
 139         RETPOLINE_MKJUMP(r8)
 140         RETPOLINE_MKJUMP(r9)
 141         RETPOLINE_MKJUMP(r10)
 142         RETPOLINE_MKJUMP(r11)
 143         RETPOLINE_MKJUMP(r12)
 144         RETPOLINE_MKJUMP(r13)
 145         RETPOLINE_MKJUMP(r14)
 146         RETPOLINE_MKJUMP(r15)
 147 
 148         /*
 149          * The x86_rsb_stuff function is called from pretty arbitrary
 150          * contexts. It's much easier for us to save and restore all the
 151          * registers we touch rather than clobber them for callers. You must
 152          * preserve this property or the system will panic at best.
 153          */
 154         ENTRY(x86_rsb_stuff)
 155         /*
 156          * These nops are present so we can patch a ret instruction if we need
 157          * to disable RSB stuffing because enhanced IBRS is present or we're
 158          * disabling mitigations.
 159          */
 160         nop
 161         nop
 162         pushq   %rdi
 163         pushq   %rax
 164         movl    $16, %edi
 165         movq    %rsp, %rax
 166 rsb_loop:
 167         call    2f
 168 1:
 169         pause
 170         call    1b
 171 2:
 172         call    2f
 173 1:
 174         pause
 175         call    1b
 176 2:
 177         subl    $1, %edi
 178         jnz     rsb_loop
 179         movq    %rax, %rsp
 180         popq    %rax
 181         popq    %rdi
 182         ret
 183         SET_SIZE(x86_rsb_stuff)
 184 
 185 #elif defined(__i386)
 186 
 187 /*
 188  * While the kernel is 64-bit only, dboot is still 32-bit, so there are a
 189  * limited number of variants that are used for 32-bit. However as dboot is
 190  * short lived and uses them sparingly, we only do the full variant and do not
 191  * have an AMD specific version.
 192  */
 193 
 194 #define RETPOLINE_MKTHUNK(reg) \
 195         ENTRY(__x86_indirect_thunk_/**/reg)     \
 196         call    2f;                             \
 197 1:                                              \
 198         pause;                                  \
 199         lfence;                                 \
 200         jmp     1b;                             \
 201 2:                                              \
 202         movl    %/**/reg, (%esp);               \
 203         ret;                                    \
 204         SET_SIZE(__x86_indirect_thunk_/**/reg)
 205 
 206         RETPOLINE_MKTHUNK(edi)
 207         RETPOLINE_MKTHUNK(eax)
 208 
 209 #else
 210 #error  "Your architecture is in another castle."
 211 #endif