~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to kernel/arch/amd64/src/asm_utils.S

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright (c) 2005 Ondrej Palkovsky
 
3
# All rights reserved.
 
4
#
 
5
# Redistribution and use in source and binary forms, with or without
 
6
# modification, are permitted provided that the following conditions
 
7
# are met:
 
8
#
 
9
# - Redistributions of source code must retain the above copyright
 
10
#   notice, this list of conditions and the following disclaimer.
 
11
# - Redistributions in binary form must reproduce the above copyright
 
12
#   notice, this list of conditions and the following disclaimer in the
 
13
#   documentation and/or other materials provided with the distribution.
 
14
# - The name of the author may not be used to endorse or promote products
 
15
#   derived from this software without specific prior written permission.
 
16
#
 
17
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
#
 
28
 
 
29
#define IREGISTER_SPACE 72 
 
30
 
 
31
#define IOFFSET_RAX     0x0
 
32
#define IOFFSET_RCX     0x8
 
33
#define IOFFSET_RDX     0x10
 
34
#define IOFFSET_RSI     0x18
 
35
#define IOFFSET_RDI     0x20
 
36
#define IOFFSET_R8      0x28
 
37
#define IOFFSET_R9      0x30
 
38
#define IOFFSET_R10     0x38
 
39
#define IOFFSET_R11     0x40
 
40
 
 
41
#  Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int has no error word
 
42
# and 1 means interrupt with error word
 
43
#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
 
44
 
 
45
#include <arch/pm.h>
 
46
#include <arch/mm/page.h>
 
47
        
 
48
.text
 
49
.global interrupt_handlers
 
50
.global syscall_entry
 
51
.global panic_printf
 
52
 
 
53
panic_printf:
 
54
        movq $halt, (%rsp)
 
55
        jmp printf
 
56
 
 
57
.global cpuid
 
58
.global has_cpuid
 
59
.global get_cycle
 
60
.global read_efer_flag
 
61
.global set_efer_flag
 
62
.global memsetb
 
63
.global memsetw
 
64
.global memcpy
 
65
.global memcpy_from_uspace
 
66
.global memcpy_to_uspace
 
67
.global memcpy_from_uspace_failover_address
 
68
.global memcpy_to_uspace_failover_address
 
69
 
 
70
# Wrapper for generic memsetb
 
71
memsetb:
 
72
        jmp _memsetb
 
73
 
 
74
# Wrapper for generic memsetw
 
75
memsetw:
 
76
        jmp _memsetw
 
77
 
 
78
#define MEMCPY_DST      %rdi
 
79
#define MEMCPY_SRC      %rsi
 
80
#define MEMCPY_SIZE     %rdx
 
81
 
 
82
/**
 
83
 * Copy memory from/to userspace.
 
84
 *
 
85
 * This is almost conventional memcpy().
 
86
 * The difference is that there is a failover part
 
87
 * to where control is returned from a page fault if
 
88
 * the page fault occurs during copy_from_uspace()
 
89
 * or copy_to_uspace().
 
90
 *
 
91
 * @param MEMCPY_DST    Destination address.
 
92
 * @param MEMCPY_SRC    Source address.
 
93
 * @param MEMCPY_SIZE   Number of bytes to copy.
 
94
 *
 
95
 * @retrun MEMCPY_DST on success, 0 on failure.
 
96
 */
 
97
memcpy:
 
98
memcpy_from_uspace:
 
99
memcpy_to_uspace:
 
100
        movq MEMCPY_DST, %rax
 
101
 
 
102
        movq MEMCPY_SIZE, %rcx
 
103
        shrq $3, %rcx                   /* size / 8 */
 
104
        
 
105
        rep movsq                       /* copy as much as possible word by word */
 
106
 
 
107
        movq MEMCPY_SIZE, %rcx
 
108
        andq $7, %rcx                   /* size % 8 */
 
109
        jz 0f
 
