source: mainline/kernel/arch/amd64/src/asm_utils.S@ 8ccd2ea

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8ccd2ea was 296426ad, checked in by Jakub Jermar <jakub@…>, 18 years ago

Support for 6 syscalls arguments on amd64.

  • Property mode set to 100644
File size: 7.6 KB
RevLine 
[e3b9572]1#
[df4ed85]2# Copyright (c) 2005 Ondrej Palkovsky
[e3b9572]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
[8e0eb63]29#define IREGISTER_SPACE 120
30
31#define IOFFSET_RAX 0x0
32#define IOFFSET_RBX 0x8
33#define IOFFSET_RCX 0x10
34#define IOFFSET_RDX 0x18
35#define IOFFSET_RSI 0x20
36#define IOFFSET_RDI 0x28
37#define IOFFSET_R8 0x30
38#define IOFFSET_R9 0x38
39#define IOFFSET_R10 0x40
40#define IOFFSET_R11 0x48
41#define IOFFSET_R12 0x50
42#define IOFFSET_R13 0x58
43#define IOFFSET_R14 0x60
44#define IOFFSET_R15 0x68
45#define IOFFSET_RBP 0x70
[e3b9572]46
47# Mask for interrupts 0 - 31 (bits 0 - 31) where 0 means that int has no error word
48# and 1 means interrupt with error word
49#define ERROR_WORD_INTERRUPT_LIST 0x00027D00
50
51#include <arch/pm.h>
[fa2d382]52#include <arch/mm/page.h>
[e3b9572]53
54.text
55.global interrupt_handlers
[dd4d6b0]56.global syscall_entry
[e3b9572]57.global panic_printf
58
59panic_printf:
60 movq $halt, (%rsp)
61 jmp printf
62
[36b209a]63.global cpuid
[7df54df]64.global has_cpuid
[134877d]65.global get_cycle
[89344d85]66.global read_efer_flag
67.global set_efer_flag
[e3c762cd]68.global memcpy
69.global memcpy_from_uspace
70.global memcpy_to_uspace
71.global memcpy_from_uspace_failover_address
72.global memcpy_to_uspace_failover_address
73
74#define MEMCPY_DST %rdi
75#define MEMCPY_SRC %rsi
76#define MEMCPY_SIZE %rdx
77
78/**
79 * Copy memory from/to userspace.
80 *
81 * This is almost conventional memcpy().
82 * The difference is that there is a failover part
83 * to where control is returned from a page fault if
84 * the page fault occurs during copy_from_uspace()
85 * or copy_to_uspace().
86 *
87 * @param MEMCPY_DST Destination address.
88 * @param MEMCPY_SRC Source address.
89 * @param MEMCPY_SIZE Number of bytes to copy.
90 *
91 * @retrun MEMCPY_SRC on success, 0 on failure.
92 */
93memcpy:
94memcpy_from_uspace:
95memcpy_to_uspace:
96 movq MEMCPY_SRC, %rax
97
98 movq MEMCPY_SIZE, %rcx
99 shrq $3, %rcx /* size / 8 */
100
101 rep movsq /* copy as much as possible word by word */
102
103 movq MEMCPY_SIZE, %rcx
104 andq $7, %rcx /* size % 8 */
105 jz 0f
106
107 rep movsb /* copy the rest byte by byte */
[89344d85]108
[e3c762cd]1090:
110 ret /* return MEMCPY_SRC, success */
111
112memcpy_from_uspace_failover_address:
113memcpy_to_uspace_failover_address:
114 xorq %rax, %rax /* return 0, failure */
115 ret
116
[7df54df]117## Determine CPUID support
118#
119# Return 0 in EAX if CPUID is not support, 1 if supported.
120#
121has_cpuid:
122 pushfq # store flags
123 popq %rax # read flags
[d6dcdd2e]124 movq %rax,%rdx # copy flags
125 btcl $21,%edx # swap the ID bit
126 pushq %rdx
[7df54df]127 popfq # propagate the change into flags
128 pushfq
[d6dcdd2e]129 popq %rdx # read flags
[7df54df]130 andl $(1<<21),%eax # interested only in ID bit
[d6dcdd2e]131 andl $(1<<21),%edx
132 xorl %edx,%eax # 0 if not supported, 1 if supported
[7df54df]133 ret
134
[89344d85]135cpuid:
136 movq %rbx, %r10 # we have to preserve rbx across function calls
137
138 movl %edi,%eax # load the command into %eax
139
140 cpuid
141 movl %eax,0(%rsi)
142 movl %ebx,4(%rsi)
143 movl %ecx,8(%rsi)
144 movl %edx,12(%rsi)
145
146 movq %r10, %rbx
147 ret
[7df54df]148
[134877d]149get_cycle:
[7df54df]150 xorq %rax,%rax
151 rdtsc
152 ret
[89344d85]153
154set_efer_flag:
155 movq $0xc0000080, %rcx
156 rdmsr
157 btsl %edi, %eax
158 wrmsr
159 ret
[7df54df]160
[89344d85]161read_efer_flag:
162 movq $0xc0000080, %rcx
163 rdmsr
164 ret
[7df54df]165
[e3b9572]166# Push all general purpose registers on stack except %rbp, %rsp
[49a39c2]167.macro save_all_gpr
168 movq %rax, IOFFSET_RAX(%rsp)
169 movq %rcx, IOFFSET_RCX(%rsp)
170 movq %rdx, IOFFSET_RDX(%rsp)
171 movq %rsi, IOFFSET_RSI(%rsp)
172 movq %rdi, IOFFSET_RDI(%rsp)
173 movq %r8, IOFFSET_R8(%rsp)
174 movq %r9, IOFFSET_R9(%rsp)
175 movq %r10, IOFFSET_R10(%rsp)
176 movq %r11, IOFFSET_R11(%rsp)
[8d25b44]177#ifdef CONFIG_DEBUG_ALLREGS
178 movq %rbx, IOFFSET_RBX(%rsp)
179 movq %rbp, IOFFSET_RBP(%rsp)
[49a39c2]180 movq %r12, IOFFSET_R12(%rsp)
181 movq %r13, IOFFSET_R13(%rsp)
182 movq %r14, IOFFSET_R14(%rsp)
183 movq %r15, IOFFSET_R15(%rsp)
[8d25b44]184#endif
[e3b9572]185.endm
186
[49a39c2]187.macro restore_all_gpr
188 movq IOFFSET_RAX(%rsp), %rax
189 movq IOFFSET_RCX(%rsp), %rcx
190 movq IOFFSET_RDX(%rsp), %rdx
191 movq IOFFSET_RSI(%rsp), %rsi
192 movq IOFFSET_RDI(%rsp), %rdi
193 movq IOFFSET_R8(%rsp), %r8
194 movq IOFFSET_R9(%rsp), %r9
195 movq IOFFSET_R10(%rsp), %r10
196 movq IOFFSET_R11(%rsp), %r11
[8d25b44]197#ifdef CONFIG_DEBUG_ALLREGS
198 movq IOFFSET_RBX(%rsp), %rbx
199 movq IOFFSET_RBP(%rsp), %rbp
[49a39c2]200 movq IOFFSET_R12(%rsp), %r12
201 movq IOFFSET_R13(%rsp), %r13
202 movq IOFFSET_R14(%rsp), %r14
203 movq IOFFSET_R15(%rsp), %r15
[8d25b44]204#endif
[e3b9572]205.endm
[8e0eb63]206
[8d25b44]207#ifdef CONFIG_DEBUG_ALLREGS
208# define INTERRUPT_ALIGN 256
209#else
210# define INTERRUPT_ALIGN 128
211#endif
212
[e3b9572]213## Declare interrupt handlers
214#
215# Declare interrupt handlers for n interrupt
216# vectors starting at vector i.
217#
[8e0eb63]218# The handlers call exc_dispatch().
[e3b9572]219#
220.macro handler i n
221
[8e0eb63]222 /*
[296426ad]223 * Choose between version with error code and version without error
224 * code. Both versions have to be of the same size. amd64 assembly is,
225 * however, a little bit tricky. For instance, subq $0x80, %rsp and
226 * subq $0x78, %rsp can result in two instructions with different
227 * op-code lengths.
[e1be3b6]228 * Therefore we align the interrupt handlers.
[8e0eb63]229 */
230
231 .iflt \i-32
232 .if (1 << \i) & ERROR_WORD_INTERRUPT_LIST
233 /*
234 * Version with error word.
235 */
236 subq $IREGISTER_SPACE, %rsp
237 .else
238 /*
239 * Version without error word,
240 */
241 subq $(IREGISTER_SPACE+8), %rsp
242 .endif
243 .else
244 /*
245 * Version without error word,
246 */
247 subq $(IREGISTER_SPACE+8), %rsp
248 .endif
[e3b9572]249
[8e0eb63]250 save_all_gpr
[e3b9572]251
[8e0eb63]252 movq $(\i), %rdi # %rdi - first parameter
253 movq %rsp, %rsi # %rsi - pointer to istate
254 call exc_dispatch # exc_dispatch(i, istate)
255
[49a39c2]256 restore_all_gpr
257 # $8 = Skip error word
[8e0eb63]258 addq $(IREGISTER_SPACE+8), %rsp
[e3b9572]259 iretq
260
[8d25b44]261 .align INTERRUPT_ALIGN
[e3b9572]262 .if (\n-\i)-1
263 handler "(\i+1)",\n
264 .endif
265.endm
[8d25b44]266
267.align INTERRUPT_ALIGN
[e3b9572]268interrupt_handlers:
269h_start:
270 handler 0 IDT_ITEMS
271h_end:
[dd4d6b0]272
[296426ad]273## Low-level syscall handler
274#
275# Registers on entry:
276#
277# @param rcx Userspace return address.
278# @param r11 Userspace RLFAGS.
279#
280# @param rax Syscall number.
281# @param rdi 1st syscall argument.
282# @param rsi 2nd syscall argument.
283# @param rdx 3rd syscall argument.
284# @param r10 4th syscall argument. Used instead of RCX because the
285# SYSCALL instruction clobbers it.
286# @param r8 5th syscall argument.
287# @param r9 6th syscall argument.
288#
289# @return Return value is in rax.
290#
[dd4d6b0]291syscall_entry:
[296426ad]292 swapgs # Switch to hidden gs
293 #
294 # %gs:0 Scratch space for this thread's user RSP
295 # %gs:8 Address to be used as this thread's kernel RSP
296 #
297 movq %rsp, %gs:0 # Save this thread's user RSP
298 movq %gs:8, %rsp # Set this thread's kernel RSP
299 swapgs # Switch back to remain consistent
[6d9c49a]300 sti
[c7c0b89b]301
[296426ad]302 pushq %rcx
303 pushq %r11
304
305 movq %r10, %rcx # Copy the 4th argument where it is expected
306 pushq %rax
[dd4d6b0]307 call syscall_handler
[296426ad]308 addq $8, %rsp
[6d9c49a]309
[37b451f7]310 popq %r11
311 popq %rcx
[296426ad]312
313 cli
314 swapgs
315 movq %gs:0, %rsp # Restore the user RSP
316 swapgs
317
[37b451f7]318 sysretq
[296426ad]319
[e3b9572]320.data
321.global interrupt_handler_size
322
[42744880]323interrupt_handler_size: .quad (h_end-h_start)/IDT_ITEMS
Note: See TracBrowser for help on using the repository browser.