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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* 
  2.  * HPMC (High Priority Machine Check) handler.
  3.  *
  4.  * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
  5.  * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
  6.  * Copyright (C) 2000 Hewlett-Packard (John Marvin)
  7.  *
  8.  *    This program is free software; you can redistribute it and/or modify
  9.  *    it under the terms of the GNU General Public License as published by
  10.  *    the Free Software Foundation; either version 2, or (at your option)
  11.  *    any later version.
  12.  *
  13.  *    This program is distributed in the hope that it will be useful,
  14.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *    GNU General Public License for more details.
  17.  *
  18.  *    You should have received a copy of the GNU General Public License
  19.  *    along with this program; if not, write to the Free Software
  20.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22. /*
  23.  * This HPMC handler retrieves the HPMC pim data, resets IO and
  24.  * returns to the default trap handler with code set to 1 (HPMC).
  25.  * The default trap handler calls handle interruption, which
  26.  * does a stack and register dump. This at least allows kernel
  27.  * developers to get back to C code in virtual mode, where they
  28.  * have the option to examine and print values from memory that
  29.  * would help in debugging an HPMC caused by a software bug.
  30.  *
  31.  * There is more to do here:
  32.  *
  33.  *      1) On MP systems we need to synchronize processors
  34.  *         before calling pdc/iodc.
  35.  *      2) We should be checking the system state and not
  36.  *         returning to the fault handler if things are really
  37.  *         bad.
  38.  *
  39.  */
  40. .level 1.1
  41. .data
  42. #define __ASSEMBLY__
  43. #include <asm/assembly.h>
  44. #include <asm/pdc.h>
  45. /*
  46.  * stack for os_hpmc, the HPMC handler.
  47.  * buffer for IODC procedures (for the HPMC handler).
  48.  *
  49.  * IODC requires 7K byte stack.  That leaves 1K byte for os_hpmc.
  50.  */
  51. .align 4096
  52. hpmc_stack:
  53. .block 16384
  54. #define HPMC_IODC_BUF_SIZE 0x8000
  55. .align 4096
  56. hpmc_iodc_buf:
  57. .block HPMC_IODC_BUF_SIZE
  58. .align 8
  59. hpmc_raddr:
  60. .block 128
  61. #define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
  62. .export hpmc_pim_data, data
  63. .align 8
  64. hpmc_pim_data:
  65. .block HPMC_PIM_DATA_SIZE
  66. .text
  67. .export os_hpmc, code
  68. .import intr_save, code
  69. os_hpmc:
  70. /*
  71.  * registers modified:
  72.  *
  73.  *   Using callee saves registers without saving them.  The
  74.  *   original values are in the pim dump if we need them.
  75.  *
  76.  *   r2   (rp)  return pointer
  77.  *   r3   address of PDCE_PROC
  78.  *   r4   scratch
  79.  *   r5   scratch
  80.  *   r23  (arg3) procedure arg
  81.  *   r24  (arg2) procedure arg
  82.  *   r25  (arg1) procedure arg
  83.  *   r26  (arg0) procedure arg
  84.  *   r30  (sp)   stack pointer
  85.  *
  86.  * registers read:
  87.  *
  88.  *   r26  contains address of PDCE_PROC on entry
  89.  *   r28  (ret0) return value from procedure
  90.  */
  91. copy    arg0, %r3       /* save address of PDCE_PROC */
  92. /*
  93.  *  disable nested HPMCs
  94.  *
  95.  * Increment os_hpmc checksum to invalidate it.
  96.  * Do this before turning the PSW M bit off.
  97.  */
  98. mfctl   %cr14, %r4
  99. ldw     52(%r4),%r5
  100. addi    1,%r5,%r5
  101. stw     %r5,52(%r4)
  102. /* MP_FIXME: synchronize all processors. */
  103. /* Setup stack pointer. */
  104. ldil    L%PA(hpmc_stack),sp
  105. ldo     R%PA(hpmc_stack)(sp),sp
  106. ldo     128(sp),sp /* leave room for arguments */
  107. /*
  108.  * Most PDC routines require that the M bit be off.
  109.  * So turn on the Q bit and turn off the M bit.
  110.  */
  111. ldo     8(%r0),%r4                       /* PSW Q on, PSW M off */
  112. mtctl   %r4,ipsw
  113. mtctl   %r0,pcsq
  114. mtctl   %r0,pcsq
  115. ldil    L%PA(os_hpmc_1),%r4
  116. ldo     R%PA(os_hpmc_1)(%r4),%r4
  117. mtctl   %r4,pcoq
  118. ldo     4(%r4),%r4
  119. mtctl   %r4,pcoq
  120. rfi
  121. nop
  122. os_hpmc_1:
  123. /* Call PDC_PIM to get HPMC pim info */
  124. /*
  125.  * Note that on some newer boxes, PDC_PIM must be called
  126.  * before PDC_IO if you want IO to be reset. PDC_PIM sets
  127.  * a flag that PDC_IO examines.
  128.  */
  129. ldo     PDC_PIM(%r0), arg0
  130. ldo     PDC_PIM_HPMC(%r0),arg1          /* Transfer HPMC data */
  131. ldil    L%PA(hpmc_raddr),arg2
  132. ldo     R%PA(hpmc_raddr)(arg2),arg2
  133. ldil    L%PA(hpmc_pim_data),arg3
  134. ldo     R%PA(hpmc_pim_data)(arg3),arg3
  135. ldil    L%HPMC_PIM_DATA_SIZE,%r4
  136. ldo     R%HPMC_PIM_DATA_SIZE(%r4),%r4
  137. stw     %r4,-52(sp)
  138. ldil    L%PA(os_hpmc_2), rp
  139. bv      (r3)                            /* call pdce_proc */
  140. ldo     R%PA(os_hpmc_2)(rp), rp
  141. os_hpmc_2:
  142. comib,<>  0,ret0, os_hpmc_fail
  143. /* Reset IO by calling the hversion dependent PDC_IO routine */
  144. ldo     PDC_IO(%r0),arg0
  145. ldo     0(%r0),arg1                     /* log IO errors */
  146. ldo     0(%r0),arg2                     /* reserved */
  147. ldo     0(%r0),arg3                     /* reserved */
  148. stw     %r0,-52(sp)                     /* reserved */
  149. ldil    L%PA(os_hpmc_3),rp
  150. bv      (%r3)                           /* call pdce_proc */
  151. ldo     R%PA(os_hpmc_3)(rp),rp
  152. os_hpmc_3:
  153. /* FIXME? Check for errors from PDC_IO (-1 might be OK) */
  154. /*
  155.  * Initialize the IODC console device (HPA,SPA, path etc.
  156.  * are stored on page 0.
  157.  */
  158. /*
  159.  * Load IODC into hpmc_iodc_buf by calling PDC_IODC.
  160.  * Note that PDC_IODC handles flushing the appropriate
  161.  * data and instruction cache lines.
  162.  */
  163. ldo     PDC_IODC(%r0),arg0
  164. ldo     PDC_IODC_READ(%r0),arg1
  165. ldil    L%PA(hpmc_raddr),arg2
  166. ldo     R%PA(hpmc_raddr)(arg2),arg2
  167. ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
  168. ldo     PDC_IODC_RI_INIT(%r0),%r4
  169. stw     %r4,-52(sp)
  170. ldil    L%PA(hpmc_iodc_buf),%r4
  171. ldo     R%PA(hpmc_iodc_buf)(%r4),%r4
  172. stw     %r4,-56(sp)
  173. ldil    L%HPMC_IODC_BUF_SIZE,%r4
  174. ldo     R%HPMC_IODC_BUF_SIZE(%r4),%r4
  175. stw     %r4,-60(sp)
  176. ldil    L%PA(os_hpmc_4),rp
  177. bv      (%r3)                            /* call pdce_proc */
  178. ldo     R%PA(os_hpmc_4)(rp),rp
  179. os_hpmc_4:
  180. comib,<>  0,ret0,os_hpmc_fail
  181. /* Call the entry init (just loaded by PDC_IODC) */
  182. ldw     BOOT_CONSOLE_HPA_OFFSET(%r0),arg0  /* console hpa */
  183. ldo     ENTRY_INIT_MOD_DEV(%r0), arg1
  184. ldw     BOOT_CONSOLE_SPA_OFFSET(%r0),arg2  /* console spa */
  185. depi    0,31,11,arg2                       /* clear bits 21-31    */
  186. ldo     BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
  187. ldil    L%PA(hpmc_raddr),%r4
  188. ldo     R%PA(hpmc_raddr)(%r4),%r4
  189. stw     %r4, -52(sp)
  190. stw     %r0, -56(sp)                    /* HV                  */
  191. stw     %r0, -60(sp)                    /* HV                  */
  192. stw     %r0, -64(sp)                    /* HV                  */
  193. stw     %r0, -68(sp)                    /* lang, must be zero  */
  194. ldil    L%PA(hpmc_iodc_buf),%r5
  195. ldo     R%PA(hpmc_iodc_buf)(%r5),%r5
  196. ldil    L%PA(os_hpmc_5),rp
  197. bv      (%r5)
  198. ldo     R%PA(os_hpmc_5)(rp),rp
  199. os_hpmc_5:
  200. comib,<>  0,ret0,os_hpmc_fail
  201. /* Prepare to call intr_save */
  202. /*
  203.  * Load kernel page directory (load into user also, since
  204.  * we don't intend to ever return to user land anyway)
  205.  */
  206. ldil L%PA(swapper_pg_dir),%r4
  207. ldo R%PA(swapper_pg_dir)(%r4),%r4
  208. mtctl %r4,%cr24 /* Initialize kernel root pointer */
  209. mtctl %r4,%cr25 /* Initialize user root pointer */
  210. /* Clear sr4-sr7 */
  211. mtsp %r0, %sr4
  212. mtsp %r0, %sr5
  213. mtsp %r0, %sr6
  214. mtsp %r0, %sr7
  215. tovirt  %r30        /* make sp virtual */
  216. rsm 8,%r0           /* Clear Q bit */
  217. ldi     1,%r1
  218. mtctl   %r1,%cr29   /* Set trap code to "1" for HPMC */
  219. mtctl   %r0,%cr30   /* Force interruptions to use hpmc stack */
  220. ldil    L%PA(intr_save), %r1
  221. ldo     R%PA(intr_save)(%r1), %r1
  222. be      0(%sr7,%r1)
  223. nop
  224. os_hpmc_fail:
  225. /*
  226.  * Reset the system
  227.  *
  228.  * Some systems may lockup from a broadcast reset, so try the
  229.  * hversion PDC_BROADCAST_RESET() first.
  230.  * MP_FIXME: reset all processors if more than one central bus.
  231.  */
  232. /* PDC_BROADCAST_RESET() */
  233. ldo     PDC_BROADCAST_RESET(%r0),arg0
  234. ldo     0(%r0),arg1                     /* do reset */
  235. ldil    L%PA(os_hpmc_6),rp
  236. bv      (%r3)                           /* call pdce_proc */
  237. ldo     R%PA(os_hpmc_6)(rp),rp
  238. os_hpmc_6:
  239. /*
  240.  * possible return values:
  241.  *  -1  non-existent procedure
  242.  *  -2  non-existent option
  243.  *  -16 unaligned stack
  244.  *
  245.  * If call returned, do a broadcast reset.
  246.  */
  247. ldil    L%0xfffc0000,%r4        /* IO_BROADCAST */
  248. ldo     5(%r0),%r5
  249. stw     %r5,48(%r4)             /*  CMD_RESET to IO_COMMAND offset */
  250. b .
  251. nop
  252. /* this label used to compute os_hpmc checksum */
  253. .export os_hpmc_end, code
  254. os_hpmc_end:
  255. nop