~ubuntu-branches/ubuntu/vivid/ndiswrapper/vivid

« back to all changes in this revision

Viewing changes to driver/win2lin_stubs.S

  • Committer: Package Import Robot
  • Author(s): Julian Andres Klode
  • Date: 2012-03-05 16:49:02 UTC
  • mfrom: (1.2.8)
  • Revision ID: package-import@ubuntu.com-20120305164902-rrir76um4yq4eimb
Tags: 1.57-1
* Imported Upstream version 1.57
  - Fixes build with kernel 3.2 (Closes: #655223, LP: #910597)
* Enable hardening build flags (Closes: #655249)
* patches/ndiswrapper-harden.patch: Use $(shell X) instead of `X`
* Update to Policy 3.9.3, copyright-format 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
77
77
 
78
78
        .text
79
79
 
80
 
/*
81
 
 * Registers %rdi and %rsi must be preserved on Windows, but not on Linux.
82
 
 */
83
 
 
84
 
.macro win2lin_prolog
85
 
        push    %rsi
86
 
        push    %rdi
87
 
.endm
88
 
 
89
 
.macro win2lin_epilog
90
 
        pop     %rdi
91
 
        pop     %rsi
92
 
.endm
93
 
 
94
 
/*
95
 
 * Allocate stack frame for Linux arguments.
96
 
 *
97
 
 * First 6 arguments are passed through registers, so we need space for
98
 
 * argument 7 and above.  The arguments should be copied onto stack after
99
 
 * the space has been reserved.
100
 
 */
101
 
 
102
 
.macro reserve_stack argtotal
103
 
        sub $(\argtotal - 6) * 8, %rsp
104
 
        .endm
105
 
 
106
 
.macro free_stack argtotal
107
 
        add $(\argtotal - 6) * 8, %rsp
108
 
        .endm
109
 
 
110
 
/*
111
 
 * Call Linux function.  win2lin macro puts its address to %r10.
112
 
 */
113
 
 
114
 
.macro call_lin_func
115
 
        xor     %rax, %rax      /* number of arguments in SSE registers */
116
 
        call    *%r10
117
 
.endm
118
 
 
119
 
/*
120
 
 * win2lin_win_arg(N, ARGTOTAL) gives the address of the Windows argument
121
 
 * N out of ARGTOTAL after the stack has been prepared for the Linux function
122
 
 * call.
123
 
 *
124
 
 * When calling the Linux function, two registers (%rdi and %rsi) are pushed
125
 
 * to the stack in win2lin_prolog.  When passing more than 6 arguments,
126
 
 * arguments starting with argument 7 are pushed to the stack as well.
127
 
 *
128
 
 * When called from Windows, the Nth argument is at (N * 8)(%rsp).  We add two
129
 
 * 8-byte positions for the saved registers (%rdi and %rsi) and (ARGTOTAL - 6)
130
 
 * for the arguments to be passed on stack to the Linux function.
131
 
 *
132
 
 * If there are 6 and less arguments, ARGTOTAL must be 6.  N must be at least
133
 
 * 5, as arguments 1 to 4 are passed in registers.
134
 
 */
135
 
#define win2lin_win_arg(arg, argtotal) ((arg + 2 + (argtotal - 6)) * 8)(%rsp)
136
 
 
137
 
/*
138
 
 * win2lin_lin_arg(N) gives the address of the Nth linux argument of the extra
139
 
 * linux stack frame.  When more than 6 arguments are used, %rsp points to the
 
80
#define LINUX_REG_ARGS 6
 
81
#define LOOP_THRESHOLD 9
 
82
#define WORD_BYTES 8
 
83
 
 
84
/*
 
85
 * %rsi and %rdi must be saved because they are not saved by Linux calls, but
 
86
 * Windows callers expect them to be saved.  %rbp is saved to create a stack
 
87
 * frame, which can help with debugging.  We need to reserve space for an odd
 
88
 * number of registers anyway to keep 16-bit alignment of the stack (one more
 
89
 * position is used by the return address).
 
90
 */
 
91
#define SAVED_REGS 3
 
92
 
 
93
/*
 
94
 * When calling the Linux function, several registers are saved on the stack.
 
95
 * When passing more than 6 arguments, arguments starting with argument 7 are
 
96
 * pushed to the stack as well.
 
97
 *
 
98
 * We also need to allocate an additional word on the stack to keep it aligned
 
99
 * to the 16-bit boundary if the number of saved arguments plus one (for the
 
100
 * return address) is odd.
 
101
 */
 
102
 
 
103
/*
 
104
 * Number of arguments we pass on stack to the Linux function.
 
105
 * The value of true is -1 in assembler, so we multiply it by another true
 
106
 * value.
 
107
 */
 
108
#define stack_args(argc)                                        \
 
109
        ((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS))
 
110
 
 
111
/* Full required change of stack pointer, in words */
 
112
#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1)
 
113
 
 
114
/* Full actual change of stack pointer, in words (must be even) */
 
115
#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1)
 
116
 
 
117
/* Space allocated for Linux arguments on stack */
 
118
#define stack_space(argc) \
 
119
        ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES)
 
120
 
 
121
/*
 
122
 * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of
 
123
 * total ARGC after the stack has been prepared for the Linux function call.
 
124
 *
 
125
 * When called from Windows, the Nth argument is at (N * 8)(%rsp).  We add the
 
126
 * stack space allocated by the Linux function to compensate for %rsp change.
 
127
 *
 
128
 * Don't call with N less than 5!
 
129
 */
 
130
#define win2lin_win_arg(n, argc) \
 
131
        ((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp)
 
132
 
 
133
/*
 
134
 * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra
 
135
 * Linux stack frame.  When more than 6 arguments are used, %rsp points to the
140
136
 * 7th argument.  The Nth argument is therefore at ((N - 7) * 8)(%rsp).
141
 
 */
142
 
#define win2lin_lin_arg(n) ((n - 7) * 8)(%rsp)
143
 
 
144
 
/* Copy arguments 1 - 4 */
145
 
#define win2lin_arg1 mov %rcx, %rdi
146
 
#define win2lin_arg2 mov %rdx, %rsi
147
 
#define win2lin_arg3 mov %r8, %rdx
148
 
#define win2lin_arg4 mov %r9, %rcx
149
 
 
150
 
/*
151
 
 * Copy arguments 5 - 6.
152
137
 *
153
 
 * Arguments 5 and 6 must be copied after arguments 3 and 4 to prevent
154
 
 * clobbering %r8 and %r9.  win2lin_arg5 and win2lin_arg6 must be used
155
 
 * only between win2lin_prolog and reserving the extra stack space for the
156
 
 * arguments.
157
 
 */
158
 
#define win2lin_arg5 mov win2lin_win_arg(5, 6), %r8
159
 
#define win2lin_arg6 mov win2lin_win_arg(6, 6), %r9
160
 
 
161
 
        .type   win2lin0, @function
162
 
win2lin0:
163
 
        win2lin_prolog
164
 
        call_lin_func
165
 
        win2lin_epilog
166
 
        ret
167
 
        .size   win2lin0, .-win2lin0
168
 
 
169
 
        .type   win2lin1, @function
170
 
win2lin1:
171
 
        win2lin_prolog
172
 
        win2lin_arg1
173
 
        call_lin_func
174
 
        win2lin_epilog
175
 
        ret
176
 
        .size   win2lin1, .-win2lin1
177
 
 
178
 
        .type   win2lin2, @function
179
 
win2lin2:
180
 
        win2lin_prolog
181
 
        win2lin_arg1
182
 
        win2lin_arg2
183
 
        call_lin_func
184
 
        win2lin_epilog
185
 
        ret
186
 
        .size   win2lin2, .-win2lin2
187
 
 
188
 
        .type   win2lin3, @function
189
 
win2lin3:
190
 
        win2lin_prolog
191
 
        win2lin_arg1
192
 
        win2lin_arg2
193
 
        win2lin_arg3
194
 
        call_lin_func
195
 
        win2lin_epilog
196
 
        ret
197
 
        .size   win2lin3, .-win2lin3
198
 
 
199
 
        .type   win2lin4, @function
200
 
win2lin4:
201
 
        win2lin_prolog
202
 
        win2lin_arg1
203
 
        win2lin_arg2
204
 
        win2lin_arg3
205
 
        win2lin_arg4
206
 
        call_lin_func
207
 
        win2lin_epilog
208
 
        ret
209
 
        .size   win2lin4, .-win2lin4
210
 
 
211
 
        .type   win2lin5, @function
212
 
win2lin5:
213
 
        win2lin_prolog
214
 
        win2lin_arg1
215
 
        win2lin_arg2
216
 
        win2lin_arg3
217
 
        win2lin_arg4
218
 
        win2lin_arg5
219
 
        call_lin_func
220
 
        win2lin_epilog
221
 
        ret
222
 
        .size   win2lin5, .-win2lin5
223
 
 
224
 
        .type   win2lin6, @function
225
 
win2lin6:
226
 
        win2lin_prolog
227
 
        win2lin_arg1
228
 
        win2lin_arg2
229
 
        win2lin_arg3
230
 
        win2lin_arg4
231
 
        win2lin_arg5
232
 
        win2lin_arg6
233
 
        call_lin_func
234
 
        win2lin_epilog
235
 
        ret
236
 
        .size   win2lin6, .-win2lin6
237
 
 
238
 
        .type   win2lin7, @function
239
 
win2lin7:
240
 
        win2lin_prolog
241
 
 
242
 
        win2lin_arg1
243
 
        win2lin_arg2
244
 
        win2lin_arg3
245
 
        win2lin_arg4
246
 
        win2lin_arg5
247
 
        win2lin_arg6
248
 
 
249
 
        reserve_stack(7)
250
 
 
251
 
        /* Copy Windows argument 7 onto stack for the Linux function */
252
 
        mov     win2lin_win_arg(7, 7), %r11
253
 
        mov     %r11, win2lin_lin_arg(7)
254
 
 
255
 
        call_lin_func
256
 
 
257
 
        free_stack(7)
258
 
 
259
 
        win2lin_epilog
260
 
        ret
261
 
        .size   win2lin7, .-win2lin7
262
 
 
263
 
        .type   win2lin8, @function
264
 
win2lin8:
265
 
        win2lin_prolog
266
 
 
267
 
        win2lin_arg1
268
 
        win2lin_arg2
269
 
        win2lin_arg3
270
 
        win2lin_arg4
271
 
        win2lin_arg5
272
 
        win2lin_arg6
273
 
 
274
 
        reserve_stack(8)
275
 
 
276
 
        /* Copy Windows arguments 7 and 8 onto stack for the Linux function */
277
 
        mov     win2lin_win_arg(7,8), %r11
278
 
        mov     %r11, win2lin_lin_arg(7)
279
 
        mov     win2lin_win_arg(8,8), %r11
280
 
        mov     %r11, win2lin_lin_arg(8)
281
 
 
282
 
        call_lin_func
283
 
 
284
 
        free_stack(8)
285
 
 
286
 
        win2lin_epilog
287
 
        ret
288
 
        .size   win2lin8, .-win2lin8
289
 
 
290
 
/*
291
 
 * We assume here that we never need to handle more than 12 arguments.
292
 
 * Copy 12 arguments even if we need less.
293
 
 */
294
 
        .type   win2lin9, @function
295
 
win2lin9:
296
 
win2lin10:
297
 
win2lin11:
298
 
win2lin12:
299
 
        win2lin_prolog
300
 
 
301
 
        reserve_stack(12)
302
 
 
303
 
        /* Copy Windows arguments 7 through 12 onto stack */
304
 
        mov     %rcx, %r11                      /* save %rcx */
305
 
        lea     win2lin_win_arg(7, 12), %rsi    /* source */
306
 
        lea     win2lin_lin_arg(7), %rdi        /* destination */
307
 
        mov     $6, %rcx                        /* 6 arguments */
308
 
        rep
309
 
        movsq
310
 
        mov     %r11, %rcx                      /* restore %rcx */
311
 
 
312
 
        /* Copy arguments 1 - 4 */
313
 
        win2lin_arg1
314
 
        win2lin_arg2
315
 
        win2lin_arg3
316
 
        win2lin_arg4
317
 
 
318
 
        /*
319
 
         * Copy arguments 5 and 6. Cannot use win2lin_arg5 and win2lin_arg6
320
 
         * after reserve_stack.
321
 
         */
322
 
        mov win2lin_win_arg(5, 12), %r8
323
 
        mov win2lin_win_arg(6, 12), %r9
324
 
 
325
 
        call_lin_func
326
 
 
327
 
        free_stack(12)
328
 
 
329
 
        win2lin_epilog
330
 
        ret
331
 
        .size   win2lin9, .-win2lin9
332
 
 
333
 
#define win2lin(name, argc)                     \
334
 
ENTRY(win2lin_ ## name ## _ ## argc)            \
335
 
        lea     name(%rip), %r10 ;              \
336
 
        jmp     win2lin ## argc
 
138
 * Don't call with N less than 7!
 
139
 */
 
140
#define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp)
 
141
 
 
142
/* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */
 
143
.macro win2linm longname, shortname, argc
 
144
        .type \longname, @function
 
145
        ENTRY(\longname)
 
146
 
 
147
        /* Create a call frame - it's optional, but good for debugging */
 
148
        .cfi_startproc
 
149
        push %rbp
 
150
        .cfi_def_cfa %rsp, 2 * WORD_BYTES
 
151
        .cfi_offset %rbp, -2 * WORD_BYTES
 
152
        mov %rsp, %rbp
 
153
        .cfi_def_cfa %rbp, 2 * WORD_BYTES
 
154
 
 
155
        /*
 
156
         * Registers %rdi and %rsi are volatile on Linux, but not on Windows,
 
157
         * so save them on the stack.
 
158
         */
 
159
        push %rsi
 
160
        push %rdi
 
161
 
 
162
        /* Allocate extra stack space for arguments 7 and up */
 
163
        sub $stack_space(\argc), %rsp
 
164
 
 
165
        /*
 
166
         * Copy arguments 7 and up.  We do it early, before %rdi and %rsi
 
167
         * are used for arguments 1 and 2, so we don't have to save them.
 
168
         * We still need to save %rcx if using a string copy.
 
169
         */
 
170
        .if (\argc < LOOP_THRESHOLD)
 
171
                /* If a few arguments, copy them individually through %r11 */
 
172
                .if (\argc >= 7)
 
173
                        mov win2lin_win_arg(7, \argc), %r11
 
174
                        mov %r11, win2lin_lin_arg(7)
 
175
                .endif
 
176
                .if (\argc >= 8)
 
177
                        mov win2lin_win_arg(8, \argc), %r11
 
178
                        mov %r11, win2lin_lin_arg(8)
 
179
                .endif
 
180
        .else
 
181
                /* If there are many arguments, copy them in a loop */
 
182
                /* Save arg1 to %r11 */
 
183
                mov %rcx, %r11
 
184
                /* Source and destination */
 
185
                lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi
 
186
                lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi
 
187
                /* Number of arguments to copy (%ecx zero-extends to %rcx) */
 
188
                mov $(\argc - LINUX_REG_ARGS), %ecx
 
189
                rep movsq
 
190
                /* Restore arg1 directly to %rdi */
 
191
                mov %r11, %rdi
 
192
        .endif
 
193
 
 
194
        /*
 
195
         * Argument 1 - %rcx on Windows, %rdi on Linux
 
196
         * Micro-optimization - if we used loop, arg1 is already in %rdi
 
197
         */
 
198
        .if (\argc >= 1) && (\argc < LOOP_THRESHOLD)
 
199
                mov %rcx, %rdi
 
200
        .endif
 
201
 
 
202
        /* Argument 2 - %rdx on Windows, %rsi on Linux */
 
203
        .if (\argc >= 2)
 
204
                mov %rdx, %rsi
 
205
        .endif
 
206
 
 
207
        /* Argument 3 - %r8 on Windows, %rdx on Linux */
 
208
        .if (\argc >= 3)
 
209
                mov %r8, %rdx
 
210
        .endif
 
211
 
 
212
        /* Argument 4 - %r9 on Windows, %rcx on Linux */
 
213
        .if (\argc >= 4)
 
214
                mov %r9, %rcx
 
215
        .endif
 
216
 
 
217
        /* Argument 5 - first argument on stack on Windows, %r8 Linux */
 
218
        .if (\argc >= 5)
 
219
                mov win2lin_win_arg(5, \argc), %r8
 
220
        .endif
 
221
 
 
222
        /* Argument 6 - second argument on stack on Windows, %r9 Linux */
 
223
        .if (\argc >= 6)
 
224
                mov win2lin_win_arg(6, \argc), %r9
 
225
        .endif
 
226
 
 
227
        /* %rax on Linux is the number of arguments in SSE registers (zero) */
 
228
        xor %rax, %rax
 
229
 
 
230
        /* Call the function */
 
231
        call \shortname
 
232
 
 
233
        /* Free stack space for arguments 7 and up */
 
234
        add $stack_space(\argc), %rsp
 
235
 
 
236
        /* Restore saved registers */
 
237
        pop %rdi
 
238
        pop %rsi
 
239
 
 
240
        /* Return to Windows code */
 
241
        leave
 
242
        .cfi_def_cfa %rsp, WORD_BYTES
 
243
        .cfi_restore %rbp
 
244
        ret
 
245
        .cfi_endproc
 
246
        .size \longname, (. - \longname)
 
247
.endm
 
248
 
 
249
#define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc
337
250
 
338
251
#include "win2lin_stubs.h"
339
252