"Fossies" - the Fresh Open Source Software Archive

Member "ndiswrapper-1.63/driver/win2lin_stubs.S" (3 May 2020, 7937 Bytes) of package /linux/misc/ndiswrapper-1.63.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PowerPC Assembler source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "win2lin_stubs.S": 1.62_vs_1.63.

    1 /*
    2  *  Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani
    3  *
    4  *  This program is free software; you can redistribute it and/or modify
    5  *  it under the terms of the GNU General Public License as published by
    6  *  the Free Software Foundation; either version 2 of the License, or
    7  *  (at your option) any later version.
    8  *
    9  *  This program is distributed in the hope that it will be useful,
   10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   12  *  GNU General Public License for more details.
   13  *
   14  */
   15 
   16 #include <linux/linkage.h>
   17 #include <linux/version.h>
   18 
   19 #ifdef CONFIG_X86_64
   20 
   21 /*
   22 # Windows <---> Linux register usage conversion when calling functions
   23 # V = Volatile
   24 # NV = Non Volatile (needs to be saved)
   25 #
   26 #         Win                     Lin
   27 # ---------------------------------------
   28 # Rax    Return           V       Return          V
   29 # Rbx                     NV                      NV
   30 # Rcx     Arg1            V       Arg4            V
   31 # Rdx     Arg2            V       Arg3            V
   32 # Rsi                     NV      Arg2            V
   33 # Rdi                     NV      Arg1            V
   34 # Rsp                     NV                      NV
   35 # Rbp                     NV                      NV
   36 # R8      Arg3            V       Arg5            V
   37 # R9      Arg4            V       Arg6            V
   38 # R10                     V                       V
   39 # R11                     V                       V
   40 # R12                     NV                      NV
   41 # R13                     NV                      NV
   42 # R14                     NV                      NV
   43 # R15                     NV                      NV
   44 #
   45 # In addition, Linux uses %rax to indicate number of SSE registers used
   46 # when variadic functions are called. Since there is no way to obtain this
   47 # from Windows, for now, we just assume this is 0 (hence %rax is cleared).
   48 #
   49 # Windows pushes arguments 5 and higher onto stack in case of integer
   50 # variables and 4 and higher in case of floating point variables (passed
   51 # in SSE registers).
   52 
   53 In a windows function, the stackframe/registers look like this:
   54 
   55 # 0x0048 ....
   56 # 0x0040 arg8
   57 # 0x0038 arg7
   58 # 0x0030 arg6
   59 # 0x0028 arg5
   60 # 0x0020 shadow/spill space for arg4
   61 # 0x0018 shadow/spill space for arg3
   62 # 0x0010 shadow/spill space for arg2
   63 # 0x0008 shadow/spill space for arg1
   64 # 0x0000 ret
   65 
   66 # register spill space is same irrespective of number of arguments - even
   67 # if Windows function takes less than 4 arguments, 32 bytes above return
   68 # address is reserved for the function
   69 
   70 In Linux it should look like:
   71 
   72 # 0x0018 ....
   73 # 0x0010 arg8
   74 # 0x0008 arg7
   75 # 0x0000 ret
   76 
   77 */
   78 
   79     .text
   80 
   81 #define LINUX_REG_ARGS 6
   82 #define LOOP_THRESHOLD 9
   83 #define WORD_BYTES 8
   84 
   85 /*
   86  * %rsi and %rdi must be saved because they are not saved by Linux calls, but
   87  * Windows callers expect them to be saved.  %rbp is saved to create a stack
   88  * frame, which can help with debugging.  We need to reserve space for an odd
   89  * number of registers anyway to keep 16-bit alignment of the stack (one more
   90  * position is used by the return address).
   91  */
   92 #define SAVED_REGS 3
   93 
   94 /*
   95  * When calling the Linux function, several registers are saved on the stack.
   96  * When passing more than 6 arguments, arguments starting with argument 7 are
   97  * pushed to the stack as well.
   98  *
   99  * We also need to allocate an additional word on the stack to keep it aligned
  100  * to the 16-bit boundary if the number of saved arguments plus one (for the
  101  * return address) is odd.
  102  */
  103 
  104 /*
  105  * Number of arguments we pass on stack to the Linux function.
  106  * The value of true is -1 in assembler, so we multiply it by another true
  107  * value.
  108  */
  109 #define stack_args(argc)                    \
  110     ((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS))
  111 
  112 /* Full required change of stack pointer, in words */
  113 #define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1)
  114 
  115 /* Full actual change of stack pointer, in words (must be even) */
  116 #define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1)
  117 
  118 /* Space allocated for Linux arguments on stack */
  119 #define stack_space(argc) \
  120     ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES)
  121 
  122 /*
  123  * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of
  124  * total ARGC after the stack has been prepared for the Linux function call.
  125  *
  126  * When called from Windows, the Nth argument is at (N * 8)(%rsp).  We add the
  127  * stack space allocated by the Linux function to compensate for %rsp change.
  128  *
  129  * Don't call with N less than 5!
  130  */
  131 #define win2lin_win_arg(n, argc) \
  132     ((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp)
  133 
  134 /*
  135  * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra
  136  * Linux stack frame.  When more than 6 arguments are used, %rsp points to the
  137  * 7th argument.  The Nth argument is therefore at ((N - 7) * 8)(%rsp).
  138  *
  139  * Don't call with N less than 7!
  140  */
  141 #define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp)
  142 
  143 /* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */
  144 .macro win2linm longname, shortname, argc
  145 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
  146     SYM_FUNC_START(\longname)
  147 #else
  148     .type \longname, @function
  149     ENTRY(\longname)
  150 #endif
  151 
  152     /* Create a call frame - it's optional, but good for debugging */
  153     .cfi_startproc
  154     push %rbp
  155     .cfi_def_cfa %rsp, 2 * WORD_BYTES
  156     .cfi_offset %rbp, -2 * WORD_BYTES
  157     mov %rsp, %rbp
  158     .cfi_def_cfa %rbp, 2 * WORD_BYTES
  159 
  160     /*
  161      * Registers %rdi and %rsi are volatile on Linux, but not on Windows,
  162      * so save them on the stack.
  163      */
  164     push %rsi
  165     push %rdi
  166 
  167     /* Allocate extra stack space for arguments 7 and up */
  168     sub $stack_space(\argc), %rsp
  169 
  170     /*
  171      * Copy arguments 7 and up.  We do it early, before %rdi and %rsi
  172      * are used for arguments 1 and 2, so we don't have to save them.
  173      * We still need to save %rcx if using a string copy.
  174      */
  175     .if (\argc < LOOP_THRESHOLD)
  176         /* If a few arguments, copy them individually through %r11 */
  177         .if (\argc >= 7)
  178             mov win2lin_win_arg(7, \argc), %r11
  179             mov %r11, win2lin_lin_arg(7)
  180         .endif
  181         .if (\argc >= 8)
  182             mov win2lin_win_arg(8, \argc), %r11
  183             mov %r11, win2lin_lin_arg(8)
  184         .endif
  185     .else
  186         /* If there are many arguments, copy them in a loop */
  187         /* Save arg1 to %r11 */
  188         mov %rcx, %r11
  189         /* Source and destination */
  190         lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi
  191         lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi
  192         /* Number of arguments to copy (%ecx zero-extends to %rcx) */
  193         mov $(\argc - LINUX_REG_ARGS), %ecx
  194         rep movsq
  195         /* Restore arg1 directly to %rdi */
  196         mov %r11, %rdi
  197     .endif
  198 
  199     /*
  200      * Argument 1 - %rcx on Windows, %rdi on Linux
  201      * Micro-optimization - if we used loop, arg1 is already in %rdi
  202      */
  203     .if (\argc >= 1) && (\argc < LOOP_THRESHOLD)
  204         mov %rcx, %rdi
  205     .endif
  206 
  207     /* Argument 2 - %rdx on Windows, %rsi on Linux */
  208     .if (\argc >= 2)
  209         mov %rdx, %rsi
  210     .endif
  211 
  212     /* Argument 3 - %r8 on Windows, %rdx on Linux */
  213     .if (\argc >= 3)
  214         mov %r8, %rdx
  215     .endif
  216 
  217     /* Argument 4 - %r9 on Windows, %rcx on Linux */
  218     .if (\argc >= 4)
  219         mov %r9, %rcx
  220     .endif
  221 
  222     /* Argument 5 - first argument on stack on Windows, %r8 Linux */
  223     .if (\argc >= 5)
  224         mov win2lin_win_arg(5, \argc), %r8
  225     .endif
  226 
  227     /* Argument 6 - second argument on stack on Windows, %r9 Linux */
  228     .if (\argc >= 6)
  229         mov win2lin_win_arg(6, \argc), %r9
  230     .endif
  231 
  232     /* %rax on Linux is the number of arguments in SSE registers (zero) */
  233     xor %rax, %rax
  234 
  235     /* Call the function */
  236     call \shortname
  237 
  238     /* Free stack space for arguments 7 and up */
  239     add $stack_space(\argc), %rsp
  240 
  241     /* Restore saved registers */
  242     pop %rdi
  243     pop %rsi
  244 
  245     /* Return to Windows code */
  246     leave
  247     .cfi_def_cfa %rsp, WORD_BYTES
  248     .cfi_restore %rbp
  249     ret
  250     .cfi_endproc
  251 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)
  252     SYM_FUNC_END(\longname)
  253 #else
  254     .size \longname, (. - \longname)
  255 #endif
  256 .endm
  257 
  258 #define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc
  259 
  260 #include "win2lin_stubs.h"
  261 
  262 #endif  /* CONFIG_X86_64 */