1129198Scognet/* $NetBSD: fusu.S,v 1.10 2003/12/01 13:34:44 rearnsha Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1996-1998 Mark Brinicombe. 5129198Scognet * All rights reserved. 6129198Scognet * 7129198Scognet * Redistribution and use in source and binary forms, with or without 8129198Scognet * modification, are permitted provided that the following conditions 9129198Scognet * are met: 10129198Scognet * 1. Redistributions of source code must retain the above copyright 11129198Scognet * notice, this list of conditions and the following disclaimer. 12129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 13129198Scognet * notice, this list of conditions and the following disclaimer in the 14129198Scognet * documentation and/or other materials provided with the distribution. 15129198Scognet * 3. All advertising materials mentioning features or use of this software 16129198Scognet * must display the following acknowledgement: 17129198Scognet * This product includes software developed by Mark Brinicombe 18129198Scognet * 4. The name of the company nor the name of the author may be used to 19129198Scognet * endorse or promote products derived from this software without specific 20129198Scognet * prior written permission. 21129198Scognet * 22129198Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 23129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25129198Scognet * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 26129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32129198Scognet * SUCH DAMAGE. 33129198Scognet * 34129198Scognet */ 35129198Scognet 36129198Scognet#include <machine/asm.h> 37129198Scognet#include <machine/armreg.h> 38129198Scognet#include "assym.s" 39129198Scognet__FBSDID("$FreeBSD$"); 40129198Scognet 41275767Sandrew .syntax unified 42275767Sandrew 43239268Sgonzo#ifdef _ARM_ARCH_6 44239268Sgonzo#define GET_PCB(tmp) \ 45239268Sgonzo mrc p15, 0, tmp, c13, c0, 4; \ 46266159Sian add tmp, tmp, #(TD_PCB) 47129198Scognet#else 48129198Scognet.Lcurpcb: 49129198Scognet .word _C_LABEL(__pcpu) + PC_CURPCB 50239268Sgonzo#define GET_PCB(tmp) \ 51239268Sgonzo ldr tmp, .Lcurpcb 52129198Scognet#endif 53129198Scognet 54129198Scognet/* 55129198Scognet * fuword(caddr_t uaddr); 56129198Scognet * Fetch an int from the user's address space. 57129198Scognet */ 58129198Scognet 59163449SdavidxuENTRY(casuword) 60269796SianEENTRY_NP(casuword32) 61239268Sgonzo GET_PCB(r3) 62137271Scognet ldr r3, [r3] 63137271Scognet 64137271Scognet#ifdef DIAGNOSTIC 65137271Scognet teq r3, #0x00000000 66137271Scognet beq .Lfusupcbfault 67137271Scognet#endif 68145452Scognet stmfd sp!, {r4, r5} 69163449Sdavidxu adr r4, .Lcasuwordfault 70137271Scognet str r4, [r3, #PCB_ONFAULT] 71269679Sian#ifdef _ARM_ARCH_6 72269679Sian1: 73269679Sian cmp r0, #KERNBASE 74269679Sian mvnhs r0, #0 75269679Sian bhs 2f 76269679Sian 77269679Sian ldrex r5, [r0] 78269679Sian cmp r5, r1 79269679Sian movne r0, r5 80269679Sian bne 2f 81269679Sian strex r5, r2, [r0] 82269679Sian cmp r5, #0 83269679Sian bne 1b 84269679Sian#else 85145452Scognet ldrt r5, [r0] 86145452Scognet cmp r5, r1 87145452Scognet movne r0, r5 88275767Sandrew strteq r2, [r0] 89269679Sian#endif 90145452Scognet moveq r0, r1 91269679Sian2: 92145452Scognet ldmfd sp!, {r4, r5} 93137271Scognet mov r1, #0x00000000 94137271Scognet str r1, [r3, #PCB_ONFAULT] 95137463Scognet RET 96269796SianEEND(casuword32) 97248361SandrewEND(casuword) 98137271Scognet 99137271Scognet/* 100163449Sdavidxu * Handle faults from casuword. Clean up and return -1. 101145452Scognet */ 102145452Scognet 103163449Sdavidxu.Lcasuwordfault: 104145452Scognet mov r0, #0x00000000 105145452Scognet str r0, [r3, #PCB_ONFAULT] 106145452Scognet mvn r0, #0x00000000 107145452Scognet ldmfd sp!, {r4, r5} 108145452Scognet RET 109248361Sandrew 110145452Scognet/* 111137271Scognet * fuword(caddr_t uaddr); 112137271Scognet * Fetch an int from the user's address space. 113137271Scognet */ 114137271Scognet 115129198ScognetENTRY(fuword) 116269796SianEENTRY_NP(fuword32) 117239268Sgonzo GET_PCB(r2) 118129198Scognet ldr r2, [r2] 119129198Scognet 120129198Scognet#ifdef DIAGNOSTIC 121129198Scognet teq r2, #0x00000000 122129198Scognet beq .Lfusupcbfault 123129198Scognet#endif 124129198Scognet 125129198Scognet adr r1, .Lfusufault 126129198Scognet str r1, [r2, #PCB_ONFAULT] 127129198Scognet 128129198Scognet ldrt r3, [r0] 129129198Scognet 130129198Scognet mov r1, #0x00000000 131129198Scognet str r1, [r2, #PCB_ONFAULT] 132129198Scognet mov r0, r3 133137463Scognet RET 134294686SianEEND(fueword32) 135294686SianEND(fueword) 136129198Scognet 137129198Scognet/* 138129198Scognet * fusword(caddr_t uaddr); 139129198Scognet * Fetch a short from the user's address space. 140129198Scognet */ 141129198Scognet 142129198ScognetENTRY(fusword) 143239268Sgonzo GET_PCB(r2) 144129198Scognet ldr r2, [r2] 145129198Scognet 146129198Scognet#ifdef DIAGNOSTIC 147129198Scognet teq r2, #0x00000000 148129198Scognet beq .Lfusupcbfault 149129198Scognet#endif 150129198Scognet 151129198Scognet adr r1, .Lfusufault 152129198Scognet str r1, [r2, #PCB_ONFAULT] 153129198Scognet 154129198Scognet ldrbt r3, [r0], #1 155129198Scognet ldrbt ip, [r0] 156129198Scognet#ifdef __ARMEB__ 157129198Scognet orr r0, ip, r3, asl #8 158129198Scognet#else 159129198Scognet orr r0, r3, ip, asl #8 160129198Scognet#endif 161129198Scognet mov r1, #0x00000000 162129198Scognet str r1, [r2, #PCB_ONFAULT] 163137463Scognet RET 164248361SandrewEND(fusword) 165129198Scognet 166129198Scognet/* 167129198Scognet * fuswintr(caddr_t uaddr); 168129198Scognet * Fetch a short from the user's address space. Can be called during an 169129198Scognet * interrupt. 170129198Scognet */ 171129198Scognet 172129198ScognetENTRY(fuswintr) 173129198Scognet ldr r2, Lblock_userspace_access 174129198Scognet ldr r2, [r2] 175129198Scognet teq r2, #0 176129198Scognet mvnne r0, #0x00000000 177137463Scognet RETne 178129198Scognet 179239268Sgonzo GET_PCB(r2) 180129198Scognet ldr r2, [r2] 181129198Scognet 182129198Scognet#ifdef DIAGNOSTIC 183129198Scognet teq r2, #0x00000000 184129198Scognet beq .Lfusupcbfault 185129198Scognet#endif 186129198Scognet 187129198Scognet adr r1, _C_LABEL(fusubailout) 188129198Scognet str r1, [r2, #PCB_ONFAULT] 189129198Scognet 190129198Scognet ldrbt r3, [r0], #1 191129198Scognet ldrbt ip, [r0] 192129198Scognet#ifdef __ARMEB__ 193129198Scognet orr r0, ip, r3, asl #8 194129198Scognet#else 195129198Scognet orr r0, r3, ip, asl #8 196129198Scognet#endif 197129198Scognet 198129198Scognet mov r1, #0x00000000 199129198Scognet str r1, [r2, #PCB_ONFAULT] 200137463Scognet RET 201248361SandrewEND(fuswintr) 202129198Scognet 203129198ScognetLblock_userspace_access: 204129198Scognet .word _C_LABEL(block_userspace_access) 205129198Scognet 206129198Scognet .data 207278652Sian .align 2 208129198Scognet .global _C_LABEL(block_userspace_access) 209129198Scognet_C_LABEL(block_userspace_access): 210129198Scognet .word 0 211129198Scognet .text 212129198Scognet 213129198Scognet/* 214129198Scognet * fubyte(caddr_t uaddr); 215129198Scognet * Fetch a byte from the user's address space. 216129198Scognet */ 217129198Scognet 218129198ScognetENTRY(fubyte) 219239268Sgonzo GET_PCB(r2) 220129198Scognet ldr r2, [r2] 221129198Scognet 222129198Scognet#ifdef DIAGNOSTIC 223129198Scognet teq r2, #0x00000000 224129198Scognet beq .Lfusupcbfault 225129198Scognet#endif 226129198Scognet 227129198Scognet adr r1, .Lfusufault 228129198Scognet str r1, [r2, #PCB_ONFAULT] 229129198Scognet 230129198Scognet ldrbt r3, [r0] 231129198Scognet 232129198Scognet mov r1, #0x00000000 233129198Scognet str r1, [r2, #PCB_ONFAULT] 234129198Scognet mov r0, r3 235137463Scognet RET 236248361SandrewEND(fubyte) 237129198Scognet 238129198Scognet/* 239129198Scognet * Handle faults from [fs]u*(). Clean up and return -1. 240129198Scognet */ 241129198Scognet 242129198Scognet.Lfusufault: 243129198Scognet mov r0, #0x00000000 244129198Scognet str r0, [r2, #PCB_ONFAULT] 245129198Scognet mvn r0, #0x00000000 246137463Scognet RET 247129198Scognet 248129198Scognet/* 249129198Scognet * Handle faults from [fs]u*(). Clean up and return -1. This differs from 250129198Scognet * fusufault() in that trap() will recognise it and return immediately rather 251129198Scognet * than trying to page fault. 252129198Scognet */ 253129198Scognet 254129198Scognet/* label must be global as fault.c references it */ 255129198Scognet .global _C_LABEL(fusubailout) 256129198Scognet_C_LABEL(fusubailout): 257129198Scognet mov r0, #0x00000000 258129198Scognet str r0, [r2, #PCB_ONFAULT] 259129198Scognet mvn r0, #0x00000000 260137463Scognet RET 261129198Scognet 262129198Scognet#ifdef DIAGNOSTIC 263129198Scognet/* 264129198Scognet * Handle earlier faults from [fs]u*(), due to no pcb 265129198Scognet */ 266129198Scognet 267129198Scognet.Lfusupcbfault: 268129198Scognet mov r1, r0 269129198Scognet adr r0, fusupcbfaulttext 270129198Scognet b _C_LABEL(panic) 271129198Scognet 272129198Scognetfusupcbfaulttext: 273129198Scognet .asciz "Yikes - no valid PCB during fusuxxx() addr=%08x\n" 274275767Sandrew .align 2 275129198Scognet#endif 276129198Scognet 277129198Scognet/* 278129198Scognet * suword(caddr_t uaddr, int x); 279129198Scognet * Store an int in the user's address space. 280129198Scognet */ 281129198Scognet 282129198ScognetENTRY(suword) 283269796SianEENTRY_NP(suword32) 284239268Sgonzo GET_PCB(r2) 285129198Scognet ldr r2, [r2] 286129198Scognet 287129198Scognet#ifdef DIAGNOSTIC 288129198Scognet teq r2, #0x00000000 289129198Scognet beq .Lfusupcbfault 290129198Scognet#endif 291129198Scognet 292129198Scognet adr r3, .Lfusufault 293129198Scognet str r3, [r2, #PCB_ONFAULT] 294129198Scognet 295129198Scognet strt r1, [r0] 296129198Scognet 297129198Scognet mov r0, #0x00000000 298129198Scognet str r0, [r2, #PCB_ONFAULT] 299137463Scognet RET 300275767SandrewEEND(suword32) 301248361SandrewEND(suword) 302129198Scognet 303129198Scognet/* 304129198Scognet * suswintr(caddr_t uaddr, short x); 305129198Scognet * Store a short in the user's address space. Can be called during an 306129198Scognet * interrupt. 307129198Scognet */ 308129198Scognet 309129198ScognetENTRY(suswintr) 310129198Scognet ldr r2, Lblock_userspace_access 311129198Scognet ldr r2, [r2] 312129198Scognet teq r2, #0 313129198Scognet mvnne r0, #0x00000000 314137463Scognet RETne 315129198Scognet 316239268Sgonzo GET_PCB(r2) 317129198Scognet ldr r2, [r2] 318129198Scognet 319129198Scognet#ifdef DIAGNOSTIC 320129198Scognet teq r2, #0x00000000 321129198Scognet beq .Lfusupcbfault 322129198Scognet#endif 323129198Scognet 324129198Scognet adr r3, _C_LABEL(fusubailout) 325129198Scognet str r3, [r2, #PCB_ONFAULT] 326129198Scognet 327129198Scognet#ifdef __ARMEB__ 328129198Scognet mov ip, r1, lsr #8 329129198Scognet strbt ip, [r0], #1 330129198Scognet#else 331129198Scognet strbt r1, [r0], #1 332129198Scognet mov r1, r1, lsr #8 333129198Scognet#endif 334129198Scognet strbt r1, [r0] 335129198Scognet 336129198Scognet mov r0, #0x00000000 337129198Scognet str r0, [r2, #PCB_ONFAULT] 338137463Scognet RET 339248361SandrewEND(suswintr) 340129198Scognet 341129198Scognet/* 342129198Scognet * susword(caddr_t uaddr, short x); 343129198Scognet * Store a short in the user's address space. 344129198Scognet */ 345129198Scognet 346129198ScognetENTRY(susword) 347239268Sgonzo GET_PCB(r2) 348129198Scognet ldr r2, [r2] 349129198Scognet 350129198Scognet#ifdef DIAGNOSTIC 351129198Scognet teq r2, #0x00000000 352129198Scognet beq .Lfusupcbfault 353129198Scognet#endif 354129198Scognet 355129198Scognet adr r3, .Lfusufault 356129198Scognet str r3, [r2, #PCB_ONFAULT] 357129198Scognet 358129198Scognet#ifdef __ARMEB__ 359129198Scognet mov ip, r1, lsr #8 360129198Scognet strbt ip, [r0], #1 361129198Scognet#else 362129198Scognet strbt r1, [r0], #1 363129198Scognet mov r1, r1, lsr #8 364129198Scognet#endif 365129198Scognet strbt r1, [r0] 366129198Scognet 367129198Scognet mov r0, #0x00000000 368129198Scognet str r0, [r2, #PCB_ONFAULT] 369137463Scognet RET 370248361SandrewEND(susword) 371129198Scognet 372129198Scognet/* 373129198Scognet * subyte(caddr_t uaddr, char x); 374129198Scognet * Store a byte in the user's address space. 375129198Scognet */ 376129198Scognet 377129198ScognetENTRY(subyte) 378239268Sgonzo GET_PCB(r2) 379129198Scognet ldr r2, [r2] 380129198Scognet 381129198Scognet 382129198Scognet#ifdef DIAGNOSTIC 383129198Scognet teq r2, #0x00000000 384129198Scognet beq .Lfusupcbfault 385129198Scognet#endif 386129198Scognet 387129198Scognet adr r3, .Lfusufault 388129198Scognet str r3, [r2, #PCB_ONFAULT] 389129198Scognet 390129198Scognet strbt r1, [r0] 391129198Scognet mov r0, #0x00000000 392129198Scognet str r0, [r2, #PCB_ONFAULT] 393137463Scognet RET 394248361SandrewEND(subyte) 395