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