1/*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <machine/asm.h> 36__FBSDID("$FreeBSD$"); 37 38#include <machine/setjmp.h> 39 40#include "assym.s" 41 42/* 43 * One of the fu* or su* functions failed, return -1. 44 */ 45ENTRY(fsu_fault) 46 SET_FAULT_HANDLER(x0, a1) /* Reset the handler function */ 47fsu_fault_nopcb: 48 li a0, -1 49 ret 50END(fsu_fault) 51 52/* 53 * int casueword32(volatile uint32_t *, uint32_t, uint32_t *, uint32_t) 54 */ 55ENTRY(casueword32) 56 li a4, (VM_MAXUSER_ADDRESS-3) 57 bgt a0, a4, fsu_fault_nopcb 58 la a6, fsu_fault /* Load the fault handler */ 59 SET_FAULT_HANDLER(a6, a4) /* And set it */ 601: lr.w a4, 0(a0) /* Load-exclusive the data */ 61 bne a4, a1, 2f /* If not equal then exit */ 62 sc.w a5, a3, 0(a0) /* Store the new data */ 63 bnez a5, 1b /* Retry on failure */ 642: SET_FAULT_HANDLER(x0, a5) /* Reset the fault handler */ 65 sw a4, 0(a2) /* Store the read data */ 66 li a0, 0 /* Success */ 67 ret /* Return */ 68END(casueword32) 69 70/* 71 * int casueword(volatile u_long *, u_long, u_long *, u_long) 72 */ 73ENTRY(casueword) 74 li a4, (VM_MAXUSER_ADDRESS-7) 75 bgt a0, a4, fsu_fault_nopcb 76 la a6, fsu_fault /* Load the fault handler */ 77 SET_FAULT_HANDLER(a6, a4) /* And set it */ 781: lr.d a4, 0(a0) /* Load-exclusive the data */ 79 bne a4, a1, 2f /* If not equal then exit */ 80 sc.d a5, a3, 0(a0) /* Store the new data */ 81 bnez a5, 1b /* Retry on failure */ 822: SET_FAULT_HANDLER(x0, a5) /* Reset the fault handler */ 83 sd a4, 0(a2) /* Store the read data */ 84 li a0, 0 /* Success */ 85 ret /* Return */ 86END(casueword) 87 88/* 89 * int fubyte(volatile const void *) 90 */ 91ENTRY(fubyte) 92 li a1, VM_MAXUSER_ADDRESS 93 bgt a0, a1, fsu_fault_nopcb 94 la a6, fsu_fault /* Load the fault handler */ 95 SET_FAULT_HANDLER(a6, a1) /* And set it */ 96 lb a0, 0(a0) /* Try loading the data */ 97 SET_FAULT_HANDLER(x0, a1) /* Reset the fault handler */ 98 ret /* Return */ 99END(fubyte) 100 101/* 102 * int fuword(volatile const void *) 103 */ 104ENTRY(fuword16) 105 li a1, (VM_MAXUSER_ADDRESS-1) 106 bgt a0, a1, fsu_fault_nopcb 107 la a6, fsu_fault /* Load the fault handler */ 108 SET_FAULT_HANDLER(a6, a1) /* And set it */ 109 lh a0, 0(a0) /* Try loading the data */ 110 SET_FAULT_HANDLER(x0, a1) /* Reset the fault handler */ 111 ret /* Return */ 112END(fuword16) 113 114/* 115 * int32_t fueword32(volatile const void *, int32_t *) 116 */ 117ENTRY(fueword32) 118 li a2, (VM_MAXUSER_ADDRESS-3) 119 bgt a0, a2, fsu_fault_nopcb 120 la a6, fsu_fault /* Load the fault handler */ 121 SET_FAULT_HANDLER(a6, a2) /* And set it */ 122 lw a0, 0(a0) /* Try loading the data */ 123 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 124 sw a0, 0(a1) /* Save the data in kernel space */ 125 li a0, 0 /* Success */ 126 ret /* Return */ 127END(fueword32) 128 129/* 130 * long fueword(volatile const void *, int64_t *) 131 * int64_t fueword64(volatile const void *, int64_t *) 132 */ 133ENTRY(fueword) 134EENTRY(fueword64) 135 li a2, (VM_MAXUSER_ADDRESS-7) 136 bgt a0, a2, fsu_fault_nopcb 137 la a6, fsu_fault /* Load the fault handler */ 138 SET_FAULT_HANDLER(a6, a2) /* And set it */ 139 ld a0, 0(a0) /* Try loading the data */ 140 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 141 sd a0, 0(a1) /* Save the data in kernel space */ 142 li a0, 0 /* Success */ 143 ret /* Return */ 144EEND(fueword64) 145END(fueword) 146 147/* 148 * int subyte(volatile void *, int) 149 */ 150ENTRY(subyte) 151 li a2, VM_MAXUSER_ADDRESS 152 bgt a0, a2, fsu_fault_nopcb 153 la a6, fsu_fault /* Load the fault handler */ 154 SET_FAULT_HANDLER(a6, a2) /* And set it */ 155 sb a1, 0(a0) /* Try storing the data */ 156 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 157 li a0, 0 /* Success */ 158 ret /* Return */ 159END(subyte) 160 161/* 162 * int suword16(volatile void *, int) 163 */ 164ENTRY(suword16) 165 li a2, (VM_MAXUSER_ADDRESS-1) 166 bgt a0, a2, fsu_fault_nopcb 167 la a6, fsu_fault /* Load the fault handler */ 168 SET_FAULT_HANDLER(a6, a2) /* And set it */ 169 sh a1, 0(a0) /* Try storing the data */ 170 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 171 li a0, 0 /* Success */ 172 ret /* Return */ 173END(suword16) 174 175/* 176 * int suword32(volatile void *, int) 177 */ 178ENTRY(suword32) 179 li a2, (VM_MAXUSER_ADDRESS-3) 180 bgt a0, a2, fsu_fault_nopcb 181 la a6, fsu_fault /* Load the fault handler */ 182 SET_FAULT_HANDLER(a6, a2) /* And set it */ 183 sw a1, 0(a0) /* Try storing the data */ 184 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 185 li a0, 0 /* Success */ 186 ret /* Return */ 187END(suword32) 188 189/* 190 * int suword(volatile void *, long) 191 */ 192ENTRY(suword) 193EENTRY(suword64) 194 li a2, (VM_MAXUSER_ADDRESS-7) 195 bgt a0, a2, fsu_fault_nopcb 196 la a6, fsu_fault /* Load the fault handler */ 197 SET_FAULT_HANDLER(a6, a2) /* And set it */ 198 sd a1, 0(a0) /* Try storing the data */ 199 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 200 li a0, 0 /* Success */ 201 ret /* Return */ 202EEND(suword64) 203END(suword) 204 205/* 206 * fuswintr and suswintr are just like fusword and susword except that if 207 * the page is not in memory or would cause a trap, then we return an error. 208 * The important thing is to prevent sleep() and switch(). 209 */ 210 211/* 212 * Special handler so the trap code knows not to sleep. 213 */ 214ENTRY(fsu_intr_fault) 215 SET_FAULT_HANDLER(x0, a1) /* Reset the handler function */ 216 li a0, -1 217 ret 218END(fsu_fault) 219 220/* 221 * int fuswintr(void *) 222 */ 223ENTRY(fuswintr) 224 li a1, (VM_MAXUSER_ADDRESS-3) 225 bgt a0, a1, fsu_fault_nopcb 226 la a6, fsu_intr_fault /* Load the fault handler */ 227 SET_FAULT_HANDLER(a6, a1) /* And set it */ 228 lw a0, 0(a0) /* Try loading the data */ 229 SET_FAULT_HANDLER(x0, x1) /* Reset the fault handler */ 230 ret /* Return */ 231END(fuswintr) 232 233/* 234 * int suswintr(void *base, int word) 235 */ 236ENTRY(suswintr) 237 li a2, (VM_MAXUSER_ADDRESS-3) 238 bgt a0, a2, fsu_fault_nopcb 239 la a6, fsu_intr_fault /* Load the fault handler */ 240 SET_FAULT_HANDLER(a6, a2) /* And set it */ 241 sw a1, 0(a0) /* Try storing the data */ 242 SET_FAULT_HANDLER(x0, a2) /* Reset the fault handler */ 243 li a0, 0 /* Success */ 244 ret /* Return */ 245END(suswintr) 246 247ENTRY(setjmp) 248 /* Store the stack pointer */ 249 sd sp, 0(a0) 250 addi a0, a0, 8 251 252 /* Store the general purpose registers and ra */ 253 sd s0, (0 * 8)(a0) 254 sd s1, (1 * 8)(a0) 255 sd s2, (2 * 8)(a0) 256 sd s3, (3 * 8)(a0) 257 sd s4, (4 * 8)(a0) 258 sd s5, (5 * 8)(a0) 259 sd s6, (6 * 8)(a0) 260 sd s7, (7 * 8)(a0) 261 sd s8, (8 * 8)(a0) 262 sd s9, (9 * 8)(a0) 263 sd s10, (10 * 8)(a0) 264 sd s11, (11 * 8)(a0) 265 sd ra, (12 * 8)(a0) 266 267 /* Return value */ 268 li a0, 0 269 ret 270END(setjmp) 271 272ENTRY(longjmp) 273 /* Restore the stack pointer */ 274 ld sp, 0(a0) 275 addi a0, a0, 8 276 277 /* Restore the general purpose registers and ra */ 278 ld s0, (0 * 8)(a0) 279 ld s1, (1 * 8)(a0) 280 ld s2, (2 * 8)(a0) 281 ld s3, (3 * 8)(a0) 282 ld s4, (4 * 8)(a0) 283 ld s5, (5 * 8)(a0) 284 ld s6, (6 * 8)(a0) 285 ld s7, (7 * 8)(a0) 286 ld s8, (8 * 8)(a0) 287 ld s9, (9 * 8)(a0) 288 ld s10, (10 * 8)(a0) 289 ld s11, (11 * 8)(a0) 290 ld ra, (12 * 8)(a0) 291 292 /* Load the return value */ 293 mv a0, a1 294 ret 295END(longjmp) 296