110
        
 
111
        rep movsb                       /* copy the rest byte by byte */
 
112
        
 
113
0:
 
114
        ret                             /* return MEMCPY_SRC, success */
 
115
 
 
116
memcpy_from_uspace_failover_address:
 
117
memcpy_to_uspace_failover_address:
 
118
        xorq %rax, %rax                 /* return 0, failure */
 
119
        ret
 
120
 
 
121
## Determine CPUID support
 
122
#
 
123
# Return 0 in EAX if CPUID is not support, 1 if supported.
 
124
#
 
125
has_cpuid:
 
126
        pushfq                  # store flags
 
127
        popq %rax               # read flags
 
128
        movq %rax,%rdx          # copy flags
 
129
        btcl $21,%edx           # swap the ID bit
 
130
        pushq %rdx
 
131
        popfq                   # propagate the change into flags
 
132
        pushfq
 
133
        popq %rdx               # read flags    
 
134
        andl $(1<<21),%eax      # interested only in ID bit
 
135
        andl $(1<<21),%edx
 
136
        xorl %edx,%eax          # 0 if not supported, 1 if supported
 
137
        ret
 
138
 
 
139
cpuid:
 
140
        movq %rbx, %r10  # we have to preserve rbx across function calls
 
141
 
 
142
        movl %edi,%eax  # load the command into %eax
 
143
 
 
144
        cpuid   
 
145
        movl %eax,0(%rsi)
 
146
        movl %ebx,4(%rsi)
 
147
        movl %ecx,8(%rsi)
 
148
        movl %edx,12(%rsi)
 
149
 
 
150
        movq %r10, %rbx
 
151
        ret
 
152
 
 
153
get_cycle:
 
154
        xorq %rax,%rax
 
155
        rdtsc
 
156
        ret
 
157
 
 
158
set_efer_flag:
 
159
        movq $0xc0000080, %rcx
 
160
        rdmsr
 
161
        btsl %edi, %eax
 
162
        wrmsr
 
163
        ret
 
164
        
 
165
read_efer_flag: 
 
166
        movq $0xc0000080, %rcx
 
167
        rdmsr
 
168
        ret             
 
169
 
 
170
# Push all volatile general purpose registers on stack
 
171
.macro save_all_gpr
 
172
        movq %rax, IOFFSET_RAX(%rsp)
 
173
        movq %rcx, IOFFSET_RCX(%rsp)
 
174
        movq %rdx, IOFFSET_RDX(%rsp)
 
175
        movq %rsi, IOFFSET_RSI(%rsp)
 
176
        movq %rdi, IOFFSET_RDI(%rsp)
 
177
        movq %r8, IOFFSET_R8(%rsp)
 
178
        movq %r9, IOFFSET_R9(%rsp)
 
179
        movq %r10, IOFFSET_R10(%rsp)
 
180
        movq %r11, IOFFSET_R11(%rsp)
 
181
.endm
 
182
 
 
183
.macro restore_all_gpr
 
184
        movq IOFFSET_RAX(%rsp), %rax
 
185
        movq IOFFSET_RCX(%rsp), %rcx
 
186
        movq IOFFSET_RDX(%rsp), %rdx
 
187
        movq IOFFSET_RSI(%rsp), %rsi
 
188
        movq IOFFSET_RDI(%rsp), %rdi
 
189
        movq IOFFSET_R8(%rsp), %r8
 
190
        movq IOFFSET_R9(%rsp), %r9
 
191
        movq IOFFSET_R10(%rsp), %r10
 
192
        movq IOFFSET_R11(%rsp), %r11
 
193
.endm
 
194
 
 
195
#define INTERRUPT_ALIGN 128
 
196
        
 
197
## Declare interrupt handlers
 
198
#
 
199
# Declare interrupt handlers for n interrupt
 
200
# vectors starting at vector i.
 
201
#
 
202
# The handlers call exc_dispatch().
 
