syscall.S 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372
  1. /*
  2. * Linux/PA-RISC Project (http://www.parisc-linux.org/)
  3. *
  4. * System call entry code / Linux gateway page
  5. * Copyright (c) Matthew Wilcox 1999 <willy@infradead.org>
  6. * Licensed under the GNU GPL.
  7. * thanks to Philipp Rumpf, Mike Shaver and various others
  8. * sorry about the wall, puffin..
  9. */
  10. /*
  11. How does the Linux gateway page on PA-RISC work?
  12. ------------------------------------------------
  13. The Linux gateway page on PA-RISC is "special".
  14. It actually has PAGE_GATEWAY bits set (this is linux terminology; in parisc
  15. terminology it's Execute, promote to PL0) in the page map. So anything
  16. executing on this page executes with kernel level privilege (there's more to it
  17. than that: to have this happen, you also have to use a branch with a ,gate
  18. completer to activate the privilege promotion). The upshot is that everything
  19. that runs on the gateway page runs at kernel privilege but with the current
  20. user process address space (although you have access to kernel space via %sr2).
  21. For the 0x100 syscall entry, we redo the space registers to point to the kernel
  22. address space (preserving the user address space in %sr3), move to wide mode if
  23. required, save the user registers and branch into the kernel syscall entry
  24. point. For all the other functions, we execute at kernel privilege but don't
  25. flip address spaces. The basic upshot of this is that these code snippets are
  26. executed atomically (because the kernel can't be pre-empted) and they may
  27. perform architecturally forbidden (to PL3) operations (like setting control
  28. registers).
  29. */
  30. #include <asm/asm-offsets.h>
  31. #include <asm/unistd.h>
  32. #include <asm/errno.h>
  33. #include <asm/page.h>
  34. #include <asm/psw.h>
  35. #include <asm/thread_info.h>
  36. #include <asm/assembly.h>
  37. #include <asm/processor.h>
  38. #include <asm/cache.h>
  39. #include <asm/spinlock_types.h>
  40. #include <linux/linkage.h>
  41. /* We fill the empty parts of the gateway page with
  42. * something that will kill the kernel or a
  43. * userspace application.
  44. */
  45. #define KILL_INSN break 0,0
  46. .level PA_ASM_LEVEL
  47. .macro lws_pagefault_disable reg1,reg2
  48. mfctl %cr30, \reg2
  49. ldo TASK_PAGEFAULT_DISABLED(\reg2), \reg2
  50. ldw 0(%sr2,\reg2), \reg1
  51. ldo 1(\reg1), \reg1
  52. stw \reg1, 0(%sr2,\reg2)
  53. .endm
  54. .macro lws_pagefault_enable reg1,reg2
  55. mfctl %cr30, \reg2
  56. ldo TASK_PAGEFAULT_DISABLED(\reg2), \reg2
  57. ldw 0(%sr2,\reg2), \reg1
  58. ldo -1(\reg1), \reg1
  59. stw \reg1, 0(%sr2,\reg2)
  60. .endm
  61. /* raise exception if spinlock content is not zero or
  62. * __ARCH_SPIN_LOCK_UNLOCKED_VAL */
  63. .macro spinlock_check spin_val,tmpreg
  64. #ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
  65. ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmpreg
  66. andcm,= \spin_val, \tmpreg, %r0
  67. .word SPINLOCK_BREAK_INSN
  68. #endif
  69. .endm
  70. .text
  71. .import syscall_exit,code
  72. .import syscall_exit_rfi,code
  73. /* Linux gateway page is aliased to virtual page 0 in the kernel
  74. * address space. Since it is a gateway page it cannot be
  75. * dereferenced, so null pointers will still fault. We start
  76. * the actual entry point at 0x100. We put break instructions
  77. * at the beginning of the page to trap null indirect function
  78. * pointers.
  79. */
  80. .align PAGE_SIZE
  81. ENTRY(linux_gateway_page)
  82. /* ADDRESS 0x00 to 0xb0 = 176 bytes / 4 bytes per insn = 44 insns */
  83. .rept 44
  84. KILL_INSN
  85. .endr
  86. /* ADDRESS 0xb0 to 0xb8, lws uses two insns for entry */
  87. /* Light-weight-syscall entry must always be located at 0xb0 */
  88. /* WARNING: Keep this number updated with table size changes */
  89. #define __NR_lws_entries (5)
  90. lws_entry:
  91. gate lws_start, %r0 /* increase privilege */
  92. depi PRIV_USER, 31, 2, %r31 /* Ensure we return into user mode. */
  93. /* Fill from 0xb8 to 0xe0 */
  94. .rept 10
  95. KILL_INSN
  96. .endr
  97. /* This function MUST be located at 0xe0 for glibc's threading
  98. mechanism to work. DO NOT MOVE THIS CODE EVER! */
  99. set_thread_pointer:
  100. gate .+8, %r0 /* increase privilege */
  101. depi PRIV_USER, 31, 2, %r31 /* Ensure we return into user mode. */
  102. be 0(%sr7,%r31) /* return to user space */
  103. mtctl %r26, %cr27 /* move arg0 to the control register */
  104. /* Increase the chance of trapping if random jumps occur to this
  105. address, fill from 0xf0 to 0x100 */
  106. .rept 4
  107. KILL_INSN
  108. .endr
  109. /* This address must remain fixed at 0x100 for glibc's syscalls to work */
  110. .align LINUX_GATEWAY_ADDR
  111. linux_gateway_entry:
  112. gate .+8, %r0 /* become privileged */
  113. mtsp %r0,%sr4 /* get kernel space into sr4 */
  114. mtsp %r0,%sr5 /* get kernel space into sr5 */
  115. mtsp %r0,%sr6 /* get kernel space into sr6 */
  116. #ifdef CONFIG_64BIT
  117. /* Store W bit on entry to the syscall in case it's a wide userland
  118. * process. */
  119. ssm PSW_SM_W, %r1
  120. extrd,u %r1,PSW_W_BIT,1,%r1
  121. /* sp must be aligned on 4, so deposit the W bit setting into
  122. * the bottom of sp temporarily */
  123. or,ev %r1,%r30,%r30
  124. b,n 1f
  125. /* The top halves of argument registers must be cleared on syscall
  126. * entry from narrow executable.
  127. */
  128. depdi 0, 31, 32, %r26
  129. depdi 0, 31, 32, %r25
  130. depdi 0, 31, 32, %r24
  131. depdi 0, 31, 32, %r23
  132. depdi 0, 31, 32, %r22
  133. depdi 0, 31, 32, %r21
  134. 1:
  135. #endif
  136. /* We use a rsm/ssm pair to prevent sr3 from being clobbered
  137. * by external interrupts.
  138. */
  139. mfsp %sr7,%r1 /* save user sr7 */
  140. rsm PSW_SM_I, %r0 /* disable interrupts */
  141. mtsp %r1,%sr3 /* and store it in sr3 */
  142. mfctl %cr30,%r1
  143. xor %r1,%r30,%r30 /* ye olde xor trick */
  144. xor %r1,%r30,%r1
  145. xor %r1,%r30,%r30
  146. LDREG TASK_STACK(%r30),%r30 /* set up kernel stack */
  147. ldo FRAME_SIZE(%r30),%r30
  148. /* N.B.: It is critical that we don't set sr7 to 0 until r30
  149. * contains a valid kernel stack pointer. It is also
  150. * critical that we don't start using the kernel stack
  151. * until after sr7 has been set to 0.
  152. */
  153. mtsp %r0,%sr7 /* get kernel space into sr7 */
  154. ssm PSW_SM_I, %r0 /* enable interrupts */
  155. STREGM %r1,FRAME_SIZE(%r30) /* save r1 (usp) here for now */
  156. mfctl %cr30,%r1 /* get task ptr in %r1 */
  157. /* Save some registers for sigcontext and potential task
  158. switch (see entry.S for the details of which ones are
  159. saved/restored). TASK_PT_PSW is zeroed so we can see whether
  160. a process is on a syscall or not. For an interrupt the real
  161. PSW value is stored. This is needed for gdb and sys_ptrace. */
  162. STREG %r0, TASK_PT_PSW(%r1)
  163. STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */
  164. STREG %r19, TASK_PT_GR19(%r1)
  165. LDREGM -FRAME_SIZE(%r30), %r2 /* get users sp back */
  166. #ifdef CONFIG_64BIT
  167. extrd,u %r2,63,1,%r19 /* W hidden in bottom bit */
  168. #if 0
  169. xor %r19,%r2,%r2 /* clear bottom bit */
  170. depd,z %r19,1,1,%r19
  171. std %r19,TASK_PT_PSW(%r1)
  172. #endif
  173. #endif
  174. STREG %r2, TASK_PT_GR30(%r1) /* ... and save it */
  175. STREG %r20, TASK_PT_GR20(%r1) /* Syscall number */
  176. STREG %r21, TASK_PT_GR21(%r1)
  177. STREG %r22, TASK_PT_GR22(%r1)
  178. STREG %r23, TASK_PT_GR23(%r1) /* 4th argument */
  179. STREG %r24, TASK_PT_GR24(%r1) /* 3rd argument */
  180. STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */
  181. STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
  182. STREG %r27, TASK_PT_GR27(%r1) /* user dp */
  183. STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
  184. STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
  185. STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
  186. STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
  187. ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */
  188. save_fp %r27 /* or potential task switch */
  189. mfctl %cr11, %r27 /* i.e. SAR */
  190. STREG %r27, TASK_PT_SAR(%r1)
  191. loadgp
  192. #ifdef CONFIG_64BIT
  193. ldo -16(%r30),%r29 /* Reference param save area */
  194. copy %r19,%r2 /* W bit back to r2 */
  195. #else
  196. /* no need to save these on stack in wide mode because the first 8
  197. * args are passed in registers */
  198. stw %r22, -52(%r30) /* 5th argument */
  199. stw %r21, -56(%r30) /* 6th argument */
  200. #endif
  201. /* Are we being ptraced? */
  202. mfctl %cr30, %r1
  203. LDREG TASK_TI_FLAGS(%r1),%r1
  204. ldi _TIF_SYSCALL_TRACE_MASK, %r19
  205. and,COND(=) %r1, %r19, %r0
  206. b,n .Ltracesys
  207. /* Note! We cannot use the syscall table that is mapped
  208. nearby since the gateway page is mapped execute-only. */
  209. #ifdef CONFIG_64BIT
  210. ldil L%sys_call_table, %r1
  211. or,ev %r2,%r2,%r2
  212. ldil L%sys_call_table64, %r1
  213. ldo R%sys_call_table(%r1), %r19
  214. or,ev %r2,%r2,%r2
  215. ldo R%sys_call_table64(%r1), %r19
  216. #else
  217. load32 sys_call_table, %r19
  218. #endif
  219. comiclr,>> __NR_Linux_syscalls, %r20, %r0
  220. b,n .Lsyscall_nosys
  221. LDREGX %r20(%r19), %r19
  222. /* If this is a sys_rt_sigreturn call, and the signal was received
  223. * when not in_syscall, then we want to return via syscall_exit_rfi,
  224. * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
  225. * trampoline code in signal.c).
  226. */
  227. ldi __NR_rt_sigreturn,%r2
  228. comb,= %r2,%r20,.Lrt_sigreturn
  229. .Lin_syscall:
  230. ldil L%syscall_exit,%r2
  231. be 0(%sr7,%r19)
  232. ldo R%syscall_exit(%r2),%r2
  233. .Lrt_sigreturn:
  234. comib,<> 0,%r25,.Lin_syscall
  235. ldil L%syscall_exit_rfi,%r2
  236. be 0(%sr7,%r19)
  237. ldo R%syscall_exit_rfi(%r2),%r2
  238. /* Note! Because we are not running where we were linked, any
  239. calls to functions external to this file must be indirect. To
  240. be safe, we apply the opposite rule to functions within this
  241. file, with local labels given to them to ensure correctness. */
  242. .Lsyscall_nosys:
  243. syscall_nosys:
  244. ldil L%syscall_exit,%r1
  245. be R%syscall_exit(%sr7,%r1)
  246. ldo -ENOSYS(%r0),%r28 /* set errno */
  247. /* Warning! This trace code is a virtual duplicate of the code above so be
  248. * sure to maintain both! */
  249. .Ltracesys:
  250. tracesys:
  251. /* Need to save more registers so the debugger can see where we
  252. * are. This saves only the lower 8 bits of PSW, so that the C
  253. * bit is still clear on syscalls, and the D bit is set if this
  254. * full register save path has been executed. We check the D
  255. * bit on syscall_return_rfi to determine which registers to
  256. * restore. An interrupt results in a full PSW saved with the
  257. * C bit set, a non-straced syscall entry results in C and D clear
  258. * in the saved PSW.
  259. */
  260. mfctl %cr30,%r1 /* get task ptr */
  261. ssm 0,%r2
  262. STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */
  263. mfsp %sr0,%r2
  264. STREG %r2,TASK_PT_SR0(%r1)
  265. mfsp %sr1,%r2
  266. STREG %r2,TASK_PT_SR1(%r1)
  267. mfsp %sr2,%r2
  268. STREG %r2,TASK_PT_SR2(%r1)
  269. mfsp %sr3,%r2
  270. STREG %r2,TASK_PT_SR3(%r1)
  271. STREG %r2,TASK_PT_SR4(%r1)
  272. STREG %r2,TASK_PT_SR5(%r1)
  273. STREG %r2,TASK_PT_SR6(%r1)
  274. STREG %r2,TASK_PT_SR7(%r1)
  275. STREG %r2,TASK_PT_IASQ0(%r1)
  276. STREG %r2,TASK_PT_IASQ1(%r1)
  277. LDREG TASK_PT_GR31(%r1),%r2
  278. STREG %r2,TASK_PT_IAOQ0(%r1)
  279. ldo 4(%r2),%r2
  280. STREG %r2,TASK_PT_IAOQ1(%r1)
  281. ldo TASK_REGS(%r1),%r2
  282. /* reg_save %r2 */
  283. STREG %r3,PT_GR3(%r2)
  284. STREG %r4,PT_GR4(%r2)
  285. STREG %r5,PT_GR5(%r2)
  286. STREG %r6,PT_GR6(%r2)
  287. STREG %r7,PT_GR7(%r2)
  288. STREG %r8,PT_GR8(%r2)
  289. STREG %r9,PT_GR9(%r2)
  290. STREG %r10,PT_GR10(%r2)
  291. STREG %r11,PT_GR11(%r2)
  292. STREG %r12,PT_GR12(%r2)
  293. STREG %r13,PT_GR13(%r2)
  294. STREG %r14,PT_GR14(%r2)
  295. STREG %r15,PT_GR15(%r2)
  296. STREG %r16,PT_GR16(%r2)
  297. STREG %r17,PT_GR17(%r2)
  298. STREG %r18,PT_GR18(%r2)
  299. /* Finished saving things for the debugger */
  300. copy %r2,%r26
  301. ldil L%do_syscall_trace_enter,%r1
  302. ldil L%tracesys_next,%r2
  303. be R%do_syscall_trace_enter(%sr7,%r1)
  304. ldo R%tracesys_next(%r2),%r2
  305. tracesys_next:
  306. /* do_syscall_trace_enter either returned the syscallno, or -1L,
  307. * so we skip restoring the PT_GR20 below, since we pulled it from
  308. * task->thread.regs.gr[20] above.
  309. */
  310. copy %ret0,%r20
  311. mfctl %cr30,%r1 /* get task ptr */
  312. LDREG TASK_PT_GR28(%r1), %r28 /* Restore return value */
  313. LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
  314. LDREG TASK_PT_GR25(%r1), %r25
  315. LDREG TASK_PT_GR24(%r1), %r24
  316. LDREG TASK_PT_GR23(%r1), %r23
  317. LDREG TASK_PT_GR22(%r1), %r22
  318. LDREG TASK_PT_GR21(%r1), %r21
  319. #ifdef CONFIG_64BIT
  320. ldo -16(%r30),%r29 /* Reference param save area */
  321. #else
  322. stw %r22, -52(%r30) /* 5th argument */
  323. stw %r21, -56(%r30) /* 6th argument */
  324. #endif
  325. cmpib,COND(=),n -1,%r20,tracesys_exit /* seccomp may have returned -1 */
  326. comiclr,>> __NR_Linux_syscalls, %r20, %r0
  327. b,n .Ltracesys_nosys
  328. /* Note! We cannot use the syscall table that is mapped
  329. nearby since the gateway page is mapped execute-only. */
  330. #ifdef CONFIG_64BIT
  331. LDREG TASK_PT_GR30(%r1), %r19 /* get users sp back */
  332. extrd,u %r19,63,1,%r2 /* W hidden in bottom bit */
  333. ldil L%sys_call_table, %r1
  334. or,ev %r2,%r2,%r2
  335. ldil L%sys_call_table64, %r1
  336. ldo R%sys_call_table(%r1), %r19
  337. or,ev %r2,%r2,%r2
  338. ldo R%sys_call_table64(%r1), %r19
  339. #else
  340. load32 sys_call_table, %r19
  341. #endif
  342. LDREGX %r20(%r19), %r19
  343. /* If this is a sys_rt_sigreturn call, and the signal was received
  344. * when not in_syscall, then we want to return via syscall_exit_rfi,
  345. * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
  346. * trampoline code in signal.c).
  347. */
  348. ldi __NR_rt_sigreturn,%r2
  349. comb,= %r2,%r20,.Ltrace_rt_sigreturn
  350. .Ltrace_in_syscall:
  351. ldil L%tracesys_exit,%r2
  352. be 0(%sr7,%r19)
  353. ldo R%tracesys_exit(%r2),%r2
  354. .Ltracesys_nosys:
  355. ldo -ENOSYS(%r0),%r28 /* set errno */
  356. /* Do *not* call this function on the gateway page, because it
  357. makes a direct call to syscall_trace. */
  358. tracesys_exit:
  359. mfctl %cr30,%r1 /* get task ptr */
  360. #ifdef CONFIG_64BIT
  361. ldo -16(%r30),%r29 /* Reference param save area */
  362. #endif
  363. ldo TASK_REGS(%r1),%r26
  364. BL do_syscall_trace_exit,%r2
  365. STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
  366. mfctl %cr30,%r1 /* get task ptr */
  367. LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */
  368. ldil L%syscall_exit,%r1
  369. be,n R%syscall_exit(%sr7,%r1)
  370. .Ltrace_rt_sigreturn:
  371. comib,<> 0,%r25,.Ltrace_in_syscall
  372. ldil L%tracesys_sigexit,%r2
  373. be 0(%sr7,%r19)
  374. ldo R%tracesys_sigexit(%r2),%r2
  375. tracesys_sigexit:
  376. mfctl %cr30,%r1 /* get task ptr */
  377. #ifdef CONFIG_64BIT
  378. ldo -16(%r30),%r29 /* Reference param save area */
  379. #endif
  380. BL do_syscall_trace_exit,%r2
  381. ldo TASK_REGS(%r1),%r26
  382. ldil L%syscall_exit_rfi,%r1
  383. be,n R%syscall_exit_rfi(%sr7,%r1)
  384. /*********************************************************
  385. 32/64-bit Light-Weight-Syscall ABI
  386. * - Indicates a hint for userspace inline asm
  387. implementations.
  388. Syscall number (caller-saves)
  389. - %r20
  390. * In asm clobber.
  391. Argument registers (caller-saves)
  392. - %r26, %r25, %r24, %r23, %r22
  393. * In asm input.
  394. Return registers (caller-saves)
  395. - %r28 (return), %r21 (errno)
  396. * In asm output.
  397. Caller-saves registers
  398. - %r1, %r27, %r29
  399. - %r2 (return pointer)
  400. - %r31 (ble link register)
  401. * In asm clobber.
  402. Callee-saves registers
  403. - %r3-%r18
  404. - %r30 (stack pointer)
  405. * Not in asm clobber.
  406. If userspace is 32-bit:
  407. Callee-saves registers
  408. - %r19 (32-bit PIC register)
  409. Differences from 32-bit calling convention:
  410. - Syscall number in %r20
  411. - Additional argument register %r22 (arg4)
  412. - Callee-saves %r19.
  413. If userspace is 64-bit:
  414. Callee-saves registers
  415. - %r27 (64-bit PIC register)
  416. Differences from 64-bit calling convention:
  417. - Syscall number in %r20
  418. - Additional argument register %r22 (arg4)
  419. - Callee-saves %r27.
  420. Error codes returned by entry path:
  421. ENOSYS - r20 was an invalid LWS number.
  422. *********************************************************/
  423. lws_start:
  424. #ifdef CONFIG_64BIT
  425. ssm PSW_SM_W, %r1
  426. extrd,u %r1,PSW_W_BIT,1,%r1
  427. /* sp must be aligned on 4, so deposit the W bit setting into
  428. * the bottom of sp temporarily */
  429. or,od %r1,%r30,%r30
  430. /* Clip LWS number to a 32-bit value for 32-bit processes */
  431. depdi 0, 31, 32, %r20
  432. #endif
  433. /* Is the lws entry number valid? */
  434. comiclr,>> __NR_lws_entries, %r20, %r0
  435. b,n lws_exit_nosys
  436. /* Load table start */
  437. ldil L%lws_table, %r1
  438. ldo R%lws_table(%r1), %r28 /* Scratch use of r28 */
  439. LDREGX %r20(%sr2,r28), %r21 /* Scratch use of r21 */
  440. /* Jump to lws, lws table pointers already relocated */
  441. be,n 0(%sr2,%r21)
  442. lws_exit_noerror:
  443. lws_pagefault_enable %r1,%r21
  444. ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
  445. stw,ma %r21, 0(%sr2,%r20)
  446. ssm PSW_SM_I, %r0
  447. b lws_exit
  448. copy %r0, %r21
  449. lws_wouldblock:
  450. ssm PSW_SM_I, %r0
  451. ldo 2(%r0), %r28
  452. b lws_exit
  453. ldo -EAGAIN(%r0), %r21
  454. lws_pagefault:
  455. lws_pagefault_enable %r1,%r21
  456. ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
  457. stw,ma %r21, 0(%sr2,%r20)
  458. ssm PSW_SM_I, %r0
  459. ldo 3(%r0),%r28
  460. b lws_exit
  461. ldo -EAGAIN(%r0),%r21
  462. lws_fault:
  463. ldo 1(%r0),%r28
  464. b lws_exit
  465. ldo -EFAULT(%r0),%r21
  466. lws_exit_nosys:
  467. ldo -ENOSYS(%r0),%r21
  468. /* Fall through: Return to userspace */
  469. lws_exit:
  470. #ifdef CONFIG_64BIT
  471. /* decide whether to reset the wide mode bit
  472. *
  473. * For a syscall, the W bit is stored in the lowest bit
  474. * of sp. Extract it and reset W if it is zero */
  475. extrd,u,*<> %r30,63,1,%r1
  476. rsm PSW_SM_W, %r0
  477. /* now reset the lowest bit of sp if it was set */
  478. xor %r30,%r1,%r30
  479. #endif
  480. be,n 0(%sr7, %r31)
  481. /***************************************************
  482. Implementing 32bit CAS as an atomic operation:
  483. %r26 - Address to examine
  484. %r25 - Old value to check (old)
  485. %r24 - New value to set (new)
  486. %r28 - Return prev through this register.
  487. %r21 - Kernel error code
  488. %r21 returns the following error codes:
  489. EAGAIN - CAS is busy, ldcw failed, try again.
  490. EFAULT - Read or write failed.
  491. If EAGAIN is returned, %r28 indicates the busy reason:
  492. r28 == 1 - CAS is busy. lock contended.
  493. r28 == 2 - CAS is busy. ldcw failed.
  494. r28 == 3 - CAS is busy. page fault.
  495. Scratch: r20, r28, r1
  496. ****************************************************/
  497. /* ELF64 Process entry path */
  498. lws_compare_and_swap64:
  499. #ifdef CONFIG_64BIT
  500. b,n lws_compare_and_swap
  501. #else
  502. /* If we are not a 64-bit kernel, then we don't
  503. * have 64-bit input registers, and calling
  504. * the 64-bit LWS CAS returns ENOSYS.
  505. */
  506. b,n lws_exit_nosys
  507. #endif
  508. /* ELF32/ELF64 Process entry path */
  509. lws_compare_and_swap32:
  510. #ifdef CONFIG_64BIT
  511. /* Wide mode user process? */
  512. bb,<,n %sp, 31, lws_compare_and_swap
  513. /* Clip all the input registers for 32-bit processes */
  514. depdi 0, 31, 32, %r26
  515. depdi 0, 31, 32, %r25
  516. depdi 0, 31, 32, %r24
  517. #endif
  518. lws_compare_and_swap:
  519. /* Trigger memory reference interruptions without writing to memory */
  520. 1: ldw 0(%r26), %r28
  521. proberi (%r26), PRIV_USER, %r28
  522. comb,=,n %r28, %r0, lws_fault /* backwards, likely not taken */
  523. nop
  524. 2: stbys,e %r0, 0(%r26)
  525. /* Calculate 8-bit hash index from virtual address */
  526. extru_safe %r26, 27, 8, %r20
  527. /* Load start of lock table */
  528. ldil L%lws_lock_start, %r28
  529. ldo R%lws_lock_start(%r28), %r28
  530. /* Find lock to use, the hash index is one of 0 to
  531. 255, multiplied by 16 (keep it 16-byte aligned)
  532. and add to the lock table offset. */
  533. shlw %r20, 4, %r20
  534. add %r20, %r28, %r20
  535. rsm PSW_SM_I, %r0 /* Disable interrupts */
  536. /* Try to acquire the lock */
  537. LDCW 0(%sr2,%r20), %r28
  538. spinlock_check %r28, %r21
  539. comclr,<> %r0, %r28, %r0
  540. b,n lws_wouldblock
  541. /* Disable page faults to prevent sleeping in critical region */
  542. lws_pagefault_disable %r21,%r28
  543. /*
  544. prev = *addr;
  545. if ( prev == old )
  546. *addr = new;
  547. return prev;
  548. */
  549. /* NOTES:
  550. This all works because intr_do_signal
  551. and schedule both check the return iasq
  552. and see that we are on the kernel page
  553. so this process is never scheduled off
  554. or is ever sent any signal of any sort,
  555. thus it is wholly atomic from usrspace's
  556. perspective
  557. */
  558. /* The load and store could fail */
  559. 3: ldw 0(%r26), %r28
  560. sub,<> %r28, %r25, %r0
  561. 4: stw %r24, 0(%r26)
  562. b,n lws_exit_noerror
  563. /* A fault occurred on load or stbys,e store */
  564. 5: b,n lws_fault
  565. ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 5b-linux_gateway_page)
  566. ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 5b-linux_gateway_page)
  567. /* A page fault occurred in critical region */
  568. 6: b,n lws_pagefault
  569. ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 6b-linux_gateway_page)
  570. ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 6b-linux_gateway_page)
  571. /***************************************************
  572. New CAS implementation which uses pointers and variable size
  573. information. The value pointed by old and new MUST NOT change
  574. while performing CAS. The lock only protects the value at %r26.
  575. %r26 - Address to examine
  576. %r25 - Pointer to the value to check (old)
  577. %r24 - Pointer to the value to set (new)
  578. %r23 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
  579. %r28 - Return non-zero on failure
  580. %r21 - Kernel error code
  581. %r21 returns the following error codes:
  582. EAGAIN - CAS is busy, ldcw failed, try again.
  583. EFAULT - Read or write failed.
  584. If EAGAIN is returned, %r28 indicates the busy reason:
  585. r28 == 1 - CAS is busy. lock contended.
  586. r28 == 2 - CAS is busy. ldcw failed.
  587. r28 == 3 - CAS is busy. page fault.
  588. Scratch: r20, r22, r28, r29, r1, fr4 (32bit for 64bit CAS only)
  589. ****************************************************/
  590. lws_compare_and_swap_2:
  591. #ifdef CONFIG_64BIT
  592. /* Wide mode user process? */
  593. bb,<,n %sp, 31, cas2_begin
  594. /* Clip the input registers for 32-bit processes. We don't
  595. need to clip %r23 as we only use it for word operations */
  596. depdi 0, 31, 32, %r26
  597. depdi 0, 31, 32, %r25
  598. depdi 0, 31, 32, %r24
  599. #endif
  600. cas2_begin:
  601. /* Check the validity of the size pointer */
  602. subi,>>= 3, %r23, %r0
  603. b,n lws_exit_nosys
  604. /* Jump to the functions which will load the old and new values into
  605. registers depending on the their size */
  606. shlw %r23, 2, %r29
  607. blr %r29, %r0
  608. nop
  609. /* 8-bit load */
  610. 1: ldb 0(%r25), %r25
  611. b cas2_lock_start
  612. 2: ldb 0(%r24), %r24
  613. nop
  614. nop
  615. nop
  616. nop
  617. nop
  618. /* 16-bit load */
  619. 3: ldh 0(%r25), %r25
  620. b cas2_lock_start
  621. 4: ldh 0(%r24), %r24
  622. nop
  623. nop
  624. nop
  625. nop
  626. nop
  627. /* 32-bit load */
  628. 5: ldw 0(%r25), %r25
  629. b cas2_lock_start
  630. 6: ldw 0(%r24), %r24
  631. nop
  632. nop
  633. nop
  634. nop
  635. nop
  636. /* 64-bit load */
  637. #ifdef CONFIG_64BIT
  638. 7: ldd 0(%r25), %r25
  639. 8: ldd 0(%r24), %r24
  640. #else
  641. /* Load old value into r22/r23 - high/low */
  642. 7: ldw 0(%r25), %r22
  643. 8: ldw 4(%r25), %r23
  644. /* Load new value into fr4 for atomic store later */
  645. 9: flddx 0(%r24), %fr4
  646. #endif
  647. cas2_lock_start:
  648. /* Trigger memory reference interruptions without writing to memory */
  649. copy %r26, %r28
  650. depi_safe 0, 31, 2, %r28
  651. 10: ldw 0(%r28), %r1
  652. proberi (%r28), PRIV_USER, %r1
  653. comb,=,n %r1, %r0, lws_fault /* backwards, likely not taken */
  654. nop
  655. 11: stbys,e %r0, 0(%r28)
  656. /* Calculate 8-bit hash index from virtual address */
  657. extru_safe %r26, 27, 8, %r20
  658. /* Load start of lock table */
  659. ldil L%lws_lock_start, %r28
  660. ldo R%lws_lock_start(%r28), %r28
  661. /* Find lock to use, the hash index is one of 0 to
  662. 255, multiplied by 16 (keep it 16-byte aligned)
  663. and add to the lock table offset. */
  664. shlw %r20, 4, %r20
  665. add %r20, %r28, %r20
  666. rsm PSW_SM_I, %r0 /* Disable interrupts */
  667. /* Try to acquire the lock */
  668. LDCW 0(%sr2,%r20), %r28
  669. spinlock_check %r28, %r21
  670. comclr,<> %r0, %r28, %r0
  671. b,n lws_wouldblock
  672. /* Disable page faults to prevent sleeping in critical region */
  673. lws_pagefault_disable %r21,%r28
  674. /*
  675. prev = *addr;
  676. if ( prev == old )
  677. *addr = new;
  678. return prev;
  679. */
  680. /* NOTES:
  681. This all works because intr_do_signal
  682. and schedule both check the return iasq
  683. and see that we are on the kernel page
  684. so this process is never scheduled off
  685. or is ever sent any signal of any sort,
  686. thus it is wholly atomic from usrspace's
  687. perspective
  688. */
  689. /* Jump to the correct function */
  690. blr %r29, %r0
  691. /* Set %r28 as non-zero for now */
  692. ldo 1(%r0),%r28
  693. /* 8-bit CAS */
  694. 12: ldb 0(%r26), %r29
  695. sub,= %r29, %r25, %r0
  696. b,n lws_exit_noerror
  697. 13: stb %r24, 0(%r26)
  698. b lws_exit_noerror
  699. copy %r0, %r28
  700. nop
  701. nop
  702. /* 16-bit CAS */
  703. 14: ldh 0(%r26), %r29
  704. sub,= %r29, %r25, %r0
  705. b,n lws_exit_noerror
  706. 15: sth %r24, 0(%r26)
  707. b lws_exit_noerror
  708. copy %r0, %r28
  709. nop
  710. nop
  711. /* 32-bit CAS */
  712. 16: ldw 0(%r26), %r29
  713. sub,= %r29, %r25, %r0
  714. b,n lws_exit_noerror
  715. 17: stw %r24, 0(%r26)
  716. b lws_exit_noerror
  717. copy %r0, %r28
  718. nop
  719. nop
  720. /* 64-bit CAS */
  721. #ifdef CONFIG_64BIT
  722. 18: ldd 0(%r26), %r29
  723. sub,*= %r29, %r25, %r0
  724. b,n lws_exit_noerror
  725. 19: std %r24, 0(%r26)
  726. copy %r0, %r28
  727. #else
  728. /* Compare first word */
  729. 18: ldw 0(%r26), %r29
  730. sub,= %r29, %r22, %r0
  731. b,n lws_exit_noerror
  732. /* Compare second word */
  733. 19: ldw 4(%r26), %r29
  734. sub,= %r29, %r23, %r0
  735. b,n lws_exit_noerror
  736. /* Perform the store */
  737. 20: fstdx %fr4, 0(%r26)
  738. copy %r0, %r28
  739. #endif
  740. b lws_exit_noerror
  741. copy %r0, %r28
  742. /* A fault occurred on load or stbys,e store */
  743. 30: b,n lws_fault
  744. ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
  745. ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
  746. ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
  747. ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
  748. ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
  749. ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
  750. ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
  751. ASM_EXCEPTIONTABLE_ENTRY(8b-linux_gateway_page, 30b-linux_gateway_page)
  752. #ifndef CONFIG_64BIT
  753. ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 30b-linux_gateway_page)
  754. #endif
  755. ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 30b-linux_gateway_page)
  756. ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 30b-linux_gateway_page)
  757. /* A page fault occurred in critical region */
  758. 31: b,n lws_pagefault
  759. ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 31b-linux_gateway_page)
  760. ASM_EXCEPTIONTABLE_ENTRY(13b-linux_gateway_page, 31b-linux_gateway_page)
  761. ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
  762. ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
  763. ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
  764. ASM_EXCEPTIONTABLE_ENTRY(17b-linux_gateway_page, 31b-linux_gateway_page)
  765. ASM_EXCEPTIONTABLE_ENTRY(18b-linux_gateway_page, 31b-linux_gateway_page)
  766. ASM_EXCEPTIONTABLE_ENTRY(19b-linux_gateway_page, 31b-linux_gateway_page)
  767. #ifndef CONFIG_64BIT
  768. ASM_EXCEPTIONTABLE_ENTRY(20b-linux_gateway_page, 31b-linux_gateway_page)
  769. #endif
  770. /***************************************************
  771. LWS atomic exchange.
  772. %r26 - Exchange address
  773. %r25 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
  774. %r24 - Address of new value
  775. %r23 - Address of old value
  776. %r28 - Return non-zero on failure
  777. %r21 - Kernel error code
  778. %r21 returns the following error codes:
  779. EAGAIN - CAS is busy, ldcw failed, try again.
  780. EFAULT - Read or write failed.
  781. If EAGAIN is returned, %r28 indicates the busy reason:
  782. r28 == 1 - CAS is busy. lock contended.
  783. r28 == 2 - CAS is busy. ldcw failed.
  784. r28 == 3 - CAS is busy. page fault.
  785. Scratch: r20, r1
  786. ****************************************************/
  787. lws_atomic_xchg:
  788. #ifdef CONFIG_64BIT
  789. /* Wide mode user process? */
  790. bb,<,n %sp, 31, atomic_xchg_begin
  791. /* Clip the input registers for 32-bit processes. We don't
  792. need to clip %r23 as we only use it for word operations */
  793. depdi 0, 31, 32, %r26
  794. depdi 0, 31, 32, %r25
  795. depdi 0, 31, 32, %r24
  796. depdi 0, 31, 32, %r23
  797. #endif
  798. atomic_xchg_begin:
  799. /* Check the validity of the size pointer */
  800. subi,>>= 3, %r25, %r0
  801. b,n lws_exit_nosys
  802. /* Jump to the functions which will load the old and new values into
  803. registers depending on the their size */
  804. shlw %r25, 2, %r1
  805. blr %r1, %r0
  806. nop
  807. /* Perform exception checks */
  808. /* 8-bit exchange */
  809. 1: ldb 0(%r24), %r20
  810. proberi (%r24), PRIV_USER, %r20
  811. comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
  812. nop
  813. copy %r23, %r20
  814. depi_safe 0, 31, 2, %r20
  815. b atomic_xchg_start
  816. 2: stbys,e %r0, 0(%r20)
  817. /* 16-bit exchange */
  818. 3: ldh 0(%r24), %r20
  819. proberi (%r24), PRIV_USER, %r20
  820. comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
  821. nop
  822. copy %r23, %r20
  823. depi_safe 0, 31, 2, %r20
  824. b atomic_xchg_start
  825. 4: stbys,e %r0, 0(%r20)
  826. /* 32-bit exchange */
  827. 5: ldw 0(%r24), %r20
  828. proberi (%r24), PRIV_USER, %r20
  829. comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
  830. nop
  831. b atomic_xchg_start
  832. 6: stbys,e %r0, 0(%r23)
  833. nop
  834. nop
  835. /* 64-bit exchange */
  836. #ifdef CONFIG_64BIT
  837. 7: ldd 0(%r24), %r20
  838. proberi (%r24), PRIV_USER, %r20
  839. comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
  840. nop
  841. 8: stdby,e %r0, 0(%r23)
  842. #else
  843. 7: ldw 0(%r24), %r20
  844. 8: ldw 4(%r24), %r20
  845. proberi (%r24), PRIV_USER, %r20
  846. comb,=,n %r20, %r0, lws_fault /* backwards, likely not taken */
  847. nop
  848. copy %r23, %r20
  849. depi_safe 0, 31, 2, %r20
  850. 9: stbys,e %r0, 0(%r20)
  851. 10: stbys,e %r0, 4(%r20)
  852. #endif
  853. atomic_xchg_start:
  854. /* Trigger memory reference interruptions without writing to memory */
  855. copy %r26, %r28
  856. depi_safe 0, 31, 2, %r28
  857. 11: ldw 0(%r28), %r1
  858. 12: stbys,e %r0, 0(%r28)
  859. /* Calculate 8-bit hash index from virtual address */
  860. extru_safe %r26, 27, 8, %r20
  861. /* Load start of lock table */
  862. ldil L%lws_lock_start, %r28
  863. ldo R%lws_lock_start(%r28), %r28
  864. /* Find lock to use, the hash index is one of 0 to
  865. 255, multiplied by 16 (keep it 16-byte aligned)
  866. and add to the lock table offset. */
  867. shlw %r20, 4, %r20
  868. add %r20, %r28, %r20
  869. rsm PSW_SM_I, %r0 /* Disable interrupts */
  870. /* Try to acquire the lock */
  871. LDCW 0(%sr2,%r20), %r28
  872. spinlock_check %r28, %r21
  873. comclr,<> %r0, %r28, %r0
  874. b,n lws_wouldblock
  875. /* Disable page faults to prevent sleeping in critical region */
  876. lws_pagefault_disable %r21,%r28
  877. /* NOTES:
  878. This all works because intr_do_signal
  879. and schedule both check the return iasq
  880. and see that we are on the kernel page
  881. so this process is never scheduled off
  882. or is ever sent any signal of any sort,
  883. thus it is wholly atomic from userspace's
  884. perspective
  885. */
  886. /* Jump to the correct function */
  887. blr %r1, %r0
  888. /* Set %r28 as non-zero for now */
  889. ldo 1(%r0),%r28
  890. /* 8-bit exchange */
  891. 14: ldb 0(%r26), %r1
  892. 15: stb %r1, 0(%r23)
  893. 15: ldb 0(%r24), %r1
  894. 17: stb %r1, 0(%r26)
  895. b lws_exit_noerror
  896. copy %r0, %r28
  897. nop
  898. nop
  899. /* 16-bit exchange */
  900. 18: ldh 0(%r26), %r1
  901. 19: sth %r1, 0(%r23)
  902. 20: ldh 0(%r24), %r1
  903. 21: sth %r1, 0(%r26)
  904. b lws_exit_noerror
  905. copy %r0, %r28
  906. nop
  907. nop
  908. /* 32-bit exchange */
  909. 22: ldw 0(%r26), %r1
  910. 23: stw %r1, 0(%r23)
  911. 24: ldw 0(%r24), %r1
  912. 25: stw %r1, 0(%r26)
  913. b lws_exit_noerror
  914. copy %r0, %r28
  915. nop
  916. nop
  917. /* 64-bit exchange */
  918. #ifdef CONFIG_64BIT
  919. 26: ldd 0(%r26), %r1
  920. 27: std %r1, 0(%r23)
  921. 28: ldd 0(%r24), %r1
  922. 29: std %r1, 0(%r26)
  923. #else
  924. 26: flddx 0(%r26), %fr4
  925. 27: fstdx %fr4, 0(%r23)
  926. 28: flddx 0(%r24), %fr4
  927. 29: fstdx %fr4, 0(%r26)
  928. #endif
  929. b lws_exit_noerror
  930. copy %r0, %r28
  931. /* A fault occurred on load or stbys,e store */
  932. 30: b,n lws_fault
  933. ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
  934. ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
  935. ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
  936. ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
  937. ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
  938. ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
  939. ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
  940. ASM_EXCEPTIONTABLE_ENTRY(8b-linux_gateway_page, 30b-linux_gateway_page)
  941. #ifndef CONFIG_64BIT
  942. ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 30b-linux_gateway_page)
  943. ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 30b-linux_gateway_page)
  944. #endif
  945. ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 30b-linux_gateway_page)
  946. ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 30b-linux_gateway_page)
  947. /* A page fault occurred in critical region */
  948. 31: b,n lws_pagefault
  949. ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
  950. ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
  951. ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
  952. ASM_EXCEPTIONTABLE_ENTRY(17b-linux_gateway_page, 31b-linux_gateway_page)
  953. ASM_EXCEPTIONTABLE_ENTRY(18b-linux_gateway_page, 31b-linux_gateway_page)
  954. ASM_EXCEPTIONTABLE_ENTRY(19b-linux_gateway_page, 31b-linux_gateway_page)
  955. ASM_EXCEPTIONTABLE_ENTRY(20b-linux_gateway_page, 31b-linux_gateway_page)
  956. ASM_EXCEPTIONTABLE_ENTRY(21b-linux_gateway_page, 31b-linux_gateway_page)
  957. ASM_EXCEPTIONTABLE_ENTRY(22b-linux_gateway_page, 31b-linux_gateway_page)
  958. ASM_EXCEPTIONTABLE_ENTRY(23b-linux_gateway_page, 31b-linux_gateway_page)
  959. ASM_EXCEPTIONTABLE_ENTRY(24b-linux_gateway_page, 31b-linux_gateway_page)
  960. ASM_EXCEPTIONTABLE_ENTRY(25b-linux_gateway_page, 31b-linux_gateway_page)
  961. ASM_EXCEPTIONTABLE_ENTRY(26b-linux_gateway_page, 31b-linux_gateway_page)
  962. ASM_EXCEPTIONTABLE_ENTRY(27b-linux_gateway_page, 31b-linux_gateway_page)
  963. ASM_EXCEPTIONTABLE_ENTRY(28b-linux_gateway_page, 31b-linux_gateway_page)
  964. ASM_EXCEPTIONTABLE_ENTRY(29b-linux_gateway_page, 31b-linux_gateway_page)
  965. /***************************************************
  966. LWS atomic store.
  967. %r26 - Address to store
  968. %r25 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
  969. %r24 - Address of value to store
  970. %r28 - Return non-zero on failure
  971. %r21 - Kernel error code
  972. %r21 returns the following error codes:
  973. EAGAIN - CAS is busy, ldcw failed, try again.
  974. EFAULT - Read or write failed.
  975. If EAGAIN is returned, %r28 indicates the busy reason:
  976. r28 == 1 - CAS is busy. lock contended.
  977. r28 == 2 - CAS is busy. ldcw failed.
  978. r28 == 3 - CAS is busy. page fault.
  979. Scratch: r20, r1
  980. ****************************************************/
  981. lws_atomic_store:
  982. #ifdef CONFIG_64BIT
  983. /* Wide mode user process? */
  984. bb,<,n %sp, 31, atomic_store_begin
  985. /* Clip the input registers for 32-bit processes. We don't
  986. need to clip %r23 as we only use it for word operations */
  987. depdi 0, 31, 32, %r26
  988. depdi 0, 31, 32, %r25
  989. depdi 0, 31, 32, %r24
  990. #endif
  991. atomic_store_begin:
  992. /* Check the validity of the size pointer */
  993. subi,>>= 3, %r25, %r0
  994. b,n lws_exit_nosys
  995. shlw %r25, 1, %r1
  996. blr %r1, %r0
  997. nop
  998. /* Perform exception checks */
  999. /* 8-bit store */
  1000. 1: ldb 0(%r24), %r20
  1001. b,n atomic_store_start
  1002. nop
  1003. nop
  1004. /* 16-bit store */
  1005. 2: ldh 0(%r24), %r20
  1006. b,n atomic_store_start
  1007. nop
  1008. nop
  1009. /* 32-bit store */
  1010. 3: ldw 0(%r24), %r20
  1011. b,n atomic_store_start
  1012. nop
  1013. nop
  1014. /* 64-bit store */
  1015. #ifdef CONFIG_64BIT
  1016. 4: ldd 0(%r24), %r20
  1017. #else
  1018. 4: ldw 0(%r24), %r20
  1019. 5: ldw 4(%r24), %r20
  1020. #endif
  1021. atomic_store_start:
  1022. /* Trigger memory reference interruptions without writing to memory */
  1023. copy %r26, %r28
  1024. depi_safe 0, 31, 2, %r28
  1025. 6: ldw 0(%r28), %r1
  1026. 7: stbys,e %r0, 0(%r28)
  1027. /* Calculate 8-bit hash index from virtual address */
  1028. extru_safe %r26, 27, 8, %r20
  1029. /* Load start of lock table */
  1030. ldil L%lws_lock_start, %r28
  1031. ldo R%lws_lock_start(%r28), %r28
  1032. /* Find lock to use, the hash index is one of 0 to
  1033. 255, multiplied by 16 (keep it 16-byte aligned)
  1034. and add to the lock table offset. */
  1035. shlw %r20, 4, %r20
  1036. add %r20, %r28, %r20
  1037. rsm PSW_SM_I, %r0 /* Disable interrupts */
  1038. /* Try to acquire the lock */
  1039. LDCW 0(%sr2,%r20), %r28
  1040. spinlock_check %r28, %r21
  1041. comclr,<> %r0, %r28, %r0
  1042. b,n lws_wouldblock
  1043. /* Disable page faults to prevent sleeping in critical region */
  1044. lws_pagefault_disable %r21,%r28
  1045. /* NOTES:
  1046. This all works because intr_do_signal
  1047. and schedule both check the return iasq
  1048. and see that we are on the kernel page
  1049. so this process is never scheduled off
  1050. or is ever sent any signal of any sort,
  1051. thus it is wholly atomic from userspace's
  1052. perspective
  1053. */
  1054. /* Jump to the correct function */
  1055. blr %r1, %r0
  1056. /* Set %r28 as non-zero for now */
  1057. ldo 1(%r0),%r28
  1058. /* 8-bit store */
  1059. 9: ldb 0(%r24), %r1
  1060. 10: stb %r1, 0(%r26)
  1061. b lws_exit_noerror
  1062. copy %r0, %r28
  1063. /* 16-bit store */
  1064. 11: ldh 0(%r24), %r1
  1065. 12: sth %r1, 0(%r26)
  1066. b lws_exit_noerror
  1067. copy %r0, %r28
  1068. /* 32-bit store */
  1069. 13: ldw 0(%r24), %r1
  1070. 14: stw %r1, 0(%r26)
  1071. b lws_exit_noerror
  1072. copy %r0, %r28
  1073. /* 64-bit store */
  1074. #ifdef CONFIG_64BIT
  1075. 15: ldd 0(%r24), %r1
  1076. 16: std %r1, 0(%r26)
  1077. #else
  1078. 15: flddx 0(%r24), %fr4
  1079. 16: fstdx %fr4, 0(%r26)
  1080. #endif
  1081. b lws_exit_noerror
  1082. copy %r0, %r28
  1083. /* A fault occurred on load or stbys,e store */
  1084. 30: b,n lws_fault
  1085. ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
  1086. ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
  1087. ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
  1088. ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
  1089. #ifndef CONFIG_64BIT
  1090. ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
  1091. #endif
  1092. ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
  1093. ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
  1094. /* A page fault occurred in critical region */
  1095. 31: b,n lws_pagefault
  1096. ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 31b-linux_gateway_page)
  1097. ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 31b-linux_gateway_page)
  1098. ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 31b-linux_gateway_page)
  1099. ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 31b-linux_gateway_page)
  1100. ASM_EXCEPTIONTABLE_ENTRY(13b-linux_gateway_page, 31b-linux_gateway_page)
  1101. ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
  1102. ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
  1103. ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
  1104. /* Make sure nothing else is placed on this page */
  1105. .align PAGE_SIZE
  1106. END(linux_gateway_page)
  1107. ENTRY(end_linux_gateway_page)
  1108. /* Relocate symbols assuming linux_gateway_page is mapped
  1109. to virtual address 0x0 */
  1110. #define LWS_ENTRY(_name_) ASM_ULONG_INSN (lws_##_name_ - linux_gateway_page)
  1111. .section .rodata,"a"
  1112. .align 8
  1113. /* Light-weight-syscall table */
  1114. /* Start of lws table. */
  1115. ENTRY(lws_table)
  1116. LWS_ENTRY(compare_and_swap32) /* 0 - ELF32 Atomic 32bit CAS */
  1117. LWS_ENTRY(compare_and_swap64) /* 1 - ELF64 Atomic 32bit CAS */
  1118. LWS_ENTRY(compare_and_swap_2) /* 2 - Atomic 64bit CAS */
  1119. LWS_ENTRY(atomic_xchg) /* 3 - Atomic Exchange */
  1120. LWS_ENTRY(atomic_store) /* 4 - Atomic Store */
  1121. END(lws_table)
  1122. /* End of lws table */
  1123. #ifdef CONFIG_64BIT
  1124. #define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, compat)
  1125. #else
  1126. #define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
  1127. #endif
  1128. #define __SYSCALL(nr, entry) ASM_ULONG_INSN entry
  1129. .align 8
  1130. ENTRY(sys_call_table)
  1131. .export sys_call_table,data
  1132. #include <asm/syscall_table_32.h> /* 32-bit syscalls */
  1133. END(sys_call_table)
  1134. #ifdef CONFIG_64BIT
  1135. #undef __SYSCALL_WITH_COMPAT
  1136. #define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
  1137. .align 8
  1138. ENTRY(sys_call_table64)
  1139. #include <asm/syscall_table_64.h> /* 64-bit syscalls */
  1140. END(sys_call_table64)
  1141. #endif
  1142. /*
  1143. All light-weight-syscall atomic operations
  1144. will use this set of locks
  1145. NOTE: The lws_lock_start symbol must be
  1146. at least 16-byte aligned for safe use
  1147. with ldcw.
  1148. */
  1149. .section .data
  1150. .align L1_CACHE_BYTES
  1151. ENTRY(lws_lock_start)
  1152. /* lws locks */
  1153. .rept 256
  1154. /* Keep locks aligned at 16-bytes */
  1155. .word __ARCH_SPIN_LOCK_UNLOCKED_VAL
  1156. .word 0
  1157. .word 0
  1158. .word 0
  1159. .endr
  1160. END(lws_lock_start)
  1161. .previous
  1162. .end