entry.S
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/x86_64/entry.S
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  6.  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
  7.  * 
  8.  *  $Id: entry.S,v 1.81 2002/09/12 12:55:25 ak Exp $
  9.  */
  10. /*
  11.  * entry.S contains the system-call and fault low-level handling routines.
  12.  *
  13.  * NOTE: This code handles signal-recognition, which happens every time
  14.  * after an interrupt and after each system call.
  15.  * 
  16.  * Normal syscalls and interrupts don't save a full stack frame, this is 
  17.  * only done for PT_TRACESYS, signals or fork/exec et.al.
  18.  * 
  19.  * TODO:  
  20.  * - schedule it carefully for the final hardware.  
  21.  *
  22.  */
  23. #define ASSEMBLY 1
  24. #include <linux/config.h>
  25. #include <linux/linkage.h>
  26. #include <asm/segment.h>
  27. #include <asm/current.h>
  28. #include <asm/smp.h>
  29. #include <asm/cache.h>
  30. #include <asm/errno.h>
  31. #include <asm/calling.h>
  32. #include <asm/offset.h>
  33. #include <asm/msr.h>
  34. #include <asm/unistd.h>
  35. .code64
  36. #define PDAREF(field) %gs:field  
  37. /*
  38.  * C code is not supposed to know about partial frames. Everytime a C function
  39.  * that looks at the pt_regs is called these two macros are executed around it.
  40.  * RESTORE_TOP_OF_STACK syncs the syscall state after any possible ptregs
  41.  * manipulation.
  42.  */        
  43. /* %rsp:at FRAMEEND */ 
  44. .macro FIXUP_TOP_OF_STACK tmp
  45. movq PDAREF(pda_oldrsp),tmp
  46. movq   tmp,RSP(%rsp)
  47. movq    $__USER_DS,SS(%rsp)
  48. movq    $__USER_CS,CS(%rsp)
  49. movq $-1,RCX(%rsp) /* contains return address, already in RIP */
  50. movq R11(%rsp),tmp  /* get eflags */
  51. movq tmp,EFLAGS(%rsp)
  52. .endm
  53. .macro RESTORE_TOP_OF_STACK tmp,offset=0
  54. movq   RSP-offset(%rsp),tmp
  55. movq   tmp,PDAREF(pda_oldrsp)
  56. movq   EFLAGS-offset(%rsp),tmp
  57. movq   tmp,R11-offset(%rsp)
  58. .endm
  59. /*
  60.  * A newly forked process directly context switches into this.
  61.  */ 
  62. ENTRY(ret_from_fork)
  63. movq %rax,%rdi /* return value of __switch_to -> prev task */
  64. call schedule_tail
  65. GET_CURRENT(%rcx)
  66. testb $PT_TRACESYS,tsk_ptrace(%rcx)
  67. jnz 2f
  68. 1:
  69. RESTORE_REST
  70. testl $3,CS-ARGOFFSET(%rsp) # from kernel_thread?
  71. jz   int_ret_from_sys_call
  72. testl $ASM_THREAD_IA32,tsk_thread+thread_flags(%rcx)
  73. jnz  int_ret_from_sys_call
  74. RESTORE_TOP_OF_STACK %rdi,ARGOFFSET
  75. jmp ret_from_sys_call
  76. 2:
  77. movq %rsp,%rdi
  78. call syscall_trace
  79. jmp 1b
  80. /*
  81.  * System call entry. Upto 6 arguments in registers are supported.
  82.  *
  83.  * SYSCALL does not save anything on the stack and does not change the
  84.  * stack pointer. Gets the per CPU area from the hidden GS MSR and finds the
  85.  * current kernel stack.
  86.  */
  87. /*
  88.  * Register setup:
  89.  * rax  system call number
  90.  * rdi  arg0
  91.  * rcx  return address for syscall/sysret, C arg3 
  92.  * rsi  arg1
  93.  * rdx  arg2
  94.  * r10  arg3  (--> moved to rcx for C)
  95.  * r8   arg4
  96.  * r9   arg5
  97.  * r11  eflags for syscall/sysret, temporary for C
  98.  * r12-r15,rbp,rbx saved by C code, not touched. 
  99.  * 
  100.  * Interrupts are off on entry.
  101.  * Only called from user space.
  102.  */   
  103. ENTRY(system_call)
  104. swapgs
  105. movq %rsp,PDAREF(pda_oldrsp) 
  106. movq PDAREF(pda_kernelstack),%rsp
  107. sti
  108. SAVE_ARGS 8,1
  109. movq  %rax,ORIG_RAX-ARGOFFSET(%rsp) 
  110. movq  %rcx,RIP-ARGOFFSET(%rsp)
  111. GET_CURRENT(%rcx)
  112. testl $PT_TRACESYS,tsk_ptrace(%rcx)
  113. jne tracesys
  114. cmpq $__NR_syscall_max,%rax
  115. ja badsys
  116. movq %r10,%rcx
  117. call *sys_call_table(,%rax,8)  # XXX:  rip relative
  118. movq %rax,RAX-ARGOFFSET(%rsp)
  119. .globl ret_from_sys_call
  120. ret_from_sys_call:
  121. sysret_with_reschedule:
  122. GET_CURRENT(%rcx)
  123. cli 
  124. cmpq $0,tsk_need_resched(%rcx)
  125. jne sysret_reschedule
  126. cmpl $0,tsk_sigpending(%rcx)
  127. jne sysret_signal
  128. sysret_restore_args:
  129. movq    RIP-ARGOFFSET(%rsp),%rcx
  130. RESTORE_ARGS 0,-ARG_SKIP,1
  131. movq PDAREF(pda_oldrsp),%rsp
  132. swapgs
  133. sysretq
  134. sysret_signal:
  135. sti
  136. xorl %esi,%esi # oldset
  137. leaq -ARGOFFSET(%rsp),%rdi # regs
  138. leaq do_signal(%rip),%rax
  139. call ptregscall_common
  140. sysret_signal_test:
  141. GET_CURRENT(%rcx)
  142. cli
  143. cmpq $0,tsk_need_resched(%rcx)
  144. je   sysret_restore_args
  145. sti
  146. call schedule
  147. jmp sysret_signal_test
  148. sysret_reschedule:
  149. sti
  150. call schedule
  151. jmp sysret_with_reschedule
  152. tracesys:  
  153. SAVE_REST
  154. movq $-ENOSYS,RAX(%rsp)
  155. FIXUP_TOP_OF_STACK %rdi
  156. movq %rsp,%rdi
  157. call syscall_trace
  158. LOAD_ARGS ARGOFFSET  /* reload args from stack in case ptrace changed it */
  159. RESTORE_REST
  160. cmpq $__NR_syscall_max,%rax
  161. ja  tracesys_done
  162. tracesys_call: /* backtrace marker */
  163. movq %r10,%rcx /* fixup for C */
  164. call *sys_call_table(,%rax,8)
  165. movq %rax,RAX-ARGOFFSET(%rsp)
  166. tracesys_done: /* backtrace marker */
  167. SAVE_REST
  168. movq %rsp,%rdi
  169. call syscall_trace
  170. RESTORE_TOP_OF_STACK %rbx
  171. RESTORE_REST
  172. jmp ret_from_sys_call
  173. badsys:
  174. movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
  175. jmp ret_from_sys_call
  176. /*
  177.  * Syscall return path ending with IRET.
  178.  * This can be either 64bit calls that require restoring of all registers 
  179.  * (impossible with sysret) or 32bit calls.   
  180.  */
  181. ENTRY(int_ret_from_sys_call)
  182. intret_test_kernel:
  183. testl $3,CS-ARGOFFSET(%rsp)
  184. je retint_restore_args
  185. intret_with_reschedule:
  186. GET_CURRENT(%rcx)
  187. cli 
  188. cmpq $0,tsk_need_resched(%rcx)
  189. jne intret_reschedule
  190. cmpl $0,tsk_sigpending(%rcx)
  191. jne intret_signal
  192. jmp retint_restore_args_swapgs
  193. intret_reschedule:
  194. sti
  195. call schedule
  196. jmp intret_with_reschedule
  197. intret_signal:
  198. sti
  199. SAVE_REST
  200. xorq %rsi,%rsi # oldset -> arg2 
  201. movq %rsp,%rdi # &ptregs -> arg1
  202. call do_signal
  203. RESTORE_REST
  204. intret_signal_test:
  205. GET_CURRENT(%rcx)
  206. cli
  207. cmpq $0,tsk_need_resched(%rcx)
  208. je   retint_restore_args_swapgs
  209. sti
  210. call schedule
  211. jmp  intret_signal_test
  212. /* 
  213.  * Certain special system calls that need to save a complete stack frame.
  214.  */ 
  215. .macro PTREGSCALL label,func
  216. .globl label
  217. label:
  218. leaq func(%rip),%rax
  219. jmp ptregscall_common
  220. .endm
  221. PTREGSCALL stub_clone, sys_clone
  222. PTREGSCALL stub_fork, sys_fork
  223. PTREGSCALL stub_vfork, sys_vfork
  224. PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend
  225. PTREGSCALL stub_sigaltstack, sys_sigaltstack
  226. PTREGSCALL stub_iopl, sys_iopl
  227. ENTRY(ptregscall_common)
  228. popq %r11
  229. SAVE_REST
  230. movq %r11, %r15
  231. FIXUP_TOP_OF_STACK %r11
  232. call *%rax
  233. RESTORE_TOP_OF_STACK %r11
  234. movq %r15, %r11
  235. RESTORE_REST
  236. pushq %r11
  237. ret
  238. ENTRY(stub_execve)
  239. popq %r11
  240. SAVE_REST
  241. movq %r11, %r15
  242. FIXUP_TOP_OF_STACK %r11
  243. call sys_execve
  244. GET_CURRENT(%rcx)
  245. testl $ASM_THREAD_IA32,tsk_thread+thread_flags(%rcx)
  246. jnz exec_32bit
  247. RESTORE_TOP_OF_STACK %r11
  248. movq %r15, %r11
  249. RESTORE_REST
  250. push %r11
  251. ret
  252. exec_32bit:
  253. movq %rax,RAX(%rsp)
  254. RESTORE_REST
  255. jmp int_ret_from_sys_call
  256. /*
  257.  * sigreturn is special because it needs to restore all registers on return.
  258.  * This cannot be done with SYSRET, so use the IRET return path instead.
  259.  */                
  260. ENTRY(stub_rt_sigreturn)
  261. addq $8, %rsp
  262. SAVE_REST
  263. FIXUP_TOP_OF_STACK %r11
  264. call sys_rt_sigreturn
  265. movq %rax,RAX(%rsp) # fixme, this could be done at the higher layer
  266. RESTORE_REST
  267. jmp int_ret_from_sys_call
  268. /* 
  269.  * Interrupt entry/exit.
  270.  *
  271.  * Interrupt entry points save only callee clobbered registers, except
  272.  * for signals again.
  273.  *
  274.  * Entry runs with interrupts off.
  275.  */ 
  276. /* 0(%rsp): interrupt number */ 
  277. ENTRY(common_interrupt)
  278. testl $3,16(%rsp) # from kernel?
  279. je   1f
  280. swapgs
  281. 1: cld
  282. SAVE_ARGS
  283. leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler
  284. addl $1,PDAREF(pda_irqcount) # XXX: should be merged with irq.c irqcount
  285. movq PDAREF(pda_irqstackptr),%rax
  286. cmoveq %rax,%rsp
  287. pushq %rdi # save old stack
  288. call do_IRQ
  289. /* 0(%rsp): oldrsp-ARGOFFSET */ 
  290. ENTRY(ret_from_intr)
  291. cli
  292. popq  %rdi
  293. subl $1,PDAREF(pda_irqcount)
  294. leaq ARGOFFSET(%rdi),%rsp
  295. testl $3,CS(%rdi) # from kernel?
  296. je retint_restore_args
  297. /* Interrupt came from user space */
  298. retint_with_reschedule:
  299. GET_CURRENT(%rcx)
  300. cmpq $0,tsk_need_resched(%rcx) 
  301. jne retint_reschedule
  302. cmpl $0,tsk_sigpending(%rcx)
  303. jne retint_signal
  304. retint_restore_args_swapgs:
  305. swapgs
  306. retint_restore_args:
  307. RESTORE_ARGS 0,8
  308. iret_label:
  309. iretq
  310. .section __ex_table,"a"
  311. .align 8
  312. .quad iret_label,bad_iret
  313. .previous
  314. .section .fixup,"ax"
  315. /* force a signal here? this matches i386 behaviour */
  316. bad_iret:
  317. movq $-9999,%rdi /* better code? */
  318. jmp do_exit
  319. .previous
  320. retint_signal:
  321. sti
  322. SAVE_REST
  323. movq $-1,ORIG_RAX(%rsp) 
  324. xorq %rsi,%rsi # oldset
  325. movq %rsp,%rdi # &pt_regs
  326. call do_signal
  327. RESTORE_REST
  328. retint_signal_test:
  329. cli
  330. GET_CURRENT(%rcx) 
  331. cmpq $0,tsk_need_resched(%rcx) 
  332. je   retint_restore_args_swapgs
  333. sti
  334. call schedule
  335. jmp retint_signal_test
  336. retint_reschedule:
  337. sti
  338. call schedule
  339. cli
  340. jmp retint_with_reschedule
  341. /*
  342.  * Exception entry points.
  343.  */ 
  344. .macro zeroentry sym
  345. pushq $0 /* push error code/oldrax */ 
  346. pushq %rax /* push real oldrax to the rdi slot */ 
  347. leaq  sym(%rip),%rax
  348. jmp error_entry
  349. .endm
  350. .macro errorentry sym
  351. pushq %rax
  352. leaq  sym(%rip),%rax
  353. jmp error_entry
  354. .endm
  355. /*
  356.  * Exception entry point. This expects an error code/orig_rax on the stack
  357.  * and the exception handler in %rax.
  358.  */    
  359.   ALIGN
  360. error_entry:
  361. /* rdi slot contains rax, oldrax contains error code */
  362. pushq %rsi
  363. movq  8(%rsp),%rsi /* load rax */
  364. pushq %rdx
  365. pushq %rcx
  366. pushq %rsi /* store rax */ 
  367. pushq %r8
  368. pushq %r9
  369. pushq %r10
  370. pushq %r11
  371. cld
  372. SAVE_REST
  373. testl $3,CS(%rsp)
  374. je error_kernelspace
  375. swapgs
  376. movl $1,%r15d
  377. error_action:
  378. sti
  379. movq  %rdi,RDI(%rsp) 
  380. movq %rsp,%rdi
  381. movq ORIG_RAX(%rsp),%rsi /* get error code */ 
  382. movq $-1,ORIG_RAX(%rsp)
  383. call *%rax
  384. /* r15d: swapgs flag */
  385. error_exit:
  386. testl %r15d,%r15d
  387. jz   error_restore
  388. error_test:
  389. cli
  390. GET_CURRENT(%rcx)
  391. cmpq $0,tsk_need_resched(%rcx)
  392. jne  error_reschedule
  393. cmpl $0,tsk_sigpending(%rcx)
  394. jne  error_signal
  395. error_restore_swapgs:
  396. swapgs
  397. error_restore:
  398. RESTORE_REST
  399. jmp retint_restore_args
  400. error_reschedule:
  401. sti
  402. call schedule
  403. jmp  error_test
  404. error_signal:
  405. sti
  406. xorq %rsi,%rsi
  407. movq %rsp,%rdi
  408. call do_signal
  409. error_signal_test:
  410. GET_CURRENT(%rcx)
  411. cli
  412. cmpq $0,tsk_need_resched(%rcx)
  413. je   error_restore_swapgs
  414. sti
  415. call schedule
  416. jmp  error_signal_test
  417. error_kernelspace:
  418. xorl %r15d,%r15d
  419. cmpq $iret_label,RIP(%rsp)
  420. jne  error_action
  421. movl $1,%r15d
  422. swapgs
  423. jmp error_action
  424. /*
  425.  * Create a kernel thread.
  426.  *
  427.  * C extern interface:
  428.  * extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
  429.  *
  430.  * asm input arguments:
  431.  * rdi: fn, rsi: arg, rdx: flags
  432.  */
  433. ENTRY(kernel_thread)
  434. FAKE_STACK_FRAME $child_rip
  435. SAVE_ALL
  436. # rdi: flags, rsi: usp, rdx: will be &pt_regs
  437. movq %rdx,%rdi
  438. orq  $CLONE_VM, %rdi
  439. movq $-1, %rsi
  440. movq %rsp, %rdx
  441. # clone now
  442. call do_fork
  443. # save retval on the stack so it's popped before `ret`
  444. movq %rax, RAX(%rsp)
  445. /*
  446.  * It isn't worth to check for reschedule here,
  447.  * so internally to the x86_64 port you can rely on kernel_thread()
  448.  * not to reschedule the child before returning, this avoids the need
  449.  * of hacks for example to fork off the per-CPU idle tasks.
  450.          * [Hopefully no generic code relies on the reschedule -AK]
  451.  */
  452. RESTORE_ALL
  453. UNFAKE_STACK_FRAME
  454. ret
  455. child_rip:
  456. /*
  457.  * Here we are in the child and the registers are set as they were
  458.  * at kernel_thread() invocation in the parent.
  459.  */
  460. movq %rdi, %rax
  461. movq %rsi, %rdi
  462. call *%rax
  463. # exit
  464. xorq %rdi, %rdi
  465. call do_exit
  466. /*
  467.  * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
  468.  *
  469.  * C extern interface:
  470.  *  extern long execve(char *name, char **argv, char **envp)
  471.  *
  472.  * asm input arguments:
  473.  * rdi: name, rsi: argv, rdx: envp
  474.  *
  475.  * We want to fallback into:
  476.  * extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
  477.  *
  478.  * do_sys_execve asm fallback arguments:
  479.  * rdi: name, rsi: argv, rdx: envp, fake frame on the stack
  480.  */
  481. ENTRY(execve)
  482. FAKE_STACK_FRAME $0
  483. SAVE_ALL
  484. call sys_execve
  485. movq %rax, RAX(%rsp)
  486. RESTORE_REST
  487. testq %rax,%rax
  488. je int_ret_from_sys_call
  489. RESTORE_ARGS
  490. UNFAKE_STACK_FRAME
  491. ret
  492. ENTRY(page_fault)
  493. #ifdef CONFIG_KDB
  494. pushq %rcx
  495. pushq %rdx
  496. pushq %rax
  497. movl  $473,%ecx
  498. rdmsr
  499. andl  $0xfffffffe,%eax /* Disable last branch recording */
  500. wrmsr
  501. popq  %rax
  502. popq  %rdx
  503. popq  %rcx
  504. #endif
  505. errorentry do_page_fault
  506. ENTRY(coprocessor_error)
  507. zeroentry do_coprocessor_error
  508. ENTRY(simd_coprocessor_error)
  509. zeroentry do_simd_coprocessor_error
  510. ENTRY(device_not_available)
  511. pushq $-1
  512. SAVE_ALL
  513. xorl %r15d,%r15d
  514. testl $3,CS(%rsp)
  515. jz 1f
  516. swapgs 
  517. movl $1,%r15d
  518. 1:
  519. movq  %cr0,%rax
  520. leaq  math_state_restore(%rip),%rcx
  521. leaq  math_emulate(%rip),%rbx
  522. testl $0x4,%eax
  523. cmoveq %rcx,%rbx
  524. call  *%rbx
  525. jmp  error_exit
  526. ENTRY(debug)
  527. zeroentry do_debug
  528. ENTRY(nmi)
  529. pushq $-1
  530. SAVE_ALL
  531. /* NMI could happen inside the critical section of a swapgs,
  532.    so it is needed to use this expensive way to check.
  533.    Rely on arch_prctl forbiding user space from setting a negative
  534.    GS. Only the kernel value is negative. */
  535. movl  $MSR_GS_BASE,%ecx
  536. rdmsr
  537. xorl  %ebx,%ebx
  538. testl %edx,%edx
  539. js    1f
  540. swapgs
  541. movl  $1,%ebx
  542. 1: movq %rsp,%rdi
  543. call do_nmi
  544. cli
  545. testl %ebx,%ebx
  546. jz error_restore
  547. swapgs
  548. jmp error_restore
  549. ENTRY(int3)
  550. zeroentry do_int3
  551. ENTRY(overflow)
  552. zeroentry do_overflow
  553. ENTRY(bounds)
  554. zeroentry do_bounds
  555. ENTRY(invalid_op)
  556. zeroentry do_invalid_op
  557. ENTRY(coprocessor_segment_overrun)
  558. zeroentry do_coprocessor_segment_overrun
  559. ENTRY(reserved)
  560. zeroentry do_reserved
  561. ENTRY(double_fault)
  562. errorentry do_double_fault
  563. ENTRY(invalid_TSS)
  564. errorentry do_invalid_TSS
  565. ENTRY(segment_not_present)
  566. errorentry do_segment_not_present
  567. ENTRY(stack_segment)
  568. errorentry do_stack_segment
  569. ENTRY(general_protection)
  570. errorentry do_general_protection
  571. ENTRY(alignment_check)
  572. errorentry do_alignment_check
  573. ENTRY(divide_error)
  574. zeroentry do_divide_error
  575. ENTRY(spurious_interrupt_bug)
  576. zeroentry do_spurious_interrupt_bug
  577. ENTRY(machine_check)
  578. zeroentry do_machine_check
  579. ENTRY(call_debug)
  580. zeroentry do_call_debug