203
#
 
204
.macro handler i n
 
205
 
 
206
        /*
 
207
         * Choose between version with error code and version without error
 
208
         * code. Both versions have to be of the same size. amd64 assembly is,
 
209
         * however, a little bit tricky. For instance, subq $0x80, %rsp and
 
210
         * subq $0x78, %rsp can result in two instructions with different
 
211
         * op-code lengths.
 
212
         * Therefore we align the interrupt handlers.
 
213
         */
 
214
 
 
215
        .iflt \i-32
 
216
                .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
 
217
                        /*
 
218
                         * Version with error word.
 
219
                         */
 
220
                        subq $IREGISTER_SPACE, %rsp
 
221
                .else
 
222
                        /*
 
223
                         * Version without error word,
 
224
                         */
 
225
                        subq $(IREGISTER_SPACE+8), %rsp
 
226
                .endif
 
227
        .else
 
228
                /*
 
229
                 * Version without error word,
 
230
                 */
 
231
                subq $(IREGISTER_SPACE+8), %rsp
 
232
        .endif  
 
233
 
 
234
        save_all_gpr
 
235
        cld
 
236
 
 
237
        movq $(\i), %rdi        # %rdi - first parameter
 
238
        movq %rsp, %rsi         # %rsi - pointer to istate
 
239
        call exc_dispatch       # exc_dispatch(i, istate)
 
240
        
 
241
        restore_all_gpr
 
242
        # $8 = Skip error word
 
243
        addq $(IREGISTER_SPACE+8), %rsp
 
244
        iretq
 
245
 
 
246
        .align INTERRUPT_ALIGN
 
247
        .if (\n-\i)-1
 
248
        handler "(\i+1)",\n
 
249
        .endif
 
250
.endm
 
251
 
 
252
.align INTERRUPT_ALIGN
 
253
interrupt_handlers:
 
254
h_start:
 
255
        handler 0 IDT_ITEMS
 
256
h_end:
 
257
 
 
258
## Low-level syscall handler
 
259
 
260
# Registers on entry:
 
261
#
 
262
# @param rcx            Userspace return address.
 
263
# @param r11            Userspace RLFAGS.
 
264
#
 
265
# @param rax            Syscall number.
 
266
# @param rdi            1st syscall argument.
 
267
# @param rsi            2nd syscall argument.
 
268
# @param rdx            3rd syscall argument.
 
269
# @param r10            4th syscall argument. Used instead of RCX because the
 
270
#                       SYSCALL instruction clobbers it.
 
271
# @param r8             5th syscall argument.
 
272
# @param r9             6th syscall argument.
 
273
#
 
274
# @return               Return value is in rax.
 
275
#
 
276
syscall_entry:
 
277
        swapgs                  # Switch to hidden gs   
 
278
        # 
 
279
        # %gs:0                 Scratch space for this thread's user RSP
 
280
        # %gs:8                 Address to be used as this thread's kernel RSP
 
281
        #
 
282
        movq %rsp, %gs:0        # Save this thread's user RSP
 
283
        movq %gs:8, %rsp        # Set this thread's kernel RSP
 
284
        swapgs                  # Switch back to remain consistent
 
285
        sti
 
286
        
 
287
        pushq %rcx
 
288
        pushq %r11
 
289
 
 
290
        movq %r10, %rcx         # Copy the 4th argument where it is expected 
 
291
        pushq %rax
 
292
        call syscall_handler
 
293
        addq $8, %rsp
 
294
                
 
295
        popq %r11
 
296
        popq %rcx
 
297
 
 
298
        cli
 
299
        swapgs
 
300
        movq %gs:0, %rsp        # Restore the user RSP
 
301
        swapgs
 
302
 
 
303
        sysretq
 
304
 
 
305
.data
 
306
.global interrupt_handler_size
 
307
 
 
308
interrupt_handler_size: .quad (h_end-h_start)/IDT_ITEMS