~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to kernel/arch/ia32/src/asm.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) 2001-2004 Jakub Jermar
 
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
## very low and hardware-level functions
 
30
 
 
31
# Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int has no error
 
32
# word and 1 means interrupt with error word
 
33
#define ERROR_WORD_INTERRUPT_LIST 0x00027d00
 
34
 
 
35
.text
 
36
 
 
37
.global paging_on
 
38
.global enable_l_apic_in_msr
 
39
.global interrupt_handlers
 
40
.global memsetb
 
41
.global memsetw
 
42
.global memcpy
 
43
.global memcpy_from_uspace
 
44
.global memcpy_from_uspace_failover_address
 
45
.global memcpy_to_uspace
 
46
.global memcpy_to_uspace_failover_address
 
47
 
 
48
 
 
49
# Wrapper for generic memsetb
 
50
memsetb:
 
51
        jmp _memsetb
 
52
 
 
53
# Wrapper for generic memsetw
 
54
memsetw:
 
55
        jmp _memsetw
 
56
 
 
57
 
 
58
#define MEMCPY_DST      4
 
59
#define MEMCPY_SRC      8
 
60
#define MEMCPY_SIZE     12
 
61
 
 
62
/** Copy memory to/from userspace.
 
63
 *
 
64
 * This is almost conventional memcpy().
 
65
 * The difference is that there is a failover part
 
66
 * to where control is returned from a page fault
 
67
 * if the page fault occurs during copy_from_uspace()
 
68
 * or copy_to_uspace().
 
69
 *
 
70
 * @param MEMCPY_DST(%esp)      Destination address.
 
71
 * @param MEMCPY_SRC(%esp)      Source address.
 
72
 * @param MEMCPY_SIZE(%esp)     Size.
 
73
 *
 
74
 * @return MEMCPY_DST(%esp) on success and 0 on failure.
 
75
 */
 
76
memcpy:
 
77
memcpy_from_uspace:
 
78
memcpy_to_uspace:
 
79
        movl %edi, %edx                 /* save %edi */
 
80
        movl %esi, %eax                 /* save %esi */
 
81
        
 
82
        movl MEMCPY_SIZE(%esp), %ecx
 
83
        shrl $2, %ecx                   /* size / 4 */
 
84
        
 
85
        movl MEMCPY_DST(%esp), %edi
 
86
        movl MEMCPY_SRC(%esp), %esi
 
87
        
 
88
        rep movsl                       /* copy whole words */
 
89
 
 
90
        movl MEMCPY_SIZE(%esp), %ecx
 
91
        andl $3, %ecx                   /* size % 4 */
 
92
        jz 0f
 
93
        
 
94
        rep movsb                       /* copy the rest byte by byte */
 
95
 
 
96
0:
 
97
        movl %edx, %edi
 
98
        movl %eax, %esi
 
99
        movl MEMCPY_DST(%esp), %eax     /* MEMCPY_DST(%esp), success */
 
100
        ret
 
101
        
 
102
/*
 
103
 * We got here from as_page_fault() after the memory operations
 
104
 * above had caused a page fault.
 
105
 */
 
106
memcpy_from_uspace_failover_address:
 
107
memcpy_to_uspace_failover_address:
 
108
        movl %edx, %edi
 
109
        movl %eax, %esi
 
110
        xorl %eax, %eax                 /* return 0, failure */
 
111
        ret
 
112
 
 
113
## Turn paging on
 
114
#
 
115
# Enable paging and write-back caching in CR0.
 
116
#
 
117
paging_on:
 
118
        movl %cr0, %edx
 
119
        orl $(1 << 31), %edx            # paging on
 
120
        # clear Cache Disable and not Write Though
 
121
        andl $~((1 << 30) | (1 << 29)), %edx
 
122
        movl %edx,%cr0
 
123
        jmp 0f
 
124
0:
 
125
        ret
 
126
 
 
127
 
 
128
## Enable local APIC
 
129
#
 
130
# Enable local APIC in MSR.
 
131
#
 
132
enable_l_apic_in_msr:
 
133
        movl $0x1b, %ecx
 
134
        rdmsr
 
135
        orl $(1 << 11), %eax
 
136
        orl $(0xfee00000), %eax
 
137
        wrmsr
 
138
        ret
 
139
 
 
140
# Clear nested flag
 
141
# overwrites %ecx
 
142
.macro CLEAR_NT_FLAG
 
143
        pushfl
 
144
        pop %ecx
 
145
        and $0xffffbfff, %ecx
 
146
        push %ecx
 
147
        popfl
 
148
.endm   
 
149
 
 
150
/*
 
151
 * The SYSENTER syscall mechanism can be used for syscalls with
 
152
 * four or fewer arguments. To pass these four arguments, we
 
153
 * use four registers: EDX, ECX, EBX, ESI. The syscall number
 
154
 * is passed in EAX. We use EDI to remember the return address
 
155
 * and EBP to remember the stack. The INT-based syscall mechanism
 
156
 * can actually handle six arguments plus the syscall number
 
157
 * entirely in registers.
 
158
 */
 
159
.global sysenter_handler
 
160
sysenter_handler:
 
161
        sti
 
162
        pushl %ebp      # remember user stack
 
163
        pushl %edi      # remember return user address
 
164
 
 
165
        pushl %gs       # remember TLS
 
166
 
 
167
        pushl %eax      # syscall number
 
168
        subl $8, %esp   # unused sixth and fifth argument
 
169
        pushl %esi      # fourth argument
 
170
        pushl %ebx      # third argument
 
171
        pushl %ecx      # second argument
 
172
        pushl %edx      # first argument
 
173
 
 
174
        movw $16, %ax
 
175
        movw %ax, %ds
 
176
        movw %ax, %es
 
177
 
 
178
        cld
 
179
        call syscall_handler
 
180
        addl $28, %esp  # remove arguments from stack
 
181
 
 
182
        pop %gs         # restore TLS
 
183
 
 
184
        pop %edx        # prepare return EIP for SYSEXIT
 
185
        pop %ecx        # prepare userspace ESP for SYSEXIT
 
186
 
 
187
        sysexit         # return to userspace
 
188
 
 
189
 
 
190
## Declare interrupt handlers
 
191
#
 
192
# Declare interrupt handlers for n interrupt
 
193
# vectors starting at vector i.
 
194
#
 
195
# The handlers setup data segment registers
 
196
# and call exc_dispatch().
 
197
#
 
198
#define INTERRUPT_ALIGN 64
 
199
.macro handler i n
 
200
 
 
201
.ifeq \i - 0x30     # Syscall handler
 
202
        pushl %ds
 
203
        pushl %es
 
204
        pushl %fs
 
205
        pushl %gs
 
206
 
 
207
        #
 
208
        # Push syscall arguments onto the stack
 
209
        #
 
210
        # NOTE: The idea behind the order of arguments passed in registers is to
 
211
        #       use all scratch registers first and preserved registers next.
 
212
        #       An optimized libc syscall wrapper can make use of this setup.
 
213
        #
 
214
        pushl %eax
 
215
        pushl %ebp
 
216
        pushl %edi
 
217
        pushl %esi
 
218
        pushl %ebx
 
219
        pushl %ecx
 
220
        pushl %edx
 
221
        
 
222
        # we must fill the data segment registers
 
223
        movw $16, %ax
 
224
        movw %ax, %ds
 
225
        movw %ax, %es
 
226
        
 
227
        cld
 
228
        sti
 
229
        # syscall_handler(edx, ecx, ebx, esi, edi, ebp, eax)
 
230
        call syscall_handler   
 
231
        cli
 
232
        addl $28, %esp         # clean-up of parameters
 
233
        
 
234
        popl %gs
 
235
        popl %fs
 
236
        popl %es
 
237
        popl %ds
 
238
        
 
239
        CLEAR_NT_FLAG
 
240
        iret
 
241
.else   
 
242
        /*
 
243
         * This macro distinguishes between two versions of ia32 exceptions.
 
244
         * One version has error word and the other does not have it.
 
245
         * The latter version fakes the error word on the stack so that the
 
246
         * handlers and istate_t can be the same for both types.
 
247
         */
 
248
        .iflt \i - 32
 
249
                .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
 
250
                        /* 
 
251
                         * With error word, do nothing
 
252
                         */
 
253
                .else
 
254
                        /*
 
255
                         * Version without error word,
 
256
                         */
 
257
                        subl $4, %esp
 
258
                .endif
 
259
        .else
 
260
                /*
 
261
                 * Version without error word,
 
262
                 */
 
263
                subl $4, %esp
 
264
        .endif
 
265
        
 
266
        pushl %ds
 
267
        pushl %es
 
268
        pushl %fs
 
269
        pushl %gs
 
270
 
 
271
        pushl %edx
 
272
        pushl %ecx
 
273
        pushl %eax
 
274
        
 
275
        # we must fill the data segment registers
 
276
        movw $16, %ax
 
277
        movw %ax, %ds
 
278
        movw %ax, %es
 
279
 
 
280
        cld
 
281
 
 
282
        pushl %esp          # *istate
 
283
        pushl $(\i)         # intnum
 
284
        call exc_dispatch   # excdispatch(intnum, *istate)
 
285
        addl $8, %esp       # Clear arguments from stack
 
286
 
 
287
        CLEAR_NT_FLAG # Modifies %ecx
 
288
        
 
289
        popl %eax
 
290
        popl %ecx
 
291
        popl %edx
 
292
        
 
293
        popl %gs
 
294
        popl %fs
 
295
        popl %es
 
296
        popl %ds
 
297
 
 
298
        addl $4, %esp   # Skip error word, no matter whether real or fake.
 
299
        iret
 
300
.endif
 
301
 
 
302
        .align INTERRUPT_ALIGN
 
303
        .if (\n- \i) - 1
 
304
        handler "(\i + 1)", \n
 
305
        .endif
 
306
.endm
 
307
 
 
308
# keep in sync with pm.h !!!
 
309
IDT_ITEMS = 64
 
310
.align INTERRUPT_ALIGN
 
311
interrupt_handlers:
 
312
h_start:
 
313
        handler 0 IDT_ITEMS
 
314
h_end:
 
315
 
 
316
.data
 
317
.global interrupt_handler_size
 
318
 
 
319
interrupt_handler_size: .long (h_end - h_start) / IDT_ITEMS