entry.S
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:43k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*------------------------------------------------------------------------------
  2.  * Native PARISC/Linux Project (http://www.puffingroup.com/parisc)
  3.  *
  4.  * kernel entry points (interruptions, system call wrappers)
  5.  *  Copyright (C) 1999,2000 Philipp Rumpf 
  6.  *  Copyright (C) 1999 SuSE GmbH Nuernberg 
  7.  *  Copyright (C) 2000 Hewlett-Packard (John Marvin)
  8.  *  Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
  9.  *
  10.  *    This program is free software; you can redistribute it and/or modify
  11.  *    it under the terms of the GNU General Public License as published by
  12.  *    the Free Software Foundation; either version 2, or (at your option)
  13.  *    any later version.
  14.  *
  15.  *    This program is distributed in the hope that it will be useful,
  16.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *    GNU General Public License for more details.
  19.  *
  20.  *    You should have received a copy of the GNU General Public License
  21.  *    along with this program; if not, write to the Free Software
  22.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  */
  24. #include <linux/config.h>
  25. #include <asm/offset.h>
  26. /* the following is the setup i think we should follow:
  27.  * whenever the CPU is interruptible, the following has to be true:
  28.  *  CR30 is the kernel sp or 0 if we currently use the kernel stack
  29.  *  CR31 is the kernel gp */ 
  30. /* we have the following possibilities to act on an interruption:
  31.  *  - handle in assembly and use shadowed registers only
  32.  *  - save registers to kernel stack and handle in assembly or C */
  33. .text
  34. #ifdef __LP64__
  35. .level 2.0w
  36. #endif
  37. #define __ASSEMBLY__
  38. #include <asm/assembly.h> /* for LDREG/STREG defines */
  39. #include <asm/pgtable.h>
  40. #include <asm/psw.h>
  41. #include <asm/signal.h>
  42. #ifdef __LP64__
  43. #define FRAME_SIZE 64
  44. #else
  45. #define FRAME_SIZE 64
  46. #endif
  47. /* Switch to virtual mapping, trashing only %r1 */
  48. .macro virt_map rfi_type
  49. mtsm %r0
  50. tovirt %r29
  51. tovirt %r30
  52. mfsp %sr7, %r1
  53. mtsp %r1, %sr3
  54. mtsp %r0, %sr4
  55. mtsp %r0, %sr5
  56. mtsp %r0, %sr6
  57. mtsp %r0, %sr7
  58. ldil L%KERNEL_PSW, %r1
  59. ldo R%KERNEL_PSW(%r1), %r1
  60. LDIL_FIXUP(%r1)
  61. mtctl %r1, %cr22
  62. mtctl %r0, %cr17
  63. mtctl %r0, %cr17
  64. ldil L%.+28, %r1
  65. ldo R%.+24(%r1), %r1
  66. LDIL_FIXUP(%r1)
  67. mtctl %r1, %cr18
  68. ldo 4(%r1), %r1
  69. mtctl %r1, %cr18
  70. rfi_type
  71. nop
  72. .endm
  73. .macro get_stack
  74. mfctl %cr30, %r1 
  75. comib,=,n 0, %r1, 0f   /* forward so predicted not taken */
  76. /* we save the registers in the task struct */
  77. ldo TASK_REGS(%r1), %r29
  78. tophys %r29
  79. STREG %r30, PT_GR30(%r29)
  80. STREG %r1,  PT_CR30(%r29)
  81. ldo TASK_SZ_ALGN(%r1), %r30
  82. b 1f     /* unconditional so predicted taken */
  83. mtctl %r0,%cr30
  84. 0:
  85. /* we put a struct pt_regs on the stack and save the registers there */
  86. copy %r30,%r29
  87. ldo PT_SZ_ALGN(%r30),%r30
  88. tophys %r29
  89. STREG %r30,PT_GR30(%r29)
  90. STREG %r0,PT_CR30(%r29)
  91. 1:
  92. .endm
  93. .macro rest_stack regs
  94. LDREG PT_CR30(regs), %r1
  95. comib,=,n 0, %r1, 2f/* forward so predicted not taken */
  96. /* we restore the registers out of the task struct */
  97. mtctl %r1, %cr30
  98. LDREG PT_GR1(regs), %r1
  99. LDREG PT_GR30(regs),%r30
  100. b 3f
  101. LDREG PT_GR29(regs),%r29
  102. 2:
  103. /* we take a struct pt_regs off the stack */
  104. LDREG PT_GR1(regs),  %r1
  105. LDREG PT_GR29(regs), %r29
  106. ldo -PT_SZ_ALGN(%r30), %r30
  107. 3:
  108. .endm
  109. #ifdef OLD
  110. /* fixme interruption handler */
  111. .macro def code
  112. /* WARNING!!! THIS IS DEBUG CODE ONLY!!! */
  113. b unimplemented_64bitirq
  114. ldi code, %r1
  115. .align 32
  116. .endm
  117. /* Use def to enable break - KWDB wants em
  118.  * (calls traps.c:handle_interruption) */
  119. .macro pass_break code
  120. #else
  121. /* default interruption handler
  122.  * (calls traps.c:handle_interruption) */
  123. .macro def code
  124. #endif
  125. mtctl %r29, %cr31
  126. mtctl %r1,  %cr28
  127. ldi code, %r1
  128. b intr_save
  129. mtctl   %r1, %cr29
  130. .align 32
  131. .endm
  132. /* Interrupt interruption handler
  133.  * (calls irq.c:do_irq_mask) */
  134. .macro extint code
  135. mtctl %r29, %cr31
  136. mtctl %r1,  %cr28
  137. mfctl %cr23, %r1
  138. mtctl %r1, %cr23
  139. b intr_extint
  140. mtctl %r1, %cr29
  141. .align 32
  142. .endm
  143. .import os_hpmc, code
  144. /* HPMC handler */
  145. .macro hpmc code
  146. nop /* must be a NOP, will be patched later */
  147. ldil L%PA(os_hpmc), %r3
  148. ldo R%PA(os_hpmc)(%r3), %r3
  149. bv,n 0(%r3)
  150. nop
  151. .word 0 /* checksum (will be patched) */
  152. .word PA(os_hpmc) /* address of handler */
  153. .word 0 /* length of handler */
  154. .endm
  155. /*
  156.  * Performance Note: Instructions will be moved up into
  157.  * this part of the code later on, once we are sure
  158.  * that the tlb miss handlers are close to final form.
  159.  */
  160. /* Register definitions for tlb miss handler macros */
  161. va  = r8 /* virtual address for which the trap occured */
  162. spc = r24 /* space for which the trap occured */
  163. #ifndef __LP64__
  164. /*
  165.  * itlb miss interruption handler (parisc 1.1 - 32 bit)
  166.  */
  167. .macro itlb_11 code
  168. mfctl %pcsq, spc
  169. b itlb_miss_11
  170. mfctl %pcoq, va
  171. .align 32
  172. .endm
  173. #endif
  174. /*
  175.  * itlb miss interruption handler (parisc 2.0)
  176.  */
  177. .macro itlb_20 code
  178. mfctl %pcsq, spc
  179. #ifdef __LP64__
  180. b       itlb_miss_20w
  181. #else
  182. b itlb_miss_20
  183. #endif
  184. mfctl %pcoq, va
  185. .align 32
  186. .endm
  187. #ifndef __LP64__
  188. /*
  189.  * naitlb miss interruption handler (parisc 1.1 - 32 bit)
  190.  *
  191.  * Note: naitlb misses will be treated
  192.  * as an ordinary itlb miss for now.
  193.  * However, note that naitlb misses
  194.  * have the faulting address in the
  195.  * IOR/ISR.
  196.  */
  197. .macro naitlb_11 code
  198. mfctl %isr,spc
  199. b itlb_miss_11
  200. mfctl  %ior,va
  201. /* FIXME: If user causes a naitlb miss, the priv level may not be in
  202.  * lower bits of va, where the itlb miss handler is expecting them
  203.  */
  204. .align 32
  205. .endm
  206. #endif
  207. /*
  208.  * naitlb miss interruption handler (parisc 2.0)
  209.  *
  210.  * Note: naitlb misses will be treated
  211.  * as an ordinary itlb miss for now.
  212.  * However, note that naitlb misses
  213.  * have the faulting address in the
  214.  * IOR/ISR.
  215.  */
  216. .macro naitlb_20 code
  217. mfctl %isr,spc
  218. #ifdef __LP64__
  219. b       itlb_miss_20w
  220. #else
  221. b itlb_miss_20
  222. #endif
  223. mfctl  %ior,va
  224. /* FIXME: If user causes a naitlb miss, the priv level may not be in
  225.  * lower bits of va, where the itlb miss handler is expecting them
  226.  */
  227. .align 32
  228. .endm
  229. #ifndef __LP64__
  230. /*
  231.  * dtlb miss interruption handler (parisc 1.1 - 32 bit)
  232.  */
  233. .macro dtlb_11 code
  234. mfctl %isr, spc
  235. b dtlb_miss_11
  236. mfctl %ior, va
  237. .align 32
  238. .endm
  239. #endif
  240. /*
  241.  * dtlb miss interruption handler (parisc 2.0)
  242.  */
  243. .macro dtlb_20 code
  244. mfctl %isr, spc
  245. #ifdef __LP64__
  246. b       dtlb_miss_20w
  247. #else
  248. b dtlb_miss_20
  249. #endif
  250. mfctl %ior, va
  251. .align 32
  252. .endm
  253. #ifndef __LP64__
  254. /* nadtlb miss interruption handler (parisc 1.1 - 32 bit)
  255.  *
  256.  * Note: nadtlb misses will be treated
  257.  * as an ordinary dtlb miss for now.
  258.  *
  259.  */
  260. .macro nadtlb_11 code
  261. mfctl %isr,spc
  262. b dtlb_miss_11
  263. mfctl %ior,va
  264. .align 32
  265. .endm
  266. #endif
  267. /* nadtlb miss interruption handler (parisc 2.0)
  268.  *
  269.  * Note: nadtlb misses will be treated
  270.  * as an ordinary dtlb miss for now.
  271.  *
  272.  */
  273. .macro nadtlb_20 code
  274. mfctl %isr,spc
  275. #ifdef __LP64__
  276. b       dtlb_miss_20w
  277. #else
  278. b dtlb_miss_20
  279. #endif
  280. mfctl %ior,va
  281. .align 32
  282. .endm
  283. #ifndef __LP64__
  284. /*
  285.  * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
  286.  */
  287. .macro dbit_11 code
  288. mfctl %isr,spc
  289. b dbit_trap_11
  290. mfctl %ior,va
  291. .align 32
  292. .endm
  293. #endif
  294. /*
  295.  * dirty bit trap interruption handler (parisc 2.0)
  296.  */
  297. .macro dbit_20 code
  298. mfctl %isr,spc
  299. #ifdef __LP64__
  300. b       dbit_trap_20w
  301. #else
  302. b dbit_trap_20
  303. #endif
  304. mfctl %ior,va
  305. .align 32
  306. .endm
  307. /*
  308.  * Align fault_vector_20 on 4K boundary so that both
  309.  * fault_vector_11 and fault_vector_20 are on the
  310.  * same page. This is only necessary as long as we
  311.  * write protect the kernel text, which we may stop
  312.  * doing once we use large parge translations to cover
  313.  * the static part of the kernel address space.
  314.  */
  315. .export fault_vector_20
  316. .align 4096
  317. fault_vector_20:
  318. /* First vector is invalid (0) */
  319. .ascii "cows can fly"
  320. .byte 0
  321. .align 32
  322. hpmc  1
  323. def  2
  324. def  3
  325. extint  4
  326. def  5
  327. itlb_20  6
  328. def  7
  329. def  8
  330. def              9
  331. def 10
  332. def 11
  333. def 12
  334. def 13
  335. def 14
  336. dtlb_20 15
  337. naitlb_20 16
  338. nadtlb_20 17
  339. def 18
  340. def 19
  341. dbit_20 20
  342. def 21
  343. def 22
  344. def 23
  345. def 24
  346. def 25
  347. def 26
  348. def 27
  349. def 28
  350. def 29
  351. def 30
  352. def 31
  353. #ifndef __LP64__
  354. .export fault_vector_11
  355. .align 2048
  356. fault_vector_11:
  357. /* First vector is invalid (0) */
  358. .ascii "cows can fly"
  359. .byte 0
  360. .align 32
  361. hpmc  1
  362. def  2
  363. def  3
  364. extint  4
  365. def  5
  366. itlb_11  6
  367. def  7
  368. def  8
  369. def              9
  370. def 10
  371. def 11
  372. def 12
  373. def 13
  374. def 14
  375. dtlb_11 15
  376. naitlb_11 16
  377. nadtlb_11 17
  378. def 18
  379. def 19
  380. dbit_11 20
  381. def 21
  382. def 22
  383. def 23
  384. def 24
  385. def 25
  386. def 26
  387. def 27
  388. def 28
  389. def 29
  390. def 30
  391. def 31
  392. #endif
  393. .import handle_interruption,code
  394. .import handle_real_interruption,code
  395. .import do_irq_mask,code
  396. .import parisc_stopkernel,code
  397. .import cpu_irq_region,data
  398. /*
  399.  * r26 = function to be called
  400.  * r25 = argument to pass in
  401.  * r24 = flags for do_fork()
  402.  *
  403.  * Kernel threads don't ever return, so they don't need
  404.  * a true register context. We just save away the arguments
  405.  * for copy_thread/ret_ to properly set up the child.
  406.  */
  407. #define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
  408. .export __kernel_thread, code
  409. .import do_fork
  410. __kernel_thread:
  411. STREG %r2, -RP_OFFSET(%r30)
  412. copy %r30, %r1
  413. ldo PT_SZ_ALGN(%r30),%r30
  414. #ifdef __LP64__
  415. /* Yo, function pointers in wide mode are little structs... -PB */
  416. /* XXX FIXME do we need to honor the fptr's %dp value too? */
  417. ldd 16(%r26), %r26
  418. #endif
  419. STREG %r26, PT_GR26(%r1)  /* Store function & argument for child */
  420. STREG %r25, PT_GR25(%r1)
  421. ldo CLONE_VM(%r0), %r26   /* Force CLONE_VM since only init_mm */
  422. or %r26, %r24, %r26      /* will have kernel mappings.  */
  423. copy %r0, %r25
  424. bl do_fork, %r2
  425. copy %r1, %r24
  426. /* Parent Returns here */
  427. ldo -PT_SZ_ALGN(%r30), %r30
  428. LDREG -RP_OFFSET(%r30), %r2
  429. bv %r0(%r2)
  430. nop
  431. /*
  432.  * Child Returns here
  433.  *
  434.  * copy_thread moved args from temp save area set up above
  435.  * into task save area.
  436.  */
  437. .export ret_from_kernel_thread
  438. ret_from_kernel_thread:
  439. LDREG TASK_PT_GR26-TASK_SZ_ALGN(%r30), %r1
  440. LDREG TASK_PT_GR25-TASK_SZ_ALGN(%r30), %r26
  441. ble 0(%sr7, %r1)
  442. copy %r31, %r2
  443. b sys_exit
  444. ldi 0, %r26
  445. .import sys_execve, code
  446. .export __execve, code
  447. __execve:
  448. copy %r2, %r15
  449. copy %r23, %r17
  450. copy %r30, %r16
  451. ldo PT_SZ_ALGN(%r30), %r30
  452. STREG %r26, PT_GR26(%r16)
  453. STREG %r25, PT_GR25(%r16)
  454. STREG %r24, PT_GR24(%r16)
  455. bl sys_execve, %r2
  456. copy %r16, %r26
  457. comib,<>,n 0,%r28,__execve_failed
  458. b intr_return
  459. STREG %r17, PT_CR30(%r16)
  460. __execve_failed:
  461. /* yes, this will trap and die. */
  462. copy %r15, %r2
  463. bv %r0(%r2)
  464. nop
  465. .align 4
  466. /*
  467.  * struct task_struct *_switch_to(struct task_struct *prev,
  468.  * struct task_struct *next)
  469.  *
  470.  * switch kernel stacks and return prev */
  471. .export _switch_to, code
  472. _switch_to:
  473. STREG  %r2, -RP_OFFSET(%r30)
  474. callee_save
  475. ldil L%_switch_to_ret, %r2
  476. ldo R%_switch_to_ret(%r2), %r2
  477. LDIL_FIXUP(%r2)
  478. STREG %r2, TASK_PT_KPC(%r26)
  479. LDREG TASK_PT_KPC(%r25), %r2
  480. STREG %r30, TASK_PT_KSP(%r26)
  481. LDREG TASK_PT_KSP(%r25), %r30
  482. bv %r0(%r2)
  483. nop
  484. _switch_to_ret:
  485. mtctl %r0, %cr0 /* Needed for single stepping */
  486. callee_rest
  487. LDREG -RP_OFFSET(%r30), %r2
  488. bv %r0(%r2)
  489. copy %r26, %r28
  490. /*
  491.  * Common rfi return path for interruptions, kernel execve, and some
  492.  * syscalls.  The sys_rt_sigreturn syscall will return via this path
  493.  * if the signal was received when the process was running; if the
  494.  * process was blocked on a syscall then the normal syscall_exit
  495.  * path is used.  All syscalls for traced proceses exit via
  496.  * intr_restore.
  497.  * Note that the following code uses a "relied upon translation". See
  498.  * the parisc ACD for details. The ssm is necessary due to a PCXT bug.
  499.  */
  500. .align 4096
  501. .export syscall_exit_rfi
  502. syscall_exit_rfi:
  503. copy    %r30,%r16
  504. /* FIXME! depi below has hardcoded dependency on kernel stack size */
  505. depi    0,31,14,%r16 /* get task pointer */
  506. ldo TASK_REGS(%r16),%r16
  507. /* Force iaoq to userspace, as the user has had access to our current
  508.  * context via sigcontext.
  509.  * XXX do we need any other protection here?
  510.  */
  511. LDREG PT_IAOQ0(%r16),%r19
  512. depi 3,31,2,%r19
  513. STREG %r19,PT_IAOQ0(%r16)
  514. LDREG PT_IAOQ1(%r16),%r19
  515. depi 3,31,2,%r19
  516. STREG %r19,PT_IAOQ1(%r16)
  517. intr_return:
  518. /* Check for software interrupts */
  519. .import irq_stat,data
  520. ldil    L%irq_stat,%r19
  521. ldo     R%irq_stat(%r19),%r19
  522. LDIL_FIXUP(%r19)
  523. #ifdef CONFIG_SMP
  524. copy    %r30,%r1
  525. /* FIXME! depi below has hardcoded dependency on kernel stack size */
  526. depi    0,31,14,%r1 /* get task pointer */
  527. ldw     TASK_PROCESSOR(%r1),%r20 /* get cpu # - int */
  528. #if (IRQSTAT_SZ == 32)
  529. dep     %r20,26,27,%r20 /* shift left 5 bits */
  530. #else
  531. #error IRQSTAT_SZ changed, fix dep
  532. #endif /* IRQSTAT_SZ */
  533. add     %r19,%r20,%r19
  534. #endif /* CONFIG_SMP */
  535. ldw     IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */
  536. ldw     IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */
  537. and     %r19,%r20,%r20
  538. comib,<>,n 0,%r20,intr_do_softirq /* forward */
  539. intr_check_resched:
  540. /* check for reschedule */
  541. copy    %r30,%r1
  542. /* FIXME! depi below has hardcoded dependency on kernel stack size */
  543. depi    0,31,14,%r1 /* get task pointer */
  544. LDREG     TASK_NEED_RESCHED(%r1),%r19 /* sched.h: long need_resched */
  545. comib,<>,n 0,%r19,intr_do_resched /* forward */
  546. intr_check_sig:
  547. /* As above */
  548. copy    %r30,%r1
  549. depi    0,31,14,%r1 /* get task pointer */
  550. ldw TASK_SIGPENDING(%r1),%r19 /* sched.h: int sigpending */
  551. comib,<>,n 0,%r19,intr_do_signal /* forward */
  552. intr_restore:
  553. copy      %r16, %r29
  554. ldo PT_FR31(%r29), %r29
  555. rest_fp %r29
  556. copy     %r16, %r29
  557. rest_general  %r29
  558. ssm 0,%r0
  559. nop
  560. nop
  561. nop
  562. nop
  563. nop
  564. nop
  565. nop
  566. tophys %r29
  567. mtsm %r0
  568. rest_specials %r29
  569. rest_stack %r29
  570. rfi
  571. nop
  572. nop
  573. nop
  574. nop
  575. nop
  576. nop
  577. nop
  578. nop
  579. .import do_softirq,code
  580. intr_do_softirq:
  581. bl      do_softirq,%r2
  582. nop
  583. b       intr_check_resched
  584. nop
  585. .import schedule,code
  586. intr_do_resched:
  587. /* Only do reschedule if we are returning to user space */
  588. LDREG     PT_SR7(%r16), %r20
  589. comib,= 0,%r20,intr_restore /* backward */
  590. nop
  591. bl      schedule,%r2
  592. ssm     PSW_SM_I, %r0
  593. /* It's OK to leave I bit on */
  594. b       intr_return /* start over if we got a resched */
  595. nop
  596. .import do_signal,code
  597. intr_do_signal:
  598. /* Only do signals if we are returning to user space */
  599. LDREG   PT_SR7(%r16), %r20
  600. comib,= 0,%r20,intr_restore /* backward */
  601. nop
  602. copy %r0, %r24 /* unsigned long in_syscall */
  603. copy %r16, %r25 /* struct pt_regs *regs */
  604. ssm     PSW_SM_I, %r0
  605. bl do_signal,%r2
  606. copy %r0, %r26 /* sigset_t *oldset = NULL */
  607. b intr_restore
  608. nop
  609. /* CR28 - saved GR1
  610.  * CR29 - argument for do_irq_mask */
  611. /* External interrupts */
  612. intr_extint:
  613. get_stack
  614. save_specials %r29
  615. virt_map rfi
  616. save_general %r29
  617. ldo PT_FR0(%r29), %r24
  618. save_fp %r24
  619. loadgp
  620. copy %r29, %r24 /* arg2 is pt_regs */
  621. copy %r29, %r16 /* save pt_regs */
  622. #ifdef CONFIG_KWDB
  623. copy %r29, %r3 /* KWDB - update frame pointer (gr3) */
  624. #endif
  625. /* sorry to put this cruft in the interrupt path */
  626. ldil L%cpu_irq_region, %r25
  627. ldo R%cpu_irq_region(%r25), %r25
  628. bl do_irq_mask,%r2
  629. #ifdef __LP64__
  630. LDIL_FIXUP(%r25)
  631. #else
  632. nop
  633. #endif
  634. b intr_return
  635. nop
  636. /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
  637. .export         intr_save, code /* for os_hpmc */
  638. intr_save:
  639. get_stack
  640. save_specials %r29
  641. mfctl %cr20, %r1
  642. STREG %r1, PT_ISR(%r29)
  643. mfctl %cr21, %r1
  644. STREG %r1, PT_IOR(%r29)
  645. virt_map rfi
  646. save_general %r29
  647. ldo PT_FR0(%r29), %r25
  648. save_fp %r25
  649. loadgp
  650. copy %r29, %r25 /* arg1 is pt_regs */
  651. #ifdef CONFIG_KWDB
  652. copy %r29, %r3 /* KWDB - update frame pointer (gr3) */
  653. #endif
  654. bl handle_interruption,%r2
  655. copy %r29, %r16 /* save pt_regs */
  656. b intr_return
  657. nop
  658. /*
  659.  * Note for all tlb miss handlers:
  660.  *
  661.  * cr24 contains a pointer to the kernel address space
  662.  * page directory.
  663.  *
  664.  * cr25 contains a pointer to the current user address
  665.  * space page directory.
  666.  *
  667.  * sr3 will contain the space id of the user address space
  668.  * of the current running thread while that thread is
  669.  * running in the kernel.
  670.  */
  671. /*
  672.  * register number allocations.  Note that these are all
  673.  * in the shadowed registers
  674.  */
  675. t0 = r1 /* temporary register 0 */
  676. va = r8 /* virtual address for which the trap occured */
  677. t1 = r9 /* temporary register 1 */
  678. pte  = r16 /* pte/phys page # */
  679. prot = r17 /* prot bits */
  680. spc  = r24 /* space for which the trap occured */
  681. ptp = r25 /* page directory/page table pointer */
  682. #ifdef __LP64__
  683. dtlb_miss_20w:
  684. extrd,u         spc,31,7,t1     /* adjust va */
  685. depd            t1,31,7,va      /* adjust va */
  686. depdi           0,31,7,spc      /* adjust space */
  687. mfctl           %cr25,ptp /* Assume user space miss */
  688. or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
  689. mfctl           %cr24,ptp /* Load kernel pgd instead */
  690. extrd,u         va,33,9,t1      /* Get pgd index */
  691. mfsp            %sr7,t0 /* Get current space */
  692. or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
  693. comb,<>,n       t0,spc,dtlb_fault /* forward */
  694. /* First level page table lookup */
  695. ldd,s           t1(ptp),ptp
  696. extrd,u         va,42,9,t0     /* get second-level index */
  697. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dtlb_fault
  698. depdi           0,63,12,ptp     /* clear prot bits */
  699. /* Second level page table lookup */
  700. ldd,s           t0(ptp),ptp
  701. extrd,u         va,51,9,t0     /* get third-level index */
  702. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dtlb_fault
  703. depdi           0,63,12,ptp     /* clear prot bits */
  704. /* Third level page table lookup */
  705. shladd           t0,3,ptp,ptp
  706. ldi _PAGE_ACCESSED,t1
  707. ldd              0(ptp),pte
  708. bb,>=,n          pte,_PAGE_PRESENT_BIT,dtlb_fault
  709. /* Check whether the "accessed" bit was set, otherwise do so */
  710. or t1,pte,t0 /* t0 has R bit set */
  711. and,*<>         t1,pte,%r0      /* test and nullify if already set */
  712. std             t0,0(ptp)       /* write back pte */
  713. copy            spc,prot /* init prot with faulting space */
  714. depd pte,8,7,prot
  715. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  716. depdi 1,12,1,prot
  717. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  718. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  719. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  720. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  721. /* Get rid of prot bits and convert to page addr for idtlbt */
  722. depdi 0,63,12,pte
  723. extrd,u         pte,56,32,pte
  724. idtlbt %r16,%r17
  725. rfir
  726. nop
  727. #else
  728. dtlb_miss_11:
  729. mfctl           %cr25,ptp /* Assume user space miss */
  730. or,<>           %r0,spc,%r0 /* If it is user space, nullify */
  731. mfctl           %cr24,ptp /* Load kernel pgd instead */
  732. extru va,9,10,t1 /* Get pgd index */
  733. mfsp            %sr7,t0 /* Get current space */
  734. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  735. comb,<>,n       t0,spc,dtlb_fault /* forward */
  736. /* First level page table lookup */
  737. ldwx,s t1(ptp),ptp
  738. extru va,19,10,t0 /* get second-level index */
  739. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dtlb_fault
  740. depi 0,31,12,ptp /* clear prot bits */
  741. /* Second level page table lookup */
  742. sh2addl   t0,ptp,ptp
  743. ldi _PAGE_ACCESSED,t1
  744. ldw  0(ptp),pte
  745. bb,>=,n   pte,_PAGE_PRESENT_BIT,dtlb_fault
  746. /* Check whether the "accessed" bit was set, otherwise do so */
  747. or t1,pte,t0 /* t0 has R bit set */
  748. and,<> t1,pte,%r0 /* test and nullify if already set */
  749. stw t0,0(ptp) /* write back pte */
  750. copy            spc,prot /* init prot with faulting space */
  751. dep pte,8,7,prot
  752. extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
  753. depi 1,12,1,prot
  754. extru,=         pte,_PAGE_USER_BIT,1,r0
  755. depi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  756. extru,=  pte,_PAGE_GATEWAY_BIT,1,r0
  757. depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  758. /* Get rid of prot bits and convert to page addr for idtlba */
  759. depi 0,31,12,pte
  760. extru pte,24,25,pte
  761. mfsp %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
  762. mtsp spc,%sr1
  763. idtlba pte,(%sr1,va)
  764. idtlbp prot,(%sr1,va)
  765. mtsp t0, %sr1 /* Restore sr1 */
  766. rfir
  767. nop
  768. dtlb_miss_20:
  769. .level 2.0
  770. mfctl           %cr25,ptp /* Assume user space miss */
  771. or,<>           %r0,spc,%r0 /* If it is user space, nullify */
  772. mfctl           %cr24,ptp /* Load kernel pgd instead */
  773. extru va,9,10,t1 /* Get pgd index */
  774. mfsp            %sr7,t0 /* Get current space */
  775. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  776. comb,<>,n       t0,spc,dtlb_fault /* forward */
  777. /* First level page table lookup */
  778. ldwx,s t1(ptp),ptp
  779. extru va,19,10,t0 /* get second-level index */
  780. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dtlb_fault
  781. depi 0,31,12,ptp /* clear prot bits */
  782. /* Second level page table lookup */
  783. sh2addl   t0,ptp,ptp
  784. ldi _PAGE_ACCESSED,t1
  785. ldw  0(ptp),pte
  786. bb,>=,n   pte,_PAGE_PRESENT_BIT,dtlb_fault
  787. /* Check whether the "accessed" bit was set, otherwise do so */
  788. or t1,pte,t0 /* t0 has R bit set */
  789. and,<> t1,pte,%r0 /* test and nullify if already set */
  790. stw t0,0(ptp) /* write back pte */
  791. copy            spc,prot /* init prot with faulting space */
  792. depd pte,8,7,prot
  793. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  794. depdi 1,12,1,prot
  795. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  796. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  797. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  798. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  799. /* Get rid of prot bits and convert to page addr for idtlbt */
  800. depdi 0,63,12,pte
  801. extrd,u pte,56,25,pte
  802. idtlbt %r16,%r17
  803. .level 1.1
  804. rfir
  805. nop
  806. #endif
  807. #ifdef __LP64__
  808. itlb_miss_20w:
  809. /*
  810.  * I miss is a little different, since we allow users to fault
  811.  * on the gateway page which is in the kernel address space.
  812.  */
  813. extrd,u         spc,31,7,t1     /* adjust va */
  814. depd            t1,31,7,va      /* adjust va */
  815. depdi           0,31,7,spc      /* adjust space */
  816. cmpib,*=        0,spc,itlb_miss_kernel_20w
  817. extrd,u         va,33,9,t1      /* Get pgd index */
  818. mfctl           %cr25,ptp /* load user pgd */
  819. mfsp            %sr7,t0 /* Get current space */
  820. or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
  821. cmpb,*<>,n      t0,spc,itlb_fault /* forward */
  822. /* First level page table lookup */
  823. itlb_miss_common_20w:
  824. ldd,s           t1(ptp),ptp
  825. extrd,u         va,42,9,t0     /* get second-level index */
  826. bb,>=,n  ptp,_PAGE_PRESENT_BIT,itlb_fault
  827. depdi           0,63,12,ptp     /* clear prot bits */
  828. /* Second level page table lookup */
  829. ldd,s           t0(ptp),ptp
  830. extrd,u         va,51,9,t0     /* get third-level index */
  831. bb,>=,n         ptp,_PAGE_PRESENT_BIT,itlb_fault
  832. depdi           0,63,12,ptp     /* clear prot bits */
  833. /* Third level page table lookup */
  834. shladd           t0,3,ptp,ptp
  835. ldi _PAGE_ACCESSED,t1
  836. ldd              0(ptp),pte
  837. bb,>=,n          pte,_PAGE_PRESENT_BIT,itlb_fault
  838. /* Check whether the "accessed" bit was set, otherwise do so */
  839. or t1,pte,t0 /* t0 has R bit set */
  840. and,*<>         t1,pte,%r0      /* test and nullify if already set */
  841. std             t0,0(ptp)       /* write back pte */
  842. copy            spc,prot        /* init prot with faulting space */
  843. depd pte,8,7,prot
  844. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  845. depdi 1,12,1,prot
  846. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  847. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  848. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  849. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  850. /* Get rid of prot bits and convert to page addr for iitlbt */
  851. depdi 0,63,12,pte
  852. extrd,u         pte,56,32,pte
  853. iitlbt          %r16,%r17
  854. rfir
  855. nop
  856. itlb_miss_kernel_20w:
  857. b               itlb_miss_common_20w
  858. mfctl           %cr24,ptp /* Load kernel pgd */
  859. #else
  860. itlb_miss_11:
  861. /*
  862.  * I miss is a little different, since we allow users to fault
  863.  * on the gateway page which is in the kernel address space.
  864.  */
  865. comib,=         0,spc,itlb_miss_kernel_11
  866. extru va,9,10,t1 /* Get pgd index */
  867. mfctl           %cr25,ptp /* load user pgd */
  868. mfsp            %sr7,t0 /* Get current space */
  869. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  870. comb,<>,n       t0,spc,itlb_fault /* forward */
  871. /* First level page table lookup */
  872. itlb_miss_common_11:
  873. ldwx,s t1(ptp),ptp
  874. extru va,19,10,t0 /* get second-level index */
  875. bb,>=,n  ptp,_PAGE_PRESENT_BIT,itlb_fault
  876. depi 0,31,12,ptp /* clear prot bits */
  877. /* Second level page table lookup */
  878. sh2addl   t0,ptp,ptp
  879. ldi _PAGE_ACCESSED,t1
  880. ldw  0(ptp),pte
  881. bb,>=,n   pte,_PAGE_PRESENT_BIT,itlb_fault
  882. /* Check whether the "accessed" bit was set, otherwise do so */
  883. or t1,pte,t0 /* t0 has R bit set */
  884. and,<> t1,pte,%r0 /* test and nullify if already set */
  885. stw t0,0(ptp) /* write back pte */
  886. copy            spc,prot        /* init prot with faulting space */
  887. dep pte,8,7,prot
  888. extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
  889. depi 1,12,1,prot
  890. extru,=         pte,_PAGE_USER_BIT,1,r0
  891. depi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  892. extru,=  pte,_PAGE_GATEWAY_BIT,1,r0
  893. depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  894. /* Get rid of prot bits and convert to page addr for iitlba */
  895. depi 0,31,12,pte
  896. extru pte,24,25,pte
  897. mfsp %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
  898. mtsp spc,%sr1
  899. iitlba pte,(%sr1,va)
  900. iitlbp prot,(%sr1,va)
  901. mtsp t0, %sr1 /* Restore sr1 */
  902. rfir
  903. nop
  904. itlb_miss_kernel_11:
  905. b               itlb_miss_common_11
  906. mfctl           %cr24,ptp /* Load kernel pgd */
  907. itlb_miss_20:
  908. /*
  909.  * I miss is a little different, since we allow users to fault
  910.  * on the gateway page which is in the kernel address space.
  911.  */
  912. comib,=         0,spc,itlb_miss_kernel_20
  913. extru va,9,10,t1 /* Get pgd index */
  914. mfctl           %cr25,ptp /* load user pgd */
  915. mfsp            %sr7,t0 /* Get current space */
  916. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  917. comb,<>,n       t0,spc,itlb_fault /* forward */
  918. /* First level page table lookup */
  919. itlb_miss_common_20:
  920. ldwx,s t1(ptp),ptp
  921. extru va,19,10,t0 /* get second-level index */
  922. bb,>=,n  ptp,_PAGE_PRESENT_BIT,itlb_fault
  923. depi 0,31,12,ptp /* clear prot bits */
  924. /* Second level page table lookup */
  925. sh2addl   t0,ptp,ptp
  926. ldi _PAGE_ACCESSED,t1
  927. ldw  0(ptp),pte
  928. bb,>=,n   pte,_PAGE_PRESENT_BIT,itlb_fault
  929. /* Check whether the "accessed" bit was set, otherwise do so */
  930. or t1,pte,t0 /* t0 has R bit set */
  931. and,<> t1,pte,%r0 /* test and nullify if already set */
  932. stw t0,0(ptp) /* write back pte */
  933. copy            spc,prot        /* init prot with faulting space */
  934. .level 2.0
  935. depd pte,8,7,prot
  936. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  937. depdi 1,12,1,prot
  938. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  939. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  940. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  941. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  942. /* Get rid of prot bits and convert to page addr for iitlbt */
  943. depdi 0,63,12,pte
  944. extrd,u pte,56,25,pte
  945. iitlbt          %r16,%r17
  946. .level 1.1
  947. rfir
  948. nop
  949. itlb_miss_kernel_20:
  950. b               itlb_miss_common_20
  951. mfctl           %cr24,ptp /* Load kernel pgd */
  952. #endif
  953. #ifdef __LP64__
  954. dbit_trap_20w:
  955. extrd,u         spc,31,7,t1     /* adjust va */
  956. depd            t1,31,7,va      /* adjust va */
  957. depdi           0,1,2,va        /* adjust va */
  958. depdi           0,31,7,spc      /* adjust space */
  959. mfctl           %cr25,ptp /* Assume user space miss */
  960. or,*<>          %r0,spc,%r0     /* If it is user space, nullify */
  961. mfctl           %cr24,ptp /* Load kernel pgd instead */
  962. extrd,u         va,33,9,t1      /* Get pgd index */
  963. mfsp            %sr7,t0 /* Get current space */
  964. or,*=           %r0,t0,%r0      /* If kernel, nullify following test */
  965. comb,<>,n       t0,spc,dbit_fault /* forward */
  966. /* First level page table lookup */
  967. ldd,s           t1(ptp),ptp
  968. extrd,u         va,42,9,t0     /* get second-level index */
  969. bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
  970. depdi           0,63,12,ptp     /* clear prot bits */
  971. /* Second level page table lookup */
  972. ldd,s           t0(ptp),ptp
  973. extrd,u         va,51,9,t0     /* get third-level index */
  974. bb,>=,n         ptp,_PAGE_PRESENT_BIT,dbit_fault
  975. depdi           0,63,12,ptp     /* clear prot bits */
  976. /* Third level page table lookup */
  977. shladd           t0,3,ptp,ptp
  978. ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
  979. ldd              0(ptp),pte
  980. bb,>=,n          pte,_PAGE_PRESENT_BIT,dbit_fault
  981. /* Set Accessed and Dirty bits in the pte */
  982. or t1,pte,pte
  983. std             pte,0(ptp)      /* write back pte */
  984. copy            spc,prot /* init prot with faulting space */
  985. depd pte,8,7,prot
  986. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  987. depdi 1,12,1,prot
  988. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  989. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  990. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  991. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  992. /* Get rid of prot bits and convert to page addr for idtlbt */
  993. depdi 0,63,12,pte
  994. extrd,u         pte,56,32,pte
  995. idtlbt %r16,%r17
  996. rfir
  997. nop
  998. #else
  999. dbit_trap_11:
  1000. mfctl           %cr25,ptp /* Assume user space trap */
  1001. or,<>           %r0,spc,%r0 /* If it is user space, nullify */
  1002. mfctl           %cr24,ptp /* Load kernel pgd instead */
  1003. extru va,9,10,t1 /* Get pgd index */
  1004. mfsp            %sr7,t0 /* Get current space */
  1005. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  1006. comb,<>,n       t0,spc,dbit_fault /* forward */
  1007. /* First level page table lookup */
  1008. ldwx,s t1(ptp),ptp
  1009. extru va,19,10,t0 /* get second-level index */
  1010. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dbit_fault
  1011. depi 0,31,12,ptp /* clear prot bits */
  1012. /* Second level page table lookup */
  1013. sh2addl   t0,ptp,ptp
  1014. ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
  1015. ldw  0(ptp),pte
  1016. bb,>=,n   pte,_PAGE_PRESENT_BIT,dbit_fault
  1017. /* Set Accessed and Dirty bits in the pte */
  1018. or t1,pte,pte
  1019. stw pte,0(ptp) /* write back pte */
  1020. copy            spc,prot        /* init prot with faulting space */
  1021. dep pte,8,7,prot
  1022. extru,= pte,_PAGE_NO_CACHE_BIT,1,r0
  1023. depi 1,12,1,prot
  1024. extru,=         pte,_PAGE_USER_BIT,1,r0
  1025. depi 7,11,3,prot /* Set for user space (1 rsvd for read) */
  1026. extru,=  pte,_PAGE_GATEWAY_BIT,1,r0
  1027. depi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  1028. /* Get rid of prot bits and convert to page addr for idtlba */
  1029. depi 0,31,12,pte
  1030. extru pte,24,25,pte
  1031. mfsp %sr1,t0  /* Save sr1 so we can use it in tlb inserts */
  1032. mtsp spc,%sr1
  1033. idtlba pte,(%sr1,va)
  1034. idtlbp prot,(%sr1,va)
  1035. mtsp t0, %sr1     /* Restore sr1 */
  1036. rfir
  1037. nop
  1038. dbit_trap_20:
  1039. mfctl           %cr25,ptp /* Assume user space trap */
  1040. or,<>           %r0,spc,%r0 /* If it is user space, nullify */
  1041. mfctl           %cr24,ptp /* Load kernel pgd instead */
  1042. extru va,9,10,t1 /* Get pgd index */
  1043. mfsp            %sr7,t0 /* Get current space */
  1044. or,=            %r0,t0,%r0 /* If kernel, nullify following test */
  1045. comb,<>,n       t0,spc,dbit_fault /* forward */
  1046. /* First level page table lookup */
  1047. ldwx,s t1(ptp),ptp
  1048. extru va,19,10,t0 /* get second-level index */
  1049. bb,>=,n  ptp,_PAGE_PRESENT_BIT,dbit_fault
  1050. depi 0,31,12,ptp /* clear prot bits */
  1051. /* Second level page table lookup */
  1052. sh2addl   t0,ptp,ptp
  1053. ldi (_PAGE_ACCESSED|_PAGE_DIRTY),t1
  1054. ldw  0(ptp),pte
  1055. bb,>=,n   pte,_PAGE_PRESENT_BIT,dbit_fault
  1056. /* Set Accessed and Dirty bits in the pte */
  1057. or t1,pte,pte
  1058. stw pte,0(ptp) /* write back pte */
  1059. copy            spc,prot        /* init prot with faulting space */
  1060. .level 2.0
  1061. depd pte,8,7,prot
  1062. extrd,u,*= pte,_PAGE_NO_CACHE_BIT+32,1,r0
  1063. depdi 1,12,1,prot
  1064. extrd,u,*=      pte,_PAGE_USER_BIT+32,1,r0
  1065. depdi 7,11,3,prot   /* Set for user space (1 rsvd for read) */
  1066. extrd,u,*=  pte,_PAGE_GATEWAY_BIT+32,1,r0
  1067. depdi 0,11,2,prot /* If Gateway, Set PL2 to 0 */
  1068. /* Get rid of prot bits and convert to page addr for idtlbt */
  1069. depdi 0,63,12,pte
  1070. extrd,u pte,56,25,pte
  1071. idtlbt %r16,%r17
  1072. .level 1.1
  1073. rfir
  1074. nop
  1075. #endif
  1076. .import handle_interruption,code
  1077. kernel_bad_space:
  1078. b tlb_fault
  1079. ldi 31,%r1 /* Use an unused code */
  1080. dbit_fault:
  1081. b tlb_fault
  1082. ldi 20,%r1
  1083. itlb_fault:
  1084. b tlb_fault
  1085. ldi 6,%r1
  1086. dtlb_fault:
  1087. ldi 15,%r1
  1088. /* Fall Through */
  1089. tlb_fault:
  1090. mtctl %r1,%cr29
  1091. mtctl %r29,%cr31
  1092. get_stack
  1093. save_specials %r29 /* Note this saves a trashed r1 */
  1094. SAVE_CR (%cr20, PT_ISR(%r29))
  1095. SAVE_CR (%cr21, PT_IOR(%r29))
  1096. virt_map rfir
  1097. STREG %r1,PT_GR1(%r29) /* save good value after rfir */
  1098. save_general %r29
  1099. ldo PT_FR0(%r29), %r25
  1100. save_fp %r25
  1101. loadgp
  1102. copy %r29, %r25
  1103. bl handle_interruption, %r2
  1104. copy %r29, %r16
  1105. b intr_return
  1106. nop
  1107. /* Register saving semantics for system calls:
  1108.    %r1    clobbered by system call macro in userspace
  1109.    %r2    saved in PT_REGS by gateway page
  1110.    %r3  - %r18    preserved by C code (saved by signal code)
  1111.    %r19 - %r20    saved in PT_REGS by gateway page
  1112.    %r21 - %r22    non-standard syscall args
  1113.    stored in kernel stack by gateway page
  1114.    %r23 - %r26    arg3-arg0, saved in PT_REGS by gateway page
  1115.    %r27 - %r30    saved in PT_REGS by gateway page
  1116.    %r31    syscall return pointer
  1117.  */
  1118. /* Floating point registers (FIXME: what do we do with these?)
  1119.    %fr0  - %fr3    status/exception, not preserved
  1120.    %fr4  - %fr7    arguments
  1121.    %fr8  - %fr11   not preserved by C code
  1122.    %fr12 - %fr21   preserved by C code
  1123.    %fr22 - %fr31   not preserved by C code
  1124.  */
  1125. .macro reg_save regs
  1126. STREG %r3, PT_GR3(regs)
  1127. STREG %r4, PT_GR4(regs)
  1128. STREG %r5, PT_GR5(regs)
  1129. STREG %r6, PT_GR6(regs)
  1130. STREG %r7, PT_GR7(regs)
  1131. STREG %r8, PT_GR8(regs)
  1132. STREG %r9, PT_GR9(regs)
  1133. STREG   %r10,PT_GR10(regs)
  1134. STREG   %r11,PT_GR11(regs)
  1135. STREG   %r12,PT_GR12(regs)
  1136. STREG   %r13,PT_GR13(regs)
  1137. STREG   %r14,PT_GR14(regs)
  1138. STREG   %r15,PT_GR15(regs)
  1139. STREG   %r16,PT_GR16(regs)
  1140. STREG   %r17,PT_GR17(regs)
  1141. STREG   %r18,PT_GR18(regs)
  1142. .endm
  1143. .macro reg_restore regs
  1144. LDREG PT_GR3(regs), %r3
  1145. LDREG PT_GR4(regs), %r4
  1146. LDREG PT_GR5(regs), %r5
  1147. LDREG PT_GR6(regs), %r6
  1148. LDREG PT_GR7(regs), %r7
  1149. LDREG PT_GR8(regs), %r8
  1150. LDREG PT_GR9(regs), %r9
  1151. LDREG   PT_GR10(regs),%r10
  1152. LDREG   PT_GR11(regs),%r11
  1153. LDREG   PT_GR12(regs),%r12
  1154. LDREG   PT_GR13(regs),%r13
  1155. LDREG   PT_GR14(regs),%r14
  1156. LDREG   PT_GR15(regs),%r15
  1157. LDREG   PT_GR16(regs),%r16
  1158. LDREG   PT_GR17(regs),%r17
  1159. LDREG   PT_GR18(regs),%r18
  1160. .endm
  1161. .export sys_fork_wrapper
  1162. sys_fork_wrapper:
  1163. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
  1164. reg_save %r1
  1165. STREG %r2,-RP_OFFSET(%r30)
  1166. ldo FRAME_SIZE(%r30),%r30
  1167. /* These are call-clobbered registers and therefore
  1168.    also syscall-clobbered (we hope). */
  1169. STREG %r2,PT_GR19(%r1) /* save for child */
  1170. STREG %r30,PT_GR20(%r1)
  1171. ldil L%child_return, %r3
  1172. ldo R%child_return(%r3), %r3
  1173. LDIL_FIXUP(%r3)
  1174. STREG %r3,PT_GR21(%r1) /* save for child */
  1175. LDREG PT_GR30(%r1),%r25
  1176. copy %r1,%r24
  1177. bl sys_clone,%r2
  1178. ldi SIGCHLD,%r26
  1179. LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
  1180. wrapper_exit:
  1181. ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
  1182. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1    /* get pt regs */
  1183. reg_restore %r1
  1184. bv %r0(%r2)
  1185. nop
  1186. /* Set the return value for the child */
  1187. child_return:
  1188. LDREG TASK_PT_GR19-TASK_SZ_ALGN-128(%r30),%r2
  1189. b wrapper_exit
  1190. copy %r0,%r28
  1191. .export sys_clone_wrapper
  1192. sys_clone_wrapper:
  1193. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
  1194. reg_save %r1
  1195. STREG %r2,-RP_OFFSET(%r30)
  1196. ldo FRAME_SIZE(%r30),%r30
  1197. STREG %r30,PT_GR20(%r1)
  1198. ldil L%child_return,%r3
  1199. ldo R%child_return(%r3),%r3
  1200. LDIL_FIXUP(%r3)
  1201. bl sys_clone,%r2
  1202. STREG %r3,PT_GR21(%r1) /* save for child */
  1203. b wrapper_exit
  1204. LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
  1205. .export sys_vfork_wrapper
  1206. sys_vfork_wrapper:
  1207. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get pt regs */
  1208. reg_save %r1
  1209. STREG %r2,-RP_OFFSET(%r30)
  1210. ldo FRAME_SIZE(%r30),%r30
  1211. STREG %r30,PT_GR20(%r1)
  1212. ldil L%child_return,%r3
  1213. ldo R%child_return(%r3),%r3
  1214. LDIL_FIXUP(%r3)
  1215. STREG %r3,PT_GR21(%r1) /* save for child */
  1216. bl sys_vfork,%r2
  1217. copy %r1,%r26
  1218. b wrapper_exit
  1219. LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
  1220. .macro  execve_wrapper execve
  1221. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
  1222. /*
  1223.  * Do we need to save/restore r3-r18 here?
  1224.  * I don't think so. why would new thread need old
  1225.  * threads registers?
  1226.  */
  1227. /* %arg0 - %arg3 are already saved for us. */
  1228. STREG %r2,-RP_OFFSET(%r30)
  1229. ldo FRAME_SIZE(%r30),%r30
  1230. bl execve,%r2
  1231. copy %r1,%arg0
  1232. ldo -FRAME_SIZE(%r30),%r30
  1233. LDREG -RP_OFFSET(%r30),%r2
  1234. /* If exec succeeded we need to load the args */
  1235. ldo -1024(%r0),%r1
  1236. comb,>>= %r28,%r1,error_execve
  1237. copy %r2,%r19
  1238. error_execve:
  1239. bv %r0(%r19)
  1240. nop
  1241. .endm
  1242. .export sys_execve_wrapper
  1243. .import sys_execve
  1244. sys_execve_wrapper:
  1245. execve_wrapper sys_execve
  1246. #ifdef __LP64__
  1247. .export sys32_execve_wrapper
  1248. .import sys32_execve
  1249. sys32_execve_wrapper:
  1250. execve_wrapper sys32_execve
  1251. #endif
  1252. .export sys_rt_sigreturn_wrapper
  1253. sys_rt_sigreturn_wrapper:
  1254. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r26
  1255. /* Don't save regs, we are going to restore them from sigcontext. */
  1256. STREG %r2, -RP_OFFSET(%r30)
  1257. bl sys_rt_sigreturn,%r2
  1258. ldo FRAME_SIZE(%r30), %r30
  1259. ldo -FRAME_SIZE(%r30), %r30
  1260. LDREG -RP_OFFSET(%r30), %r2
  1261. /* FIXME: I think we need to restore a few more things here. */
  1262. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1     /* get pt regs */
  1263. reg_restore %r1
  1264. /* If the signal was received while the process was blocked on a
  1265.  * syscall, then r2 will take us to syscall_exit; otherwise r2 will
  1266.  * take us to syscall_exit_rfi and on to intr_return.
  1267.  */
  1268. bv %r0(%r2)
  1269. LDREG PT_GR28(%r1),%r28  /* reload original r28 for syscall_exit */
  1270. .export sys_sigaltstack_wrapper
  1271. sys_sigaltstack_wrapper:
  1272. /* Get the user stack pointer */
  1273. LDREG -TASK_SZ_ALGN-FRAME_SIZE+TASK_PT_GR30(%r30), %r24
  1274. STREG %r2, -RP_OFFSET(%r30)
  1275. bl do_sigaltstack,%r2
  1276. ldo FRAME_SIZE(%r30), %r30
  1277. ldo -FRAME_SIZE(%r30), %r30
  1278. LDREG -RP_OFFSET(%r30), %r2
  1279. bv %r0(%r2)
  1280. nop
  1281. .export sys_rt_sigsuspend_wrapper
  1282. sys_rt_sigsuspend_wrapper:
  1283. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30), %r24
  1284. reg_save %r24
  1285. STREG %r2, -RP_OFFSET(%r30)
  1286. bl sys_rt_sigsuspend,%r2
  1287. ldo FRAME_SIZE(%r30), %r30
  1288. ldo -FRAME_SIZE(%r30), %r30
  1289. LDREG -RP_OFFSET(%r30), %r2
  1290. ldo TASK_REGS-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1
  1291. reg_restore %r1
  1292. bv %r0(%r2)
  1293. nop
  1294. .export syscall_exit
  1295. syscall_exit:
  1296. /* NOTE: HP-UX syscalls also come through here
  1297.    after hpux_syscall_exit fixes up return
  1298.    values. */
  1299. /* NOTE: Not all syscalls exit this way.  rt_sigreturn will exit
  1300.  * via syscall_exit_rfi if the signal was received while the process
  1301.  * was running.  All traced processes will probably exit via
  1302.  * syscall_exit_rfi in the future.
  1303.  */
  1304. /* save return value now */
  1305. STREG     %r28,TASK_PT_GR28-TASK_SZ_ALGN-FRAME_SIZE(%r30)
  1306. syscall_check_bh:
  1307. /* #ifdef NOTNOW */
  1308. /* Check for software interrupts */
  1309. .import irq_stat,data
  1310. ldil    L%irq_stat,%r19
  1311. ldo     R%irq_stat(%r19),%r19
  1312. LDIL_FIXUP(%r19)
  1313. #ifdef CONFIG_SMP
  1314. /* sched.h: int processor */
  1315. ldw     TASK_PROCESSOR-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r20 /* get cpu # */
  1316. #if (IRQSTAT_SZ == 32)
  1317. dep     %r20,26,27,%r20 /* shift left 5 bits */
  1318. #else
  1319. #error IRQSTAT_SZ changed, fix dep
  1320. #endif /* IRQSTAT_SZ */
  1321. add     %r19,%r20,%r19
  1322. #endif /* CONFIG_SMP */
  1323. ldw     IRQSTAT_SI_ACTIVE(%r19),%r20 /* hardirq.h: unsigned int */
  1324. ldw     IRQSTAT_SI_MASK(%r19),%r19 /* hardirq.h: unsigned int */
  1325. and     %r19,%r20,%r20
  1326. comib,<>,n 0,%r20,syscall_do_softirq /* forward */
  1327. /* #endif */
  1328. syscall_check_resched:
  1329. /* check for reschedule */
  1330. LDREG  TASK_NEED_RESCHED-TASK_SZ_ALGN-FRAME_SIZE(%r30),%r19 /* long */
  1331. comib,<>,n 0,%r19,syscall_do_resched /* forward */
  1332. syscall_check_sig:
  1333. ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1         /* get task ptr */
  1334. /* check for pending signals */
  1335. ldw     TASK_SIGPENDING(%r1),%r19
  1336. comib,<>,n 0,%r19,syscall_do_signal  /* forward */
  1337. syscall_restore:
  1338. /* disable interrupts while dicking with the kernel stack, */
  1339. /* or life can become unpleasant */
  1340. rsm PSW_SM_I, %r20
  1341. LDREG TASK_PTRACE(%r1), %r19 /* Are we being ptraced? */
  1342. bb,<,n %r19,31,syscall_restore_rfi
  1343. LDREG TASK_PT_GR20(%r1),%r19
  1344. mtctl %r19, %cr27
  1345. LDREG TASK_PT_GR2(%r1),%r2    /* restore user rp */
  1346. LDREG TASK_PT_GR21(%r1),%r21
  1347. LDREG TASK_PT_GR22(%r1),%r22
  1348. LDREG TASK_PT_GR23(%r1),%r23
  1349. LDREG TASK_PT_GR24(%r1),%r24
  1350. LDREG TASK_PT_GR25(%r1),%r25
  1351. LDREG TASK_PT_GR26(%r1),%r26
  1352. LDREG TASK_PT_GR27(%r1),%r27    /* restore user dp */
  1353. LDREG TASK_PT_GR28(%r1),%r28    /* syscall return value */
  1354. LDREG TASK_PT_GR29(%r1),%r29
  1355. LDREG TASK_PT_GR30(%r1),%r30    /* restore user sp */
  1356. LDREG TASK_PT_GR31(%r1),%r31    /* restore syscall rp */
  1357. ldo TASK_PT_FR31(%r1),%r19    /* reload fpregs */
  1358. rest_fp %r19
  1359. LDREG TASK_PT_SAR(%r1),%r19    /* restore SAR */
  1360. mtsar %r19
  1361. LDREG TASK_PT_GR19(%r1),%r19
  1362. mtctl %r1,%cr30    /* intrhandler okay. */
  1363. mfsp %sr3,%r1    /* Get users space id */
  1364. mtsp %r1,%sr4    /* Restore sr4 */
  1365. mtsp %r1,%sr5    /* Restore sr5 */
  1366. mtsp %r1,%sr6    /* Restore sr6 */
  1367. depi 3,31,2,%r31    /* ensure return to user mode. */
  1368. mtsm %r20    /* restore irq state  */
  1369. mfctl %cr27,%r20
  1370. /*
  1371.  * Due to a dependency in the tlb miss handlers on sr7, it
  1372.  * is essential that sr7 get set in the delay slot.
  1373.  */
  1374. #ifdef __LP64__
  1375. /* Note the be (and mtsp) is executed in narrow mode. This is OK
  1376.  * for 32 bit processes, but won't work once we support 64 bit
  1377.  * processes.
  1378.  */
  1379. rsm PSW_SM_W, %r0
  1380. be 0(%sr3,%r31)    /* return to user space */
  1381. mtsp %r1,%sr7    /* Restore sr7 */
  1382. #else
  1383. be 0(%sr3,%r31)    /* return to user space */
  1384. mtsp %r1,%sr7    /* Restore sr7 */
  1385. #endif
  1386. /* We have to return via an RFI, so that PSW T and R bits can be set
  1387.  * appropriately.
  1388.  * This sets up pt_regs so we can return via intr_restore, which is not
  1389.  * the most efficient way of doing things, but it works.
  1390.  */
  1391. syscall_restore_rfi:
  1392. ldo -1(%r0),%r2    /* Set recovery cntr to -1 */
  1393. mtctl %r2,%cr0    /*   for immediate trap */
  1394. copy %r0,%r2    /* Create a reasonable PSW */
  1395. /* XXX W bit??? */
  1396. depi -1,13,1,%r2
  1397. depi -1,28,1,%r2
  1398. depi -1,30,1,%r2
  1399. depi -1,31,1,%r2
  1400. bb,<,n %r19,15,set_rbit    /* PT_SINGLESTEP */
  1401. bb,>=,n %r19,14,set_nobit    /* PT_BLOCKSTEP, see ptrace.c */
  1402. set_tbit:
  1403. depi -1,7,1,%r2
  1404. b,n set_nobit
  1405. set_rbit:
  1406. depi -1,27,1,%r2
  1407. set_nobit:
  1408. STREG %r2,TASK_PT_PSW(%r1)
  1409. STREG %r1,TASK_PT_CR30(%r1)
  1410. mfsp %sr0,%r2
  1411. STREG %r2,TASK_PT_SR0(%r1)
  1412. mfsp %sr1,%r2
  1413. STREG %r2,TASK_PT_SR1(%r1)
  1414. mfsp %sr2,%r2
  1415. STREG %r2,TASK_PT_SR2(%r1)
  1416. mfsp %sr3,%r2
  1417. STREG %r2,TASK_PT_SR3(%r1)
  1418. STREG %r2,TASK_PT_SR4(%r1)
  1419. STREG %r2,TASK_PT_SR5(%r1)
  1420. STREG %r2,TASK_PT_SR6(%r1)
  1421. STREG %r2,TASK_PT_SR7(%r1)
  1422. STREG %r2,TASK_PT_IASQ0(%r1)
  1423. STREG %r2,TASK_PT_IASQ1(%r1)
  1424. LDREG TASK_PT_GR31(%r1),%r2
  1425. depi 3,31,2,%r2    /* ensure return to user mode. */
  1426. STREG %r2,TASK_PT_IAOQ0(%r1)
  1427. ldo 4(%r2),%r2
  1428. STREG %r2,TASK_PT_IAOQ1(%r1)
  1429. ldo TASK_REGS(%r1),%r25
  1430. reg_save %r25    /* Save r3 to r18 */
  1431. copy %r25,%r16
  1432. b intr_restore
  1433. nop
  1434. .import do_softirq,code
  1435. syscall_do_softirq:
  1436. bl      do_softirq,%r2
  1437. nop
  1438. b       syscall_check_resched
  1439. ssm     PSW_SM_I, %r0  /* do_softirq returns with I bit off */
  1440. .import schedule,code
  1441. syscall_do_resched:
  1442. bl schedule,%r2
  1443. nop
  1444. b       syscall_check_bh  /* if resched, we start over again */
  1445. nop
  1446. .import do_signal,code
  1447. syscall_do_signal:
  1448. /* Save callee-save registers (for sigcontext).
  1449.    FIXME: After this point the process structure should be
  1450.    consistent with all the relevant state of the process
  1451.    before the syscall.  We need to verify this. */
  1452. ldo TASK_REGS(%r1), %r25 /* struct pt_regs *regs */
  1453. reg_save %r25
  1454. ldi 1, %r24 /* unsigned long in_syscall */
  1455. bl do_signal,%r2
  1456. copy %r0, %r26 /* sigset_t *oldset = NULL */
  1457. ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30), %r1     /* reload task ptr */
  1458. ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
  1459. reg_restore %r20
  1460. b,n     syscall_restore
  1461. #ifdef __LP64__
  1462. unimplemented_64bitirq:
  1463. ssm PSW_SM_Q+PSW_SM_I, %r0
  1464. /* indicate that we had an interrupt */
  1465. ldi 0x77, %r28
  1466. ldi 0x77, %r29
  1467. /* save interrupt registers in GRs for diagnosis */
  1468. mfctl %cr17, %r17
  1469. mfctl %cr18, %r18
  1470. mfctl %cr19, %r19
  1471. mfctl %cr20, %r20
  1472. mfctl %cr21, %r21
  1473. mfctl %cr22, %r22
  1474. b,n .
  1475. nop
  1476. #endif