1/* $NetBSD: trap.S,v 1.5 2002/08/25 20:19:59 fredette Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matthew Fredette. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* $OpenBSD: locore.S,v 1.46 2001/09/20 18:33:03 mickey Exp $ */ 40 41/* 42 * Copyright (c) 1998-2001 Michael Shalayeff 43 * All rights reserved. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed by Michael Shalayeff. 56 * 4. The name of the author may not be used to endorse or promote products 57 * derived from this software without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 60 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 61 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 62 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 63 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 64 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 65 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 67 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 68 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 69 * THE POSSIBILITY OF SUCH DAMAGE. 70 * 71 * Portitions of this file are derived from other sources, see 72 * the copyrights and acknowledgements below. 73 */ 74/* 75 * Copyright (c) 1990,1991,1992,1994 The University of Utah and 76 * the Computer Systems Laboratory (CSL). All rights reserved. 77 * 78 * THE UNIVERSITY OF UTAH AND CSL PROVIDE THIS SOFTWARE IN ITS "AS IS" 79 * CONDITION, AND DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES 80 * WHATSOEVER RESULTING FROM ITS USE. 81 * 82 * CSL requests users of this software to return to csl-dist@cs.utah.edu any 83 * improvements that they make and grant CSL redistribution rights. 84 * 85 * Utah $Hdr: locore.s 1.62 94/12/15$ 86 */ 87/* 88 * (c) Copyright 1988 HEWLETT-PACKARD COMPANY 89 * 90 * To anyone who acknowledges that this file is provided "AS IS" 91 * without any express or implied warranty: 92 * permission to use, copy, modify, and distribute this file 93 * for any purpose is hereby granted without fee, provided that 94 * the above copyright notice and this notice appears in all 95 * copies, and that the name of Hewlett-Packard Company not be 96 * used in advertising or publicity pertaining to distribution 97 * of the software without specific, written prior permission. 98 * Hewlett-Packard Company makes no representations about the 99 * suitability of this software for any purpose. 100 */ 101 102/* 103 * NOTICE: This is not a standalone file. To use it, #include it in 104 * your port's locore.S, like so: 105 * 106 * #include <hppa/hppa/trap.S> 107 */ 108 109 .section .data 110 .align 2048 111$trap_tmp_save /* XXX assumed to be aligned on 2048 */ 112 .block TF_PHYS /* XXX must be aligned to 64 */ 113 .align 64 114 .export emergency_stack_start, data 115emergency_stack_start 116 .block 32768 /* XXX must be aligned to 64 */ 117 .export emergency_stack_end, data 118emergency_stack_end 119 .block 4 120 121 .text 122 123/* 124 * Kernel Gateway Page (must be at known address) 125 * System Call Gate 126 * Signal Return Gate 127 * 128 * GATEway instructions have to be at a fixed known locations 129 * because their addresses are hard coded in routines such as 130 * those in the C library. 131 */ 132 .align NBPG 133 .export gateway_page, entry 134gateway_page 135 nop /* @ 0.C0000000 (Nothing) */ 136 gate,n $bsd_syscall,r0 /* @ 0.C0000004 (HPUX/BSD) */ 137#ifdef COMPAT_OSF1 138 bl,n $osf_syscall,r0 139 bl,n $osf_syscall,r0 140#else 141 nop /* @ 0.C0000008 (HPOSF UNIX) */ 142 nop /* @ 0.C000000C (HPOSF Mach) */ 143#endif 144 nop 145 nop 146 nop 147 nop 148 149#ifdef COMPAT_OSF1 150$osf_syscall 151 /* 152 * Ripped screaming from OSF/MkLinux: 153 * 154 * Convert HPOSF system call to a BSD one by stashing arg4 and arg5 155 * back into the frame, and moving the system call number into r22. 156 * Fortunately, the HPOSF compiler has a bigger stack frame, which 157 * allows this horrible hack. 158 * 159 * We also need to save r29 (aka ret1) for the emulator since it may 160 * get clobbered between here and there. 161 */ 162 stw r22, HPPA_FRAME_ARG(4)(sp) 163 stw r21, HPPA_FRAME_ARG(5)(sp) 164 stw r29, HPPA_FRAME_SL(sp) 165 gate $bsd_syscall,r0 166 copy r1, r22 167#endif /* COMPAT_OSF1 */ 168 169$bsd_syscall 170 /* 171 * set up a space register and a protection id so that 172 * we can access kernel memory 173 */ 174 mfctl eiem, r1 175 mtctl r0, eiem 176 mtsp r0, sr1 177 mfctl pidr1, r28 178 ldi HPPA_PID_KERNEL, t2 179 mtctl t2, pidr1 180 181 /* 182 * now call the syscall handler 183 */ 184 .import $syscall,code 185 .call 186 ldil L%$syscall, t2 187 be,n R%$syscall(sr7, t2) 188 nop 189 190 .align NBPG 191 .export gateway_page_end, entry 192gateway_page_end 193 194 .export $syscall,entry 195 .proc 196 .callinfo calls 197 .entry 198$syscall 199 /* 200 * 201 * t1: curproc 202 * t2: user 203 * t3: args 204 * t4: user stack 205 * 206 * N.B. we are trying to rely on the fact that bottom of kernel 207 * stack contains a print of some past trapframe, so 208 * we do not save hard to get information, but do restore 209 * the whole context later on return anyway. 210 * XXXXXX this is very bad. everything must be saved 211 */ 212 ldil L%curproc, t3 213 ldw R%curproc(sr1, t3), t3 214 ldw P_ADDR(sr1, t3), t2 /* XXX can use ,sl */ 215 216 /* calculate kernel sp, load, create kernel stack frame */ 217 /* 218 * NB: Even though t4 is a caller-saved register, we 219 * save it anyways, as a convenience to __vfork14 and 220 * any other syscalls that absolutely must have a 221 * register that is saved for it. 222 */ 223 ldo NBPG+TRAPFRAME_SIZEOF(t2), t3 224 stw t1, TF_R22 -TRAPFRAME_SIZEOF(sr1, t3) /* syscall # */ 225 stw t4, TF_R19 -TRAPFRAME_SIZEOF(sr1, t3) /* convenience */ 226 copy sp, t4 227 ldo HPPA_FRAME_SIZE+HPPA_FRAME_MAXARGS(t3), sp 228 stw t4, TF_R30 -TRAPFRAME_SIZEOF(sr1, t3) /* user stack */ 229 stw r1, TF_CR15-TRAPFRAME_SIZEOF(sr1, t3) /* eiem */ 230 mtctl r1, eiem 231 232 /* 233 * Normally, we only have to save the caller-saved registers, 234 * because the callee-saved registers will be naturally 235 * saved and restored by our callee(s). However, see the 236 * longer comment in the trap handling code below for the 237 * reasons why we need to save and restore all of them. 238 */ 239 stw r27, TF_R27-TRAPFRAME_SIZEOF(sr1, t3) /* dp */ 240 stw r3 , TF_R3 -TRAPFRAME_SIZEOF(sr1, t3) 241#if defined(DDB) || defined(KGDB) || defined(FPEMUL) 242 stw r4 , TF_R4 -TRAPFRAME_SIZEOF(sr1, t3) 243 stw r5 , TF_R5 -TRAPFRAME_SIZEOF(sr1, t3) 244 stw r6 , TF_R6 -TRAPFRAME_SIZEOF(sr1, t3) 245 stw r7 , TF_R7 -TRAPFRAME_SIZEOF(sr1, t3) 246 stw r8 , TF_R8 -TRAPFRAME_SIZEOF(sr1, t3) 247 stw r9 , TF_R9 -TRAPFRAME_SIZEOF(sr1, t3) 248 stw r10, TF_R10-TRAPFRAME_SIZEOF(sr1, t3) 249 stw r11, TF_R11-TRAPFRAME_SIZEOF(sr1, t3) 250 stw r12, TF_R12-TRAPFRAME_SIZEOF(sr1, t3) 251 stw r13, TF_R13-TRAPFRAME_SIZEOF(sr1, t3) 252 stw r14, TF_R14-TRAPFRAME_SIZEOF(sr1, t3) 253 stw r15, TF_R15-TRAPFRAME_SIZEOF(sr1, t3) 254 stw r16, TF_R16-TRAPFRAME_SIZEOF(sr1, t3) 255 stw r17, TF_R17-TRAPFRAME_SIZEOF(sr1, t3) 256 stw r18, TF_R18-TRAPFRAME_SIZEOF(sr1, t3) 257#endif /* DDB || KGDB || FPEMUL */ 258 stw r0, 0(sr1, t3) /* terminate frame */ 259 copy r0 , r3 260 stw r0, HPPA_FRAME_PSP(sr1, sp) 261 stw r0, HPPA_FRAME_CRP(sr1, sp) 262 263 /* 264 * Copy Arguments 265 * unfortunately mmap() under bsd requires 7 words; 266 * linux is confined to 5, and hpux to 6. 267 * assuming the `long' syscall it gives us the maximum 268 * 9 words, which very much overkill for an average of 3. 269 * we keep it at 10, since bundling will keep it 270 * at the same speed as 9 anyway. 271 */ 272 /* 273 * XXX fredette - possible security hole here. 274 * What happens if the user hands us a stack 275 * that points to nowhere, or to data that they 276 * should not be reading? 277 */ 278 stw arg0, 1*4(sr1, t3) /* XXX can use ,bc */ 279 stw arg1, 2*4(sr1, t3) 280 stw arg2, 3*4(sr1, t3) 281 stw arg3, 4*4(sr1, t3) 282 ldw HPPA_FRAME_ARG( 4)(t4), arg0 283 ldw HPPA_FRAME_ARG( 5)(t4), arg1 284 ldw HPPA_FRAME_ARG( 6)(t4), arg2 285 ldw HPPA_FRAME_ARG( 7)(t4), arg3 286 stw arg0, 5*4(sr1, t3) 287 stw arg1, 6*4(sr1, t3) 288 stw arg2, 7*4(sr1, t3) 289 stw arg3, 8*4(sr1, t3) 290 ldw HPPA_FRAME_ARG( 8)(t4), arg0 291 ldw HPPA_FRAME_ARG( 9)(t4), arg1 292 stw arg0, 9*4(sr1, t3) 293 stw arg1,10*4(sr1, t3) 294 295 /* 296 * Save the rest of the CPU context 297 */ 298 299 ldo 4(r31), arg1 300 stw r31, TF_IIOQH-TRAPFRAME_SIZEOF(sr1, t3) 301 stw arg1, TF_IIOQT-TRAPFRAME_SIZEOF(sr1, t3) 302 303 mfsp sr0, arg0 304 stw arg0, TF_IISQH-TRAPFRAME_SIZEOF(sr1, t3) 305 stw arg0, TF_IISQT-TRAPFRAME_SIZEOF(sr1, t3) 306 307 stw arg0, TF_CR20-TRAPFRAME_SIZEOF(sr1, t3) 308 stw r31, TF_CR21-TRAPFRAME_SIZEOF(sr1, t3) 309 310 ldil L%(PSW_Q | PSW_P | PSW_C | PSW_D | PSW_I), arg1 311 ldo R%(PSW_Q | PSW_P | PSW_C | PSW_D | PSW_I)(arg1), arg1 312 mfsp sr3, arg0 313 stw arg1, TF_CR22-TRAPFRAME_SIZEOF(sr1, t3) 314 stw arg0, TF_SR3-TRAPFRAME_SIZEOF(sr1, t3) 315 stw r28, TF_CR8-TRAPFRAME_SIZEOF(sr1, t3) /* pidr1 */ 316 317 copy r0, arg0 318 ldil TFF_LAST|TFF_SYS, arg1 319 stw arg0, TF_CR19-TRAPFRAME_SIZEOF(sr1, t3) 320 stw arg1, TF_FLAGS-TRAPFRAME_SIZEOF(sr1, t3) 321 322 mfsp sr0, arg0 323 copy arg0, arg1 /* we overwrote sr1 earlier */ 324 mfsp sr2, arg2 325 mfsp sr4, arg3 326 stw arg0, TF_SR0-TRAPFRAME_SIZEOF(sr1, t3) 327 stw arg1, TF_SR1-TRAPFRAME_SIZEOF(sr1, t3) 328 stw arg2, TF_SR2-TRAPFRAME_SIZEOF(sr1, t3) 329 stw arg3, TF_SR4-TRAPFRAME_SIZEOF(sr1, t3) 330 331 mfsp sr5, arg0 332 mfsp sr6, arg1 333 mfsp sr7, arg2 334 mfctl pidr2, arg3 335 stw arg0, TF_SR5-TRAPFRAME_SIZEOF(sr1, t3) 336 stw arg1, TF_SR6-TRAPFRAME_SIZEOF(sr1, t3) 337 stw arg2, TF_SR7-TRAPFRAME_SIZEOF(sr1, t3) 338 stw arg3, TF_CR9-TRAPFRAME_SIZEOF(sr1, t3) 339 340#if pbably_not_worth_it 341 mfctl pidr3, arg2 342 mfctl pidr4, arg3 343 stw arg2, TF_CR12-TRAPFRAME_SIZEOF(sr1, t3) 344 stw arg3, TF_CR13-TRAPFRAME_SIZEOF(sr1, t3) 345#endif 346 347#if defined(DDB) || defined(KGDB) 348 /* 349 * Save hpt mask and v2p translation table pointer 350 */ 351 mfctl eirr, arg0 352 mfctl hptmask, arg1 353 stw arg0, TF_CR23-TRAPFRAME_SIZEOF(sr1, t3) 354 stw arg1, TF_CR24-TRAPFRAME_SIZEOF(sr1, t3) 355 356 mfctl vtop, arg0 357 mfctl cr28, arg1 358 stw arg0, TF_CR25-TRAPFRAME_SIZEOF(sr1, t3) 359 stw arg1, TF_CR28-TRAPFRAME_SIZEOF(sr1, t3) 360#endif 361 362 /* setup kernel context */ 363 mtsp r0, sr0 364 mtsp r0, sr1 365 mtsp r0, sr2 366 mtsp r0, sr3 367 mtsp r0, sr4 368 mtsp r0, sr5 369 mtsp r0, sr6 370 mtsp r0, sr7 371 372 ldo -TRAPFRAME_SIZEOF(t3), arg0 373 ldo 4(t3), arg1 374 375 ldil L%$global$,dp 376 ldo R%$global$(dp),dp 377 378 /* do a syscall */ 379 .import syscall,code 380 ldil L%syscall, r1 381 ldo R%syscall(r1), r1 382 .call 383 blr r0, rp 384 bv,n 0(r1) 385 nop 386 387 ldil L%curproc, r1 388 ldw R%curproc(r1), r1 389 ldw P_MD(r1), t3 390 391 .exit 392 .procend 393 /* FALLTHROUGH */ 394 395 .export $syscall_return, entry 396 .proc 397 .callinfo no_calls 398 .entry 399$syscall_return 400 /* t3 == VA trapframe */ 401 /* check for AST ? XXX */ 402 403 /* splhigh(), just in case */ 404 mtctl r0, eiem 405 406 /* 407 * 1a. Copy a `phys' part of the frame into temp store 408 * (see a note for trapall) 409 * hopefully no page fault would happen on or after the copy, 410 * and interrupts are disabled. 411 */ 412 copy t3, arg0 413 ldil L%$trap_tmp_save, arg1 414 ldi TF_PHYS - 4, arg2 415$syscall_return_copy_loop 416 ldwm 4(arg0), t1 417 addib,>= -4, arg2, $syscall_return_copy_loop 418 stwm t1, 4(arg1) 419 420 /* 1b. restore most of the general registers */ 421 ldw TF_CR11(t3), t1 422 mtctl t1, sar 423 ldw TF_R1(t3), r1 424 ldw TF_R2(t3), r2 425 ldw TF_R3(t3), r3 426 /* 427 * See the comment in the trap handling code below 428 * about why we need to save and restore all general 429 * registers under these cases. 430 */ 431#if defined(DDB) || defined(KGDB) || defined(FPEMUL) 432 ldw TF_R4(t3), r4 433 ldw TF_R5(t3), r5 434 ldw TF_R6(t3), r6 435 ldw TF_R7(t3), r7 436 ldw TF_R8(t3), r8 437 ldw TF_R9(t3), r9 438 ldw TF_R10(t3), r10 439 ldw TF_R11(t3), r11 440 ldw TF_R12(t3), r12 441 ldw TF_R13(t3), r13 442 ldw TF_R14(t3), r14 443 ldw TF_R15(t3), r15 444 ldw TF_R16(t3), r16 445 ldw TF_R17(t3), r17 446 ldw TF_R18(t3), r18 447#endif /* DDB || KGDB || FPEMUL */ 448 ldw TF_R19(t3), t4 449 /* r20(t3) is used as a temporary and will be restored later */ 450 /* r21(t2) is used as a temporary and will be restored later */ 451 /* r22(t1) is used as a temporary and will be restored later */ 452 ldw TF_R23(t3), r23 453 ldw TF_R24(t3), r24 454 ldw TF_R25(t3), r25 455 ldw TF_R26(t3), r26 456 ldw TF_R27(t3), r27 457 ldw TF_R28(t3), r28 458 ldw TF_R29(t3), r29 459 /* r30 (sp) will be restored later */ 460 ldw TF_R31(t3), r31 461 462 /* 2. restore all the space regs and pid regs, except sr3, pidr1 */ 463 ldw TF_SR0(t3), t1 464 ldw TF_SR1(t3), t2 465 mtsp t1, sr0 466 mtsp t2, sr1 467 468 ldw TF_SR2(sr3, t3), t1 469 ldw TF_SR4(sr3, t3), t2 470 mtsp t1, sr2 471 mtsp t2, sr4 472 473 ldw TF_SR5(sr3, t3), t1 474 ldw TF_SR6(sr3, t3), t2 475 mtsp t1, sr5 476 mtsp t2, sr6 477 478 ldw TF_SR7(sr3, t3), t1 479 ldw TF_CR9(sr3, t3), t2 480 mtsp t1, sr7 481 mtctl t2, pidr2 482 483#if pbably_not_worth_it 484 ldw TF_CR12(sr3, t3), t1 485 ldw TF_CR13(sr3, t3), t2 486 mtctl t1, pidr3 487 mtctl t2, pidr4 488#endif 489 ldw TF_CR0(sr3, t3), t1 490 mtctl t1, rctr 491 ldw TF_CR30(sr3, t3), t1 492 mtctl t1, cr30 493 494 /* 495 * clear the system mask, this puts us back into physical mode. 496 * reload trapframe pointer w/ correspondent PA value. 497 * sp will be left in virtual until restored from trapframe, 498 * since we don't use it anyway. 499 */ 500 rsm RESET_PSW, r0 501 nop ! nop ! nop ! nop ! nop ! nop ! nop ! nop /* XXX really? */ 502$syscall_return_phys 503 504 ldil L%$trap_tmp_save, t3 505 506 /* finally we can restore the space and offset queues and the ipsw */ 507 ldw TF_IISQH(t3), t1 508 ldw TF_IISQT(t3), t2 509 mtctl t1, pcsq 510 mtctl t2, pcsq 511 512 ldw TF_IIOQH(t3), t1 513 ldw TF_IIOQT(t3), t2 514 mtctl t1, pcoq 515 mtctl t2, pcoq 516 517 ldw TF_CR15(t3), t1 518 ldw TF_CR22(t3), t2 519 mtctl t1, eiem 520 mtctl t2, ipsw 521 522 ldw TF_SR3(t3), t1 523 ldw TF_CR8(t3), t2 524 mtsp t1, sr3 525 mtctl t2, pidr1 526 527 ldw TF_R22(t3), t1 528 ldw TF_R21(t3), t2 529 ldw TF_R30(t3), sp 530 ldw TF_R20(t3), t3 531 532 rfi 533 nop 534 .exit 535 .procend 536$syscall_end 537 538/* 539 * interrupt vector table 540 */ 541/* XXX - fredette changed sr4 to sr7 below: */ 542#define TLABEL(name) $trap$name 543#define TELABEL(num) __CONCAT(trap_ep_,num) 544#define TRAP(name,num) \ 545 .import TLABEL(name), code ! \ 546 mtctl r1, tr7 ! \ 547 ldil L%TLABEL(name), r1 ! \ 548 .call ! \ 549 be R%TLABEL(name)(sr7, r1) ! \ 550 ldi num, r1 ! \ 551 .align 32 552 553#define ATRAP(name,num) \ 554 .export TLABEL(name)$num, entry ! \ 555 .label TLABEL(name)$num ! \ 556 TRAP(all,num) 557 558#define CTRAP(name,num,pre) \ 559 .export TLABEL(name)$num, entry ! \ 560 .label TLABEL(name)$num ! \ 561 pre ! \ 562 TRAP(name,num) 563 564#define STRAP(name,num,pre) \ 565 .export TLABEL(name)$num, entry ! \ 566 .label TLABEL(name)$num ! \ 567 pre ! \ 568 mtctl r1, tr7 ! \ 569 .export TELABEL(num), entry ! \ 570 .label TELABEL(num) ! \ 571 ldil 0,r1 ! \ 572 ldo 0(r1), r1 ! \ 573 .call ! \ 574 bv 0(r1) ! \ 575 ldi num, r1 576 577#define LDILDO(name) ! \ 578 .export name, entry ! \ 579 .label name ! \ 580 ldil L%$name,%r1 ! \ 581 ldo R%$name(%r1), %r1 582 583#ifdef HP7000_CPU 584LDILDO(itlb_x) 585LDILDO(dtlb_x) 586LDILDO(dtlbna_x) 587LDILDO(tlbd_x) 588 589LDILDO(itlb_s) 590LDILDO(dtlb_s) 591LDILDO(dtlbna_s) 592LDILDO(tlbd_s) 593#endif 594 595#ifdef HP7100_CPU 596LDILDO(itlb_t) 597LDILDO(dtlb_t) 598LDILDO(dtlbna_t) 599LDILDO(tlbd_t) 600#endif 601 602#ifdef HP7100LC_CPU 603LDILDO(itlb_l) 604LDILDO(dtlb_l) 605LDILDO(dtlbna_l) 606LDILDO(tlbd_l) 607#endif 608 609#define ITLBPRE \ 610 mfctl pcoq,r9 /* Offset */ ! \ 611 mfctl pcsq,r8 /* Space */ ! \ 612 depi 0,31,PGSHIFT,r9 /* align offset to page */ 613#define DTLBPRE \ 614 mfctl ior, r9 /* Offset */ ! \ 615 mfctl isr, r8 /* Space */ ! \ 616 depi 0,31,PGSHIFT,r9 /* align offset to page */ 617 /* CR28XXX according to a popular belief cr28 should be read here */ 618#define HPMCPRE nop 619 620 .align NBPG 621 .export $ivaaddr, entry 622 .export os_hpmc, entry 623$ivaaddr 624 ATRAP(null,T_NONEXIST) /* 0. invalid interrupt vector */ 625os_hpmc 626 CTRAP(hpmc,T_HPMC,HPMCPRE) /* 1. high priority machine check */ 627 ATRAP(power,T_POWERFAIL) /* 2. power failure */ 628 ATRAP(recnt,T_RECOVERY) /* 3. recovery counter trap */ 629 ATRAP(intr,T_INTERRUPT) /* 4. external interrupt */ 630 ATRAP(lpmc,T_LPMC) /* 5. low-priority machine check */ 631 STRAP(itlb,T_ITLBMISS,ITLBPRE) /* 6. instruction TLB miss fault */ 632 ATRAP(iprot,T_IPROT) /* 7. instruction protection trap */ 633 ATRAP(ill,T_ILLEGAL) /* 8. Illegal instruction trap */ 634 CTRAP(ibrk,T_IBREAK,) /* 9. break instruction trap */ 635 ATRAP(privop,T_PRIV_OP) /* 10. privileged operation trap */ 636 ATRAP(privr,T_PRIV_REG) /* 11. privileged register trap */ 637 ATRAP(ovrfl,T_OVERFLOW) /* 12. overflow trap */ 638 ATRAP(cond,T_CONDITION) /* 13. conditional trap */ 639 ATRAP(excpt,T_EXCEPTION) /* 14. assist exception trap */ 640 STRAP(dtlb,T_DTLBMISS,DTLBPRE) /* 15. data TLB miss fault */ 641 STRAP(itlb,T_ITLBMISSNA,ITLBPRE)/* 16. ITLB non-access miss fault */ 642 STRAP(dtlb,T_DTLBMISSNA,DTLBPRE)/* 17. DTLB non-access miss fault */ 643 ATRAP(dprot,T_DPROT) /* 18. data protection trap 644 unalligned data reference trap */ 645 ATRAP(dbrk,T_DBREAK) /* 19. data break trap */ 646 STRAP(tlbd,T_TLB_DIRTY,DTLBPRE) /* 20. TLB dirty bit trap */ 647 ATRAP(pgref,T_PAGEREF) /* 21. page reference trap */ 648 CTRAP(emu,T_EMULATION,) /* 22. assist emulation trap */ 649 ATRAP(hpl,T_HIGHERPL) /* 23. higher-privelege transfer trap*/ 650 ATRAP(lpl,T_LOWERPL) /* 24. lower-privilege transfer trap */ 651 ATRAP(tknbr,T_TAKENBR) /* 25. taken branch trap */ 652 ATRAP(dacc,T_DATACC) /* 26. data access rights trap */ 653 ATRAP(dpid,T_DATAPID) /* 27. data protection ID trap */ 654 ATRAP(dalgn,T_DATALIGN) /* 28. unaligned data ref trap */ 655 ATRAP(unk29,29) 656 ATRAP(unk30,30) 657 ATRAP(unk31,31) 658 ATRAP(unk32,32) 659 ATRAP(unk33,33) 660 ATRAP(unk34,34) 661 ATRAP(unk35,35) 662 ATRAP(unk36,36) 663 ATRAP(unk37,37) 664 ATRAP(unk38,38) 665 ATRAP(unk39,39) 666 ATRAP(unk40,40) 667 ATRAP(unk41,41) 668 ATRAP(unk42,42) 669 ATRAP(unk43,43) 670 ATRAP(unk44,44) 671 ATRAP(unk45,45) 672 ATRAP(unk46,46) 673 ATRAP(unk47,47) 674 ATRAP(unk48,48) 675 ATRAP(unk49,49) 676 ATRAP(unk50,50) 677 ATRAP(unk51,51) 678 ATRAP(unk52,52) 679 ATRAP(unk53,53) 680 ATRAP(unk54,54) 681 ATRAP(unk55,55) 682 ATRAP(unk56,56) 683 ATRAP(unk57,57) 684 ATRAP(unk58,58) 685 ATRAP(unk59,59) 686 ATRAP(unk60,60) 687 ATRAP(unk61,61) 688 ATRAP(unk62,62) 689 ATRAP(unk63,63) 690 /* 64 */ 691 692/* 693 * This is the locore support for HPMC and TOC machine checks. 694 * In the HPMC case, this is a continuation of the HPMC handler 695 * that begins in the interrupt vector table. In the TOC 696 * case, this is the handler installed in page zero. 697 * 698 * Notable points about the CPU state for the OS_TOC handler: 699 * 700 * - The PSW Q bit is 1, all other PSW bits are 0. 701 * - CR14 (IVA) does not point to our vector table. 702 * - CR22 (IPSW) is valid. 703 * - All other control registers HVERSION dependent. 704 * - The TLB is initialized and invalid. 705 * 706 * Notable points about the CPU state for the OS_HPMC handler: 707 * 708 * - The PSW M bit is 1, all other PSW bits are 0. 709 * - CR14 (IVA) does point to our vector table. 710 * - CR22 (IPSW) is valid. 711 * - All other control registers HVERSION dependent. 712 * - The TLB is unchanged. 713 * 714 * The TOC CPU state is actually trickier. Whereas in the HPMC 715 * case, we can return to virtual mode right away, in the TOC 716 * case we can't return to virtual mode until the kernel mapping 717 * is reloaded into the BTLB. 718 * 719 * Otherwise, we set up the kernel context, move onto the 720 * emergency stack, and call hppa_machine_check. 721 */ 722ENTRY(os_toc, 0) 723 /* This loads %arg0 and nullifies the next instruction. */ 724 addi,tr T_INTERRUPT, %r0, %arg0 725EXIT(os_toc) 726ENTRY(TLABEL(hpmc),0) 727ALTENTRY(os_hpmc_cont) 728 ldi T_HPMC, %arg0 729 730 /* Disable interrupts. */ 731 mtctl %r0, eiem 732 733 /* Load protection and space registers for the kernel. */ 734 ldi HPPA_PID_KERNEL, %r1 735 mtctl %r1, pidr1 736 ldi HPPA_SID_KERNEL, %r1 737 mtsp %r1, sr0 738 mtsp %r1, sr1 739 mtsp %r1, sr2 740 mtsp %r1, sr3 741 mtsp %r1, sr4 742 mtsp %r1, sr5 743 mtsp %r1, sr6 744 mtsp %r1, sr7 745 746 /* Reload the Interruption Vector Address. */ 747 ldil L%$ivaaddr, %r1 748 ldo R%$ivaaddr(%r1), %r1 749 mtctl %r1, iva 750 751 /* Reload the HPT base and mask. */ 752 ldil L%hpt_base, %r1 753 ldw R%hpt_base(%r1), %r1 754 mtctl %r1, vtop 755 ldil L%hpt_mask, %r1 756 ldw R%hpt_mask(%r1), %r1 757 mtctl %r1, hptmask 758 759 /* Disable interrupts for the long haul. */ 760 ldil L%kpsw, t1 761 ldw R%kpsw(t1), %r1 762 depi 0, PSW_I_POS, 1, %r1 763 stw %r1, R%kpsw(t1) 764 765 /* Reload the global data pointer. */ 766 ldil L%$global$, dp 767 ldo R%$global$(dp), dp 768 769 /* Move onto the emergency stack. */ 770 ldil L%emergency_stack_start, %sp 771 ldo R%emergency_stack_start(%sp), %sp 772 stw,ma %r0, HPPA_FRAME_SIZE(%sp) 773 copy %sp, %r3 774 775 /* Start stack calling convention. */ 776 stw %r0, HPPA_FRAME_CRP(%sp) 777 stw %r0, HPPA_FRAME_PSP(%sp) 778 copy %r3, %r1 779 copy %sp, %r3 780 stw,ma %r1, HPPA_FRAME_SIZE(%sp) 781 782 /* If this is a TOC, remap the kernel. */ 783 comib,<>,n T_INTERRUPT, %arg0, $check_do_rfi 784 785 /* Clear kernelmapped. */ 786 ldil L%kernelmapped, %r1 787 stw %r0, R%kernelmapped(%r1) 788 789 /* Call hppa_btlb_reload. */ 790 ldil L%hppa_btlb_reload, %r1 791 ldo R%hppa_btlb_reload(%r1), %r1 792 blr 0, %rp 793 bv %r0(%r1) 794 nop 795 796 /* Set kernelmapped. */ 797 ldil L%kernelmapped, %r1 798 stw %r1, R%kernelmapped(%r1) 799 800 /* Reload %arg0 (it may have been destroyed). */ 801 ldi T_INTERRUPT, %arg0 802 803 /* Disable the interrupt queues. */ 804 rsm RESET_PSW, %r0 805 806$check_do_rfi 807 808 /* Load IPSW. */ 809 ldil L%kpsw, %r1 810 ldw R%kpsw(%r1), %r1 811 mtctl %r1, ipsw 812 813 /* Get the address of hppa_machine_check. */ 814 ldil L%hppa_machine_check, %r1 815 ldo R%hppa_machine_check(%r1), %r1 816 817 /* Load the instruction address queues. */ 818 mtctl %r1, pcoq 819 ldo 4(%r1), %r1 820 mtctl %r1, pcoq 821 ldi HPPA_SID_KERNEL, %r1 822 mtctl %r1, pcsq 823 mtctl %r1, pcsq 824 825 blr 0, %rp 826 rfi 827 nop 828 nop 829 nop 830ALTENTRY(os_hpmc_cont_end) 831 nop 832ALTENTRY(os_toc_end) 833EXIT(TLABEL(hpmc)) 834 835/* 836 * This handles all assist emulation traps. We break 837 * these down into three categories: emulate special 838 * function unit, emulate non-FPU coprocessor, and 839 * emulate FPU coprocessor, and dispatch accordingly. 840 */ 841 .export TLABEL(emu), entry 842LEAF_ENTRY(TLABEL(emu)) 843 844 /* 845 * Save %arg0 and load it with the instruction 846 * that caused the emulation trap. 847 */ 848 mtctl %arg0, tr2 849 mfctl iir, %arg0 850 851 /* 852 * If the opcode field in the instruction is 4, 853 * indicating a special function unit SPOP 854 * instruction, branch to emulate an sfu. 855 */ 856 extru %arg0, 5, 6, %r1 857 comib,=,n 4, %r1, $emulate_sfu 858 859 /* 860 * If the uid field in the instruction is not 861 * zero or one, indicating a coprocessor other 862 * than an FPU, branch to emulate a non-FPU 863 * coprocessor. 864 */ 865 extru %arg0, 25, 3, %r1 866 comib,<<,n 1, %r1, $emulate_coproc 867 868 /* 869 * If we're still here, this is a FPU 870 * coprocessor instruction. That we trapped 871 * to emulate it means one of three things. 872 * 873 * If we do not have a hardware FPU, we need 874 * to emulate this instruction. 875 * 876 * If we do have a hardware FPU but it is 877 * disabled, we trapped because the current 878 * process' state is not loaded into the 879 * FPU. We load that state in, possibly 880 * swapping out another process' state first. 881 * 882 * If we do have a hardware FPU and it is 883 * enabled, we trapped because of an 884 * instruction that isn't supported by this 885 * FPU, and so we need to emulate it. 886 */ 887 888 /* 889 * As an optimization, hppa_fpu_bootstrap 890 * replaces this branch instruction with a 891 * nop if there is a hardware FPU. 892 * 893 * Otherwise, this is the branch to emulate 894 * an FPU coprocessor. 895 */ 896ALTENTRY(hppa_fpu_nop0) 897 b,n $emulate_fpu 898 899 /* 900 * We have a hardware FPU. If it is enabled, 901 * branch to emulate the instruction. 902 */ 903 mfctl ccr, %arg0 904 extru,= %arg0, 25, 2, %r1 905 b,n $emulate_fpu 906 907 /* 908 * The hardware FPU is disabled, so we need to swap 909 * in the FPU state of the process whose uspace 910 * physical address in %cr30. We may also need 911 * to swap out the FPU state of any process whose 912 * uspace physical address is in the fpu_cur_uspace 913 * variable. 914 */ 915 916 /* 917 * So far, the CTRAP() macro has saved %r1 in 918 * %tr7, and the dispatching above has saved 919 * %arg0 in tr2. Save the other registers that 920 * we want to use. hppa_fpu_swap deliberately 921 * uses only these registers and %r1 and %arg0. 922 */ 923 mtctl %arg1, tr3 924 mtctl %rp, tr5 925 926 /* 927 * Call hppa_fpu_swap. 928 */ 929 ldil L%fpu_cur_uspace, %arg0 930 ldw R%fpu_cur_uspace(%arg0), %arg0 931 mfctl cr30, %arg1 932 blr 0, %rp 933 b hppa_fpu_swap 934 nop 935 936 /* Restore registers and rfi. */ 937 mfctl tr5, %rp 938 mfctl tr3, %arg1 939 mfctl tr2, %arg0 940 mfctl tr7, %r1 941 rfi 942 nop 943 944 /* 945 * We branch here to emulate a special function 946 * unit instruction. On entry, %r1 is saved in %tr7 947 * (courtesy of CTRAP), and %arg0 is saved in %tr2 948 * (courtesy of the sfu/coprocessor dispatcher). 949 */ 950$emulate_sfu 951 /* 952 * Currently we just restore %arg0 and 953 * trap with an illegal instruction. 954 */ 955 mfctl tr2, %arg0 956 b TLABEL(all) 957 ldi T_ILLEGAL, %r1 958 959 /* 960 * We branch here to emulate a non-FPU coprocessor 961 * instruction. On entry, %r1 is saved in %tr7 962 * (courtesy of CTRAP), and %t1 is saved in %tr2 963 * (courtesy of the sfu/coprocessor dispatcher). 964 */ 965$emulate_coproc 966 /* 967 * Currently we just restore %arg0 and 968 * trap with an illegal instruction. 969 */ 970 mfctl tr2, %arg0 971 b TLABEL(all) 972 ldi T_ILLEGAL, %r1 973 974 /* 975 * We branch here to emulate an FPU coprocessor 976 * instruction. On entry, %r1 is saved in %tr7 977 * (courtesy of CTRAP), and %t1 is saved in %tr2 978 * (courtesy of the sfu/coprocessor dispatcher). 979 */ 980$emulate_fpu 981 /* 982 * We get back to C via the normal generic trap 983 * mechanism, as opposed to switching to a special 984 * stack, setting up a trapframe, etc., ourselves, 985 * for three reasons. 986 * 987 * One, I want to turn interrupts back on, since 988 * the emulation code might not be fast. Two, 989 * because the instruction to emulate might be 990 * a load or a store, I need to turn address 991 * translation back on (i.e., return to virtual 992 * mode.) Third, doing both of those plus 993 * setting up a trapframe is a pain, and the 994 * generic trap handling already does it all. 995 * 996 * To relieve trap() from having to check for 997 * sfu and non-FPU instructions again, it assumes 998 * that these kinds of instructions have already 999 * been translated into some other trap type (as 1000 * they have, by the above $emulate_sfu and 1001 * $emulate_coproc), and all T_EMULATION | T_USER 1002 * traps are FPU instructions that need emulating. 1003 * 1004 * So we just restore %arg0 and trap with 1005 * T_EMULATION. 1006 */ 1007 mfctl tr2, %arg0 1008 b TLABEL(all) 1009 ldi T_EMULATION, %r1 1010EXIT(TLABEL(emu)) 1011 1012/* 1013 * void hppa_fpu_swap(struct user *user_out, struct user *user_in); 1014 */ 1015LEAF_ENTRY(hppa_fpu_swap) 1016 1017 /* 1018 * Note that this function must work in 1019 * physical mode as well as virtual mode, 1020 * because it can be called by a trap 1021 * handler. This also further restricts 1022 * the registers we can use. We can only 1023 * use %arg0, %arg1, and %r1. 1024 */ 1025 1026 /* 1027 * Assuming that user_out and user_in aren't 1028 * both NULL, we will have to run coprocessor 1029 * instructions, so we'd better enable it. 1030 * 1031 * Also, branch if there's no FPU state 1032 * to swap out. 1033 */ 1034 mfctl ccr, %r1 1035 depi 3, 25, 2, %r1 1036 comb,= %r0, %arg0, $fpu_swap_in 1037 mtctl %r1, ccr 1038 1039 /* 1040 * Swap out the current FPU state. 1041 */ 1042 ldo PCB_FPREGS(%arg0), %arg0 1043 fstds,ma fr0 , 8(%arg0) /* fr0 must be saved first */ 1044 fstds,ma fr1 , 8(%arg0) 1045 fstds,ma fr2 , 8(%arg0) 1046 fstds,ma fr3 , 8(%arg0) 1047 fstds,ma fr4 , 8(%arg0) 1048 fstds,ma fr5 , 8(%arg0) 1049 fstds,ma fr6 , 8(%arg0) 1050 fstds,ma fr7 , 8(%arg0) 1051 fstds,ma fr8 , 8(%arg0) 1052 fstds,ma fr9 , 8(%arg0) 1053 fstds,ma fr10, 8(%arg0) 1054 fstds,ma fr11, 8(%arg0) 1055 fstds,ma fr12, 8(%arg0) 1056 fstds,ma fr13, 8(%arg0) 1057 fstds,ma fr14, 8(%arg0) 1058 fstds,ma fr15, 8(%arg0) 1059 fstds,ma fr16, 8(%arg0) 1060 fstds,ma fr17, 8(%arg0) 1061 fstds,ma fr18, 8(%arg0) 1062 fstds,ma fr19, 8(%arg0) 1063 fstds,ma fr20, 8(%arg0) 1064 fstds,ma fr21, 8(%arg0) 1065 fstds,ma fr22, 8(%arg0) 1066 fstds,ma fr23, 8(%arg0) 1067 fstds,ma fr24, 8(%arg0) 1068 fstds,ma fr25, 8(%arg0) 1069 fstds,ma fr26, 8(%arg0) 1070 fstds,ma fr27, 8(%arg0) 1071 fstds,ma fr28, 8(%arg0) 1072 fstds,ma fr29, 8(%arg0) 1073 fstds,ma fr30, 8(%arg0) 1074 fstds fr31, 0(%arg0) 1075 1076$fpu_swap_in 1077 1078 /* 1079 * Stash the incoming user structure in 1080 * fpu_cur_uspace. Because this variable 1081 * holds a physical address, this means 1082 * that hppa_fpu_swap can only be called 1083 * with a non-zero user_in from physical 1084 * mode (i.e., from the emulation assist 1085 * trap handler). And that's exactly 1086 * what happens now. 1087 * 1088 * So stash fpu_cur_uspace, branching 1089 * past the swap-in code if it is zero. 1090 */ 1091 ldil L%fpu_cur_uspace, %r1 1092 comb,= %r0, %arg1, $fpu_no_swap_in 1093 stw %arg1, R%fpu_cur_uspace(%r1) 1094 1095 /* 1096 * Swap in the new FPU state. 1097 */ 1098 ldo PCB_FPREGS+31*8(%arg1), %arg1 1099 fldds,ma -8(%arg1), fr31 1100 fldds,ma -8(%arg1), fr30 1101 fldds,ma -8(%arg1), fr29 1102 fldds,ma -8(%arg1), fr28 1103 fldds,ma -8(%arg1), fr27 1104 fldds,ma -8(%arg1), fr26 1105 fldds,ma -8(%arg1), fr25 1106 fldds,ma -8(%arg1), fr24 1107 fldds,ma -8(%arg1), fr23 1108 fldds,ma -8(%arg1), fr22 1109 fldds,ma -8(%arg1), fr21 1110 fldds,ma -8(%arg1), fr20 1111 fldds,ma -8(%arg1), fr19 1112 fldds,ma -8(%arg1), fr18 1113 fldds,ma -8(%arg1), fr17 1114 fldds,ma -8(%arg1), fr16 1115 fldds,ma -8(%arg1), fr15 1116 fldds,ma -8(%arg1), fr14 1117 fldds,ma -8(%arg1), fr13 1118 fldds,ma -8(%arg1), fr12 1119 fldds,ma -8(%arg1), fr11 1120 fldds,ma -8(%arg1), fr10 1121 fldds,ma -8(%arg1), fr9 1122 fldds,ma -8(%arg1), fr8 1123 fldds,ma -8(%arg1), fr7 1124 fldds,ma -8(%arg1), fr6 1125 fldds,ma -8(%arg1), fr5 1126 fldds,ma -8(%arg1), fr4 1127 fldds,ma -8(%arg1), fr3 1128 fldds,ma -8(%arg1), fr2 1129 fldds,ma -8(%arg1), fr1 1130 fldds 0(%arg1), fr0 /* fr0 must be restored last */ 1131 1132$fpu_swap_done 1133 1134 /* Increment the switch count and return. */ 1135 ldil L%fpu_csw, %r1 1136 ldw R%fpu_csw(%r1), %arg0 1137 ldo 1(%arg0), %arg0 1138 bv %r0(%rp) 1139 stw %arg0, R%fpu_csw(%r1) 1140 1141$fpu_no_swap_in 1142 1143 /* We didn't swap any FPU state in, so disable the FPU. */ 1144 mfctl ccr, %r1 1145 depi 0, 25, 2, %r1 1146 b $fpu_swap_done 1147 mtctl %r1, ccr 1148EXIT(hppa_fpu_swap) 1149 1150 /* Compute the hpt entry ptr */ 1151#define HPTENT \ 1152 extru r9, 23, 24, r16 /* r16 = (offset >> 8) */ ! \ 1153 zdep r8, 22, 16, r24 /* r24 = (space << 9) */ ! \ 1154 mfctl hptmask, r17 /* r17 = sizeof(HPT)-1 */ ! \ 1155 xor r16, r24, r24 /* r24 ^= r16 */ ! \ 1156 and r17, r24, r24 /* r24 &= r17 */ ! \ 1157 mfctl vtop, r16 /* r16 = address of HPT table */! \ 1158 or r16, r24, r24 /* r24 = HPT entry */ 1159 1160 /* Construct the virtual address tag. */ 1161 /* NB: it is legal for off and t to be the same. */ 1162#define VTAG(sp,off,t) \ 1163 shd %r0, off, 1, t /* t[1..15] = off[0..14] */ ! \ 1164 dep sp, 31, 16, t /* put in the space id */ ! \ 1165 depi 1, 0, 1, t /* and set the valid bit */ 1166 1167#if defined(HP7000_CPU) 1168/* 1169 * int desidhash_s(void) 1170 */ 1171 .align 64 1172LEAF_ENTRY(desidhash_s) 1173ALTENTRY(desidhash_x) 1174 MFCPU_T(DR_CPUCFG,22) /* t1 */ 1175 MFCPU_T(DR_CPUCFG,22) 1176 depi 0, DR0_PCXS_DHE, 3, t1 /* 3 4 DR0_PCXS_DOMAIN|DR0_PCXS_IHE */ 1177 depi 1, DR0_PCXS_EQWSTO, 1, t1 1178 depi 0, DR0_PCXS_DHPMC, 1, t1 1179 depi 0, DR0_PCXS_ILPMC, 1, t1 1180 MTCPU_T(22,DR_CPUCFG) 1181 MTCPU_T(22,DR_CPUCFG) 1182 bv 0(rp) 1183 extru t1, 4, 5, ret0 /* return chip revision */ 1184EXIT(desidhash_s) 1185#endif /* HP7000_CPU */ 1186 1187#ifdef HP7100_CPU 1188/* 1189 * int desidhash_t(void) 1190 */ 1191 .align 64 1192LEAF_ENTRY(desidhash_t) 1193 MFCPU_T(DR_CPUCFG,22) /* t1 */ 1194 MFCPU_T(DR_CPUCFG,22) 1195 depi 0, DR0_PCXT_IHE, 1, t1 1196 depi 0, DR0_PCXT_DHE, 1, t1 1197 depi 0, DR0_PCXT_DHPMC, 1, t1 1198 depi 0, DR0_PCXT_ILPMC, 1, t1 1199 MTCPU_T(22,DR_CPUCFG) 1200 MTCPU_T(22,DR_CPUCFG) 1201 bv 0(rp) 1202 extru t1, 4, 5, ret0 /* return chip revision */ 1203EXIT(desidhash_t) 1204#endif 1205 1206/* 1207 * This is a handler for interruption 20, "TLB dirty bit trap". It 1208 * is used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T). 1209 * Only shadowed registers are available, and they are: 1210 * 1211 * %r1 = C trap number 1212 * %r8 = data address space identifier 1213 * %r9 = data address offset 1214 * %r16 = undefined 1215 * %r17 = undefined 1216 * %r24 = undefined 1217 * %r25 = undefined 1218 */ 1219$tlbd_x 1220$tlbd_s 1221$tlbd_t 1222 /* 1223 * Calculate the offset of the HPT entry into %r24, 1224 * and save it into %cr28 for recovery later, when 1225 * we want to update the HPT. 1226 */ 1227 HPTENT 1228 mtctl r24, cr28 1229 1230 /* 1231 * Search the list of mappings attached to this 1232 * HPT entry until we find the faulting mapping. 1233 * If we don't find it, trap to C. 1234 */ 1235 ldw HPT_ENTRY(r24), r24 1236$hash_loop_tlbd_t 1237 comb,=,n r0, r24, TLABEL(all) 1238 ldw PV_VA(r24), r25 1239 ldw PV_SPACE(r24), r17 1240 comb,<>,n r9, r25, $hash_loop_tlbd_t 1241 ldw PV_HASH(r24), r24 1242 comb,<>,n r8, r17, $hash_loop_tlbd_t 1243 ldw PV_HASH(r24), r24 1244 1245 /* 1246 * We found the faulting mapping. If it is not 1247 * marked TLB_NO_RW_ALIAS, we have to flush all 1248 * other mappings of this page. 1249 */ 1250 ldw PV_TLBPROT(r24), r25 1251 bb,>=,n %r25, TLB_NO_RW_ALIAS_POS, $flush_all_tlbd_t 1252 1253 /* 1254 * Otherwise, just calculate the HPT tag, set the 1255 * dirty bit on the mapping, and load it into the 1256 * HPT and TLB. 1257 */ 1258$load_tlbd_t 1259 VTAG(%r8, %r9, %r16) 1260 b $tlb_inshpt_t 1261 depi 1, TLB_DIRTY_POS, 1, r25 1262 1263 /* 1264 * This flushes all other mappings of the page. Since 1265 * the flushing subroutine destroys %r8, %r9, and %r25, 1266 * we have to reload them before we can continue. 1267 */ 1268$flush_all_tlbd_t 1269 bl $flush_all_tlbd, %r1 1270 nop 1271 copy %r0, %r1 1272 DTLBPRE 1273 ldw PV_TLBPROT(%r24), %r25 1274 b $load_tlbd_t 1275 1276/* 1277 * This is a handler for interruption 6, "Instruction TLB miss fault", 1278 * and interruption 16, "Non-access instruction TLB miss fault". It 1279 * is used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T). 1280 * Only shadowed registers are available, and they are: 1281 * 1282 * %r1 = C trap number 1283 * %r8 = instruction address space identifier 1284 * %r9 = instruction address offset 1285 * %r16 = undefined 1286 * %r17 = undefined 1287 * %r24 = undefined 1288 * %r25 = undefined 1289 */ 1290$itlb_x 1291$itlb_s 1292$itlb_t 1293 depi 1, TFF_ITLB_POS, 1, r1 /* mark for ITLB insert */ 1294 /* FALLTHROUGH */ 1295 1296/* 1297 * This is a handler for interruption 15, "Data TLB miss fault", 1298 * and interruption 17, "Non-access data TLB miss fault". It is 1299 * used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T). 1300 * Only shadowed registers are available, and they are: 1301 * 1302 * %r1 = C trap number 1303 * %r8 = data address space identifier 1304 * %r9 = data address offset 1305 * %r16 = undefined 1306 * %r17 = undefined 1307 * %r24 = undefined 1308 * %r25 = undefined 1309 */ 1310$dtlb_x 1311$dtlbna_x 1312$dtlb_s 1313$dtlbna_s 1314$dtlb_t 1315$dtlbna_t 1316 /* 1317 * Calculate the offset of the HPT entry into %r24, 1318 * and save it into %cr28 for recovery later, when 1319 * we want to update the HPT. 1320 */ 1321 HPTENT 1322 mtctl r24, cr28 1323 1324 /* 1325 * Calculate the HPT tag for the faulting address 1326 * and compare it against the one in the HPT entry. 1327 * If they are different, we must find the mapping 1328 * for the faulting address. 1329 */ 1330 ldw HPT_TAG(r24),r17 1331 VTAG(%r8, %r9, %r16) 1332 comb,<>,n r16, r17, $tlb_gottalook_t 1333 1334 /* 1335 * Otherwise, do the TLB insertion using the 1336 * information in the HPT entry. 1337 */ 1338 ldw HPT_TLBPAGE(r24), r17 1339 b $tlb_gothpt_t 1340 ldw HPT_TLBPROT(r24), r25 1341 1342$tlb_gottalook_t 1343 /* 1344 * Search the list of mappings attached to this 1345 * HPT entry until we find the faulting mapping. 1346 * If we don't find it, branch to a subhandler 1347 * that checks for a non-access fault caused by 1348 * an LPA instruction. 1349 */ 1350 ldw HPT_ENTRY(r24),r24 1351$hash_loop_t 1352 comb,=,n r0, r24, $tlbiflpa 1353 ldw PV_VA(r24),r25 1354 ldw PV_SPACE(r24),r17 1355 comb,<>,n r9,r25,$hash_loop_t 1356 ldw PV_HASH(r24),r24 1357 comb,<>,n r8,r17,$hash_loop_t 1358 ldw PV_HASH(r24),r24 1359 1360 /* 1361 * If this mapping is not marked TLB_REF, and 1362 * it isn't marked TLB_NO_RW_ALIAS, we have to 1363 * flush any writable mapping for this page. 1364 * Since TLB_REF and TLB_NO_RW_ALIAS are adjacent, 1365 * we can test if they are both clear with one 1366 * extru instruction. 1367 */ 1368 ldw PV_TLBPROT(r24),r25 1369 extru,<> %r25, TLB_NO_RW_ALIAS_POS, 2, %r0 1370 b,n $flush_writable_t 1371 1372 /* Mark this mapping as referenced. */ 1373 depi 1, TLB_REF_POS, 1, r25 1374 /* FALLTHROUGH */ 1375 1376/* 1377 * Load the HPT entry with a mapping. On entry: 1378 * 1379 * %r1 = C trap number 1380 * %r8 = address space identifier 1381 * %r9 = address offset 1382 * %r16 = HPT tag 1383 * %r17 = undefined 1384 * %r24 = mapping 1385 * %r25 = TLB protection 1386 * %cr28 = HPT entry 1387 */ 1388$tlb_inshpt_t 1389 stw r25, PV_TLBPROT(r24) 1390 ldw PV_TLBPAGE(r24),r17 1391 mfctl cr28, r24 1392 1393 stw r16, HPT_TAG(r24) 1394 stw r25, HPT_TLBPROT(r24) 1395 stw r17, HPT_TLBPAGE(r24) 1396 /* FALLTHROUGH */ 1397 1398/* 1399 * Do the real TLB insertion. On entry: 1400 * 1401 * %r1 = C trap number 1402 * %r8 = address space identifier 1403 * %r9 = address offset 1404 * %r16 = undefined 1405 * %r17 = TLB page 1406 * %r24 = undefined 1407 * %r25 = TLB protection 1408 */ 1409$tlb_gothpt_t 1410 mfsp sr1, r16 1411 bb,< r1, TFF_ITLB_POS, $tlb_itlb_t 1412 mtsp r8, sr1 1413 1414 idtlba r17,(sr1, r9) 1415 idtlbp r25,(sr1, r9) 1416 nop ! nop 1417 mtsp r16, sr1 1418 rfir 1419 nop 1420 1421$tlb_itlb_t 1422 iitlba r17,(sr1, r9) 1423 iitlbp r25,(sr1, r9) 1424 nop ! nop 1425 mtsp r16, sr1 1426 rfir 1427 nop 1428 1429/* 1430 * Flush any writable mapping in the TLB and cache, in order 1431 * to insert a readable mapping. On entry: 1432 * 1433 * %r1 = C trap number 1434 * %r8 = undefined 1435 * %r9 = undefined 1436 * %r16 = undefined 1437 * %r17 = undefined 1438 * %r24 = struct pv_entry * of readable mapping 1439 * %r25 = undefined 1440 */ 1441$flush_writable_t 1442 /* 1443 * Branch if this was an ITLB fault. 1444 */ 1445 bb,<,n %r1, TFF_ITLB_POS, $flush_writable_itlb_t 1446 1447 /* 1448 * Flush any writable mapping, then reload registers 1449 * for a DTLB insertion. 1450 */ 1451 bl $flush_writable, %r1 1452 nop 1453 copy %r0, %r1 1454 DTLBPRE 1455 VTAG(%r8, %r9, %r16) 1456 ldw PV_TLBPROT(%r24), %r25 1457 b $tlb_inshpt_t 1458 depi 1, TLB_REF_POS, 1, %r25 1459 1460$flush_writable_itlb_t 1461 /* 1462 * Flush any writable mapping, then reload registers 1463 * for an ITLB insertion. 1464 */ 1465 bl $flush_writable, %r1 1466 nop 1467 ldil L%TFF_ITLB, %r1 1468 ITLBPRE 1469 VTAG(%r8, %r9, %r16) 1470 ldw PV_TLBPROT(%r24), %r25 1471 b $tlb_inshpt_t 1472 depi 1, TLB_REF_POS, 1, %r25 1473 1474#ifdef HP7100LC_CPU 1475/* 1476 * int 1477 * ibtlb_l(int i, pa_space_t sp, vaddr_t va, paddr_t pa, vsize_t sz, u_int prot) 1478 */ 1479LEAF_ENTRY(ibtlb_l) 1480 rsm (PSW_R|PSW_I), t4 1481 1482 bv 0(rp) 1483 mtsm t4 1484EXIT(ibtlb_l) 1485 1486/* 1487 * int 1488 * pbtlb_l(int i) 1489 */ 1490LEAF_ENTRY(pbtlb_l) 1491 ; DR_PAGE0 1492 rsm (PSW_R|PSW_I), t4 1493 ldil L%0xc041, t1 1494 dep arg0, 30, 3, t1 1495 MTCPU_T(22,DR_DTLB) /* t1 */ 1496 mtsp r0, sr1 1497 idtlba r0,(sr1,r0) 1498 idtlbp r0,(sr1,r0) 1499 zdepi -1, 18, 1, t1 1500 MTCPU_T(22,DR_DTLB) 1501 bv 0(rp) 1502 mtsm t4 1503EXIT(pbtlb_l) 1504 1505/* 1506 * int desidhash_l(void) 1507 */ 1508LEAF_ENTRY(desidhash_l) 1509 MFCPU_C(DR_CPUCFG,22) /* t1 */ 1510 depi 0, DR0_PCXL_L2IHASH_EN, 2, t1 /* + DR0_PCXL_L2DHASH_EN */ 1511 depi 0, DR0_PCXL_L2IHPMC, 1, t1 /* don't reset */ 1512 depi 0, DR0_PCXL_L2DHPMC, 1, t1 /* don't reset */ 1513 depi 0, DR0_PCXL_L1IHPMC, 1, t1 /* don't reset */ 1514 depi 0, DR0_PCXL_L2PARERR,1, t1 /* don't reset */ 1515 /* set DR0_PCXL_L1ICACHE_EN ??? */ 1516 MTCPU_C(22,DR_CPUCFG) 1517 bv 0(rp) 1518 extru t1, 4, 5, ret0 /* return chip revision */ 1519EXIT(desidhash_l) 1520 1521 1522/* 1523 * This is a handler for interruption 20, "TLB dirty bit trap". It 1524 * is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), PA8000 (PCX-U), 1525 * PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). Only shadowed 1526 * registers are available, and they are: 1527 * 1528 * %r1 = C trap number 1529 * %r8 = data address space identifier 1530 * %r9 = data address offset 1531 * %r16 = undefined 1532 * %r17 = undefined 1533 * %r24 = undefined 1534 * %r25 = undefined 1535 */ 1536$tlbd_l 1537 /* 1538 * Calculate the offset of the HPT entry into %r24, 1539 * and save it into %cr28 for recovery later, when 1540 * we want to update the HPT. 1541 */ 1542 HPTENT 1543 mtctl %r24, %cr28 1544 1545 /* 1546 * Search the list of mappings attached to this 1547 * HPT entry until we find the faulting mapping. 1548 * If we don't find it, trap to C. 1549 */ 1550 ldw HPT_ENTRY(r24), r16 1551$hash_loop_tlbd_l 1552 comb,=,n r0, r16, TLABEL(all) 1553 ldw PV_VA(r16), r25 1554 ldw PV_SPACE(r16), r17 1555 comb,<>,n r9, r25, $hash_loop_tlbd_l 1556 ldw PV_HASH(r16), r16 1557 comb,<>,n r8, r17, $hash_loop_tlbd_l 1558 ldw PV_HASH(r16), r16 1559 1560 /* 1561 * We found the faulting mapping. If it is not 1562 * marked TLB_NO_RW_ALIAS, we have to flush all 1563 * other mappings of this page. 1564 */ 1565 ldw PV_TLBPAGE(r16), r17 1566 ldw PV_TLBPROT(r16), r25 1567 bb,>=,n %r25, TLB_NO_RW_ALIAS_POS, $flush_all_tlbd_l 1568 1569 /* 1570 * Otherwise, set the dirty bit on the mapping, and 1571 * load it into the HPT and TLB. 1572 */ 1573 b $tlb_inshpt_l 1574 depi 1, TLB_DIRTY_POS, 1, r25 1575 1576 /* 1577 * This flushes all other mappings of the page. Since 1578 * the flushing subroutine destroys effectively preserves 1579 * only the address of the writable mapping, we have to 1580 * reload all other registers before we can continue. 1581 */ 1582$flush_all_tlbd_l 1583 bl $flush_all_tlbd, %r1 1584 copy %r16, %r24 1585 copy %r0, %r1 /* reload %r1, 0 => DTLB */ 1586 DTLBPRE /* reload %r8, %r9 */ 1587 copy %r24, %r16 /* reload %r16 */ 1588 mfctl %cr28, %r24 /* reload %r24 */ 1589 ldw PV_TLBPAGE(%r16), %r17 /* reload %r17 */ 1590 ldw PV_TLBPROT(%r16), %r25 /* reload %r25 */ 1591 b $tlb_inshpt_l 1592 depi 1, TLB_DIRTY_POS, 1, %r25 /* set dirty bit */ 1593 1594/* 1595 * This is a handler for interruption 6, "Instruction TLB miss fault", 1596 * and interruption 16, "Non-access instruction TLB miss fault". It 1597 * is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), PA8000 (PCX-U), 1598 * PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). Only shadowed 1599 * registers are available, and they are: 1600 * 1601 * %r1 = C trap number 1602 * %r8 = instruction address space identifier 1603 * %r9 = instruction address offset 1604 * %r16 = undefined 1605 * %r17 = undefined 1606 * %r24 = undefined 1607 * %r25 = undefined 1608 */ 1609$itlb_l 1610 depi 1, TFF_ITLB_POS, 1, r1 /* mark for ITLB insert */ 1611 /* FALLTHROUGH */ 1612 1613/* 1614 * This is a handler for interruption 17, "Non-access data TLB miss 1615 * fault". It is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), 1616 * PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). 1617 * Only shadowed registers are available, and they are: 1618 * 1619 * %r1 = C trap number 1620 * %r8 = data address space identifier 1621 * %r9 = data address offset 1622 * %r16 = undefined 1623 * %r17 = undefined 1624 * %r24 = undefined 1625 * %r25 = undefined 1626 */ 1627$dtlbna_l 1628 /* 1629 * Calculate the offset of the HPT entry into %r24, 1630 * and save it into %cr28 for recovery later, when 1631 * we want to update the HPT. 1632 * 1633 * XXX fredette: does the PA7100LC not provide the 1634 * HPT entry in %cr28 for a non-access DTLB miss? 1635 * What about an ITLB miss or non-access ITLB miss? 1636 * Having this here, if unnecessary, hurts the 1637 * performance of all of these faults. 1638 */ 1639 HPTENT 1640 mtctl r24, cr28 1641 /* FALLTHROUGH */ 1642 1643/* 1644 * This is a handler for interruption 15, "Data TLB miss fault". 1645 * It is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), 1646 * PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+). 1647 * Only shadowed registers are available, and they are: 1648 * 1649 * %r1 = C trap number 1650 * %r8 = data address space identifier 1651 * %r9 = data address offset 1652 * %r16 = undefined 1653 * %r17 = undefined 1654 * %r24 = undefined 1655 * %r25 = undefined 1656 */ 1657$dtlb_l 1658 /* 1659 * On entry, %cr28 contains the address of the 1660 * relevant HPT entry, courtesy of hpti_g's call 1661 * to PDC_TLB(8)/PDC_TLB_CONFIG(1) asking for 1662 * PDC_TLB_CURRPDE. 1663 */ 1664 mfctl cr28, r24 1665 1666 /* 1667 * Search the list of mappings attached to this 1668 * HPT entry until we find the faulting mapping. 1669 * If we don't find it, branch to a subhandler 1670 * that checks for a non-access fault caused by 1671 * an LPA instruction. 1672 */ 1673 ldw HPT_ENTRY(r24), r16 1674$hash_loop_l 1675 comb,=,n r0, r16, $tlbiflpa 1676 ldw PV_VA(r16), r25 1677 ldw PV_SPACE(r16), r17 1678 comb,<>,n r9, r25, $hash_loop_l 1679 ldw PV_HASH(r16), r16 1680 comb,<>,n r8, r17, $hash_loop_l 1681 ldw PV_HASH(r16), r16 1682 1683 /* 1684 * If this mapping is not marked TLB_REF, and 1685 * it isn't marked TLB_NO_RW_ALIAS, we have to 1686 * flush any writable mapping for this page. 1687 * Since TLB_REF and TLB_NO_RW_ALIAS are adjacent, 1688 * we can test if they are both clear with one 1689 * extru instruction. 1690 */ 1691 ldw PV_TLBPAGE(r16), r17 1692 ldw PV_TLBPROT(r16), r25 1693 extru,<> %r25, TLB_NO_RW_ALIAS_POS, 2, %r0 1694 b,n $flush_writable_l 1695 1696 /* Mark this mapping as referenced. */ 1697 depi 1, TLB_REF_POS, 1, r25 1698 1699/* 1700 * Load the HPT entry and TLB with a mapping. On entry: 1701 * 1702 * %r1 = C trap number 1703 * %r8 = address space identifier 1704 * %r9 = address offset 1705 * %r16 = mapping 1706 * %r17 = TLB page 1707 * %r24 = HPT entry 1708 * %r25 = TLB protection 1709 */ 1710$tlb_inshpt_l 1711 stw r25, PV_TLBPROT(r16) 1712 VTAG(%r8, %r9, %r16) 1713 1714 stw r16, HPT_TAG(r24) 1715 stw r25, HPT_TLBPROT(r24) 1716 bb,< r1, TFF_ITLB_POS, $tlb_itlb_l 1717 stw r17, HPT_TLBPAGE(r24) 1718 1719 .word 0x04111440 ; idtlbaf r17 1720 .word 0x04191400 ; idtlbpf r25 1721 nop ! nop 1722 rfir 1723 nop 1724 1725$tlb_itlb_l 1726 .word 0x04110440 ; iitlbaf r17 1727 .word 0x04190400 ; iitlbpf r25 1728 nop ! nop 1729 rfir 1730 nop 1731 1732/* 1733 * Flush any writable mapping in the TLB and cache, in order 1734 * to insert a readable mapping. On entry: 1735 * 1736 * %r1 = C trap number 1737 * %r8 = undefined 1738 * %r9 = undefined 1739 * %r16 = struct pv_entry * of readable mapping 1740 * %r17 = undefined 1741 * %r24 = undefined 1742 * %r25 = undefined 1743 */ 1744$flush_writable_l 1745 /* 1746 * Branch if this was an ITLB fault. 1747 */ 1748 bb,<,n %r1, TFF_ITLB_POS, $flush_writable_itlb_l 1749 1750 /* 1751 * Flush any writable mapping, then reload registers 1752 * for an HPT and DTLB insertion. 1753 */ 1754 bl $flush_writable, %r1 1755 copy %r16, %r24 1756 copy %r0, %r1 /* reload %r0, 0 => DTLB */ 1757 DTLBPRE /* reload %r8, %r9 */ 1758 copy %r24, %r16 /* reload %r16 */ 1759 ldw PV_TLBPAGE(%r16), %r17 /* reload %r17 */ 1760 ldw PV_TLBPROT(%r16), %r25 /* reload %r25 */ 1761 mfctl %cr28, %r24 /* reload %r24 */ 1762 b $tlb_inshpt_l 1763 depi 1, TLB_REF_POS, 1, %r25 /* set ref bit */ 1764 1765$flush_writable_itlb_l 1766 /* 1767 * Flush any writable mapping, then reload registers 1768 * for an HPT and ITLB insertion. 1769 */ 1770 bl $flush_writable, %r1 1771 copy %r16, %r24 1772 ldil L%TFF_ITLB, %r1 /* reload %r0 */ 1773 ITLBPRE /* reload %r8, %r9 */ 1774 copy %r24, %r16 /* reload %r16 */ 1775 ldw PV_TLBPAGE(%r16), %r17 /* reload %r17 */ 1776 ldw PV_TLBPROT(%r16), %r25 /* reload %r25 */ 1777 mfctl %cr28, %r24 /* reload %r24 */ 1778 b $tlb_inshpt_l 1779 depi 1, TLB_REF_POS, 1, %r25 /* set ref bit */ 1780 1781#endif /* HP7100LC_CPU */ 1782 1783 .export $tlbiflpa, entry 1784$tlbiflpa 1785 ldi T_DTLBMISSNA, r16 1786 mfctl iir, r17 1787 comb,<>,n r1, r16, TLABEL(all) 1788 extru r17, 5, 6, r16 1789 ldi 0x4d, r25 1790 comib,<>,n 1, r16, TLABEL(all) 1791 extru r17, 25, 8, r16 1792 comb,<>,n r25, r16, TLABEL(all) 1793 1794 /* ok, this is a miss in LPA */ 1795 mfctl ipsw, r16 1796 depi 1, PSW_N_POS, 1, r16 1797 depi 0, 26, 27, r17 1798 mtctl r16, ipsw 1799 1800 ldi $tlbiflpa_zr, r25 1801 bv r17(r25) 1802$tlbiflpa_zr 1803 copy r0, r0 ! rfir 1804 copy r0, r1 ! rfir 1805 copy r0, r2 ! rfir 1806 copy r0, r3 ! rfir 1807 copy r0, r4 ! rfir 1808 copy r0, r5 ! rfir 1809 copy r0, r6 ! rfir 1810 copy r0, r7 ! rfir 1811 copy r0, r8 ! rfir 1812 copy r0, r9 ! rfir 1813 copy r0, r10 ! rfir 1814 copy r0, r11 ! rfir 1815 copy r0, r12 ! rfir 1816 copy r0, r13 ! rfir 1817 copy r0, r14 ! rfir 1818 copy r0, r15 ! rfir 1819 copy r0, r16 ! rfir 1820 copy r0, r17 ! rfir 1821 copy r0, r18 ! rfir 1822 copy r0, r19 ! rfir 1823 copy r0, r20 ! rfir 1824 copy r0, r21 ! rfir 1825 copy r0, r22 ! rfir 1826 copy r0, r23 ! rfir 1827 copy r0, r24 ! rfir 1828 copy r0, r25 ! rfir 1829 copy r0, r26 ! rfir 1830 copy r0, r27 ! rfir 1831 copy r0, r28 ! rfir 1832 copy r0, r29 ! rfir 1833 copy r0, r30 ! rfir 1834 copy r0, r31 ! rfir 1835 1836 .export $tlb_missend, entry 1837$tlb_missend 1838 1839 .align 64 1840 .export TLABEL(all), entry 1841ENTRY(TLABEL(all),0) 1842 /* r1 still has trap type */ 1843 1844 /* 1845 * at this point we have: 1846 * psw copied into ipsw 1847 * psw = E(default), M(1 if HPMC, else 0) 1848 * PL = 0 1849 * r1, r8, r9, r16, r17, r24, r25 shadowed (maybe) 1850 * trap number in r1 (old r1 is saved in tr7) 1851 */ 1852 1853 /* do not overwrite tr4(cr28) */ 1854 mtctl t3, tr2 1855 1856 ldil L%$trap_tmp_save, t3 1857 stw t1, TF_R22(t3) /* use ,bc */ 1858 stw t2, TF_R21(t3) 1859 1860 mfctl tr2, t1 1861 stw sp, TF_R30(t3) /* sp */ 1862 stw t1, TF_R20(t3) /* t3 */ 1863 1864 /* 1865 * Now, save away other volatile state that prevents us from turning 1866 * the PC queue back on, namely, the pc queue and ipsw, and the 1867 * interrupt information. 1868 */ 1869 1870 mfctl eiem, t1 1871 mfctl ipsw, t2 1872 stw t1, TF_CR15(t3) /* use ,bc */ 1873 stw t2, TF_CR22(t3) 1874 1875 mfsp sr3, t1 1876 mfctl pidr1, t2 1877 stw t1, TF_SR3(t3) 1878 stw t2, TF_CR8(t3) 1879 1880 /* 1881 * Setup kernel context 1882 */ 1883 1884 ldi HPPA_PID_KERNEL,t1 1885 mtctl t1, pidr1 1886 mtsp r0, sr3 1887 1888 /* this will enable interrupts after `cold' */ 1889 ldil L%kpsw, t1 1890 ldw R%kpsw(t1), t2 1891 mtctl r0, eiem 1892 mtctl t2, ipsw 1893 1894 mfctl pcsq, t1 1895 mtctl r0, pcsq 1896 mfctl pcsq, t2 1897 stw t1, TF_IISQH(t3) /* use ,bc */ 1898 stw t2, TF_IISQT(t3) 1899 mtctl r0, pcsq 1900 1901 /* 1902 * Set up the kernel stack pointer. If the trap happened 1903 * while we were in unprivileged code, or in privileged 1904 * code in the SYSCALLGATE page, move to the kernel stack 1905 * in curproc's PCB; otherwise, start a new stack frame 1906 * on whatever kernel stack we're already on. 1907 * 1908 * This used to check only for a trap while we were in 1909 * unprivileged code, but this ignored the possibility 1910 * that a trap could come in during the period between 1911 * a gateway instruction to raise privilege and the 1912 * disabling of interrupts. During this period we're 1913 * still on the user's stack, and we must move to the 1914 * kernel stack. 1915 */ 1916 mfctl pcoq, t1 1917 ldil L%SYSCALLGATE, t2 1918 /* Start aligning the assumed kernel sp. */ 1919 ldo HPPA_FRAME_SIZE-1(sp), sp 1920 /* This dep leaves t2 with SYSCALLGATE | (pcoqh & PAGE_MASK). */ 1921 dep t1, 31, PGSHIFT, t2 1922 /* Nullify if pcoqh & HPPA_PC_PRIV_MASK != 0. */ 1923 dep,<> t1, 31, 2, r0 1924 /* Branch if (pcoqh & ~PAGE_MASK) != SYSCALLGATE */ 1925 comb,<> t1, t2, $trap_from_kernel 1926 /* Finish aligning the assumed kernel sp. */ 1927 dep r0, 31, 6, sp 1928 1929 mfctl cr30, t2 1930 depi 1, T_USER_POS, 1, r1 1931 depi 1, TFF_LAST_POS, 1, r1 1932 ldw U_PCB+PCB_UVA(t2), sp 1933#ifdef DIAGNOSTIC 1934 b $trap_have_stack 1935#endif 1936 ldo NBPG(sp), sp 1937 1938$trap_from_kernel 1939#ifdef DIAGNOSTIC 1940 /* 1941 * Use the emergency stack if we have taken some kind 1942 * of TLB or protection fault on the kernel stack. 1943 */ 1944 mtctl t1, tr2 1945 ldw TF_R30(t3), t1 1946 mfctl ior, t2 1947 dep r0, 31, PGSHIFT, t1 1948 dep r0, 31, PGSHIFT, t2 1949 comb,=,n t1, t2, 0 1950 ldo NBPG(t1), t1 1951 comb,<> t1, t2, $trap_have_stack 1952 mfctl tr2, t1 1953 mfctl isr, t2 1954 comib,<>,n HPPA_SID_KERNEL, t2, $trap_have_stack 1955#define _CHECK_TRAP_TYPE(tt) ldi tt, t2 ! comb,= r1, t2, $trap_kstack_fault 1956 _CHECK_TRAP_TYPE(T_ITLBMISS) 1957 _CHECK_TRAP_TYPE(T_DTLBMISS) 1958 _CHECK_TRAP_TYPE(T_ITLBMISSNA) 1959 _CHECK_TRAP_TYPE(T_DTLBMISSNA) 1960 _CHECK_TRAP_TYPE(T_DPROT) 1961 _CHECK_TRAP_TYPE(T_DATACC) 1962 _CHECK_TRAP_TYPE(T_DATAPID) 1963 ldi T_DATALIGN, t2 1964 comb,<>,n r1, t2, $trap_have_stack 1965#undef _CHECK_TRAP_TYPE 1966$trap_kstack_fault 1967 ldil L%emergency_stack_start, sp 1968 ldo R%emergency_stack_start(sp), sp 1969$trap_have_stack 1970#endif 1971 ldil L%$trapnowvirt, t2 1972 ldo R%$trapnowvirt(t2), t2 1973 mtctl t2, pcoq 1974 stw t1, TF_IIOQH(t3) 1975 ldo 4(t2), t2 1976 mfctl pcoq, t1 1977 stw t1, TF_IIOQT(t3) 1978 mtctl t2, pcoq 1979 1980 mfctl isr, t1 1981 mfctl ior, t2 1982 stw t1, TF_CR20(t3) /* use ,bc */ 1983 stw t2, TF_CR21(t3) 1984 1985 mfctl iir, t2 1986 stw t2, TF_CR19(t3) 1987 stw r1, TF_FLAGS(t3) 1988 mfctl tr7, r1 1989 1990 copy sp, t3 1991 ldo HPPA_FRAME_SIZE+TRAPFRAME_SIZEOF(sp), sp 1992 rfir 1993 nop 1994$trapnowvirt 1995 /* 1996 * t3 contains the virtual address of the trapframe 1997 * sp is loaded w/ the right VA (we did not need it being physical) 1998 */ 1999 2000 mfsp sr0, t1 2001 mfsp sr1, t2 2002 stw t1, TF_SR0(sr3, t3) 2003 stw t2, TF_SR1(sr3, t3) 2004 2005 mfsp sr2, t1 2006 mfsp sr4, t2 2007 stw t1, TF_SR2(sr3, t3) 2008 stw t2, TF_SR4(sr3, t3) 2009 2010 mfsp sr5, t2 2011 mfsp sr6, t1 2012 stw t2, TF_SR5(sr3, t3) 2013 stw t1, TF_SR6(sr3, t3) 2014 2015 mfsp sr7, t1 2016 mfctl pidr2, t2 2017 stw t1, TF_SR7(sr3, t3) 2018 stw t2, TF_CR9(sr3, t3) 2019 2020 mtsp r0, sr0 2021 mtsp r0, sr1 2022 mtsp r0, sr2 2023 mtsp r0, sr4 2024 mtsp r0, sr5 2025 mtsp r0, sr6 2026 mtsp r0, sr7 2027 2028#if pbably_not_worth_it 2029 mfctl pidr3, t1 2030 mfctl pidr4, t2 2031 stw t1, TF_CR12(t3) 2032 stw t2, TF_CR13(t3) 2033#endif 2034 2035 /* 2036 * Save all general registers that we haven't saved already 2037 */ 2038 2039#if defined(DDB) || defined(KGDB) 2040 stw rp, HPPA_FRAME_CRP(sp) 2041 stw r0, -HPPA_FRAME_SIZE(sp) 2042#endif 2043 stw t3, -HPPA_FRAME_SIZE+4(sp) 2044 2045 mfctl sar, t1 /* use ,bc each cache line */ 2046 stw t1, TF_CR11(t3) 2047 stw r1, TF_R1(t3) 2048 stw r2, TF_R2(t3) 2049 stw r3, TF_R3(t3) 2050 2051 /* 2052 * Copy partially saved state from the store into the frame 2053 */ 2054 ldil L%$trap_tmp_save, t2 2055 /* use ,bc each line */ 2056 ldw 0(t2), r1 ! ldw 4(t2), t1 ! stw r1, 0(t3) ! stw t1, 4(t3) 2057 ldw 8(t2), r1 ! ldw 12(t2), t1 ! stw r1, 8(t3) ! stw t1, 12(t3) 2058 ldw 16(t2), r1 ! ldw 20(t2), t1 ! stw r1, 16(t3) ! stw t1, 20(t3) 2059 ldw 24(t2), r1 ! ldw 28(t2), t1 ! stw r1, 24(t3) ! stw t1, 28(t3) 2060 ldw 32(t2), r1 ! ldw 36(t2), t1 ! stw r1, 32(t3) ! stw t1, 36(t3) 2061 ldw 40(t2), r1 ! ldw 44(t2), t1 ! stw r1, 40(t3) ! stw t1, 44(t3) 2062 ldw 48(t2), r1 ! ldw 52(t2), t1 ! stw r1, 48(t3) ! stw t1, 52(t3) 2063 ldw 56(t2), r1 ! ldw 60(t2), t1 ! stw r1, 56(t3) ! stw t1, 60(t3) 2064 2065 /* 2066 * Normally, we'd only have to save and restore the 2067 * caller-save registers, because the callee-save 2068 * registers will be saved and restored automatically 2069 * by our callee(s). 2070 * 2071 * However, in two cases we need to save and restore 2072 * all of the general registers in the trapframe. One, 2073 * if we're running a debugger, we want the debugging 2074 * person to be able to see and change any and all 2075 * general register values at the trap site. Two, 2076 * if we have an FPU emulator, this trap may be to 2077 * emulate an instruction that needs to read and write 2078 * any and all general registers (for example, a load 2079 * or store instruction with a modify completer). 2080 * 2081 * See similar #ifdefs in the syscall entry and exit code. 2082 */ 2083#if defined(DDB) || defined(KGDB) || defined(FPEMUL) 2084 stw r4, TF_R4(t3) 2085 stw r5, TF_R5(t3) 2086 stw r6, TF_R6(t3) 2087 stw r7, TF_R7(t3) 2088 stw r8, TF_R8(t3) 2089 stw r9, TF_R9(t3) 2090 stw r10, TF_R10(t3) 2091 stw r11, TF_R11(t3) 2092 stw r12, TF_R12(t3) 2093 stw r13, TF_R13(t3) 2094 stw r14, TF_R14(t3) 2095 stw r15, TF_R15(t3) 2096 stw r16, TF_R16(t3) 2097 stw r17, TF_R17(t3) 2098 stw r18, TF_R18(t3) 2099#endif /* DDB || KGDB || FPEMUL */ 2100 stw t4, TF_R19(t3) 2101 stw r23,TF_R23(t3) 2102 stw r24,TF_R24(t3) 2103 stw r25,TF_R25(t3) 2104 stw r26,TF_R26(t3) 2105 stw r27,TF_R27(t3) 2106 stw r28,TF_R28(t3) 2107 stw r29,TF_R29(t3) 2108 stw r31,TF_R31(t3) 2109 2110 /* 2111 * Save the necessary control registers that have not already saved. 2112 */ 2113 2114 mfctl rctr, t1 2115 stw t1, TF_CR0(t3) 2116 /* XXX save ccr here w/ rctr */ 2117 2118#if defined(DDB) || defined(KGDB) 2119 /* 2120 * Save hpt mask and v2p translation table pointer 2121 */ 2122 mfctl eirr, t1 2123 mfctl hptmask, t2 2124 stw t1, TF_CR23(t3) 2125 stw t2, TF_CR24(t3) 2126 2127 mfctl vtop, t1 2128 mfctl cr28, t2 2129 stw t1, TF_CR25(t3) 2130 stw t2, TF_CR28(t3) 2131#endif 2132 mfctl cr30, t1 2133 stw t1, TF_CR30(t3) 2134 2135 /* 2136 * load the global pointer for the kernel 2137 */ 2138 2139 ldil L%$global$, dp 2140 ldo R%$global$(dp), dp 2141 2142 /* 2143 * call the C routine trap(). 2144 * form trap type in the first argument to trap() 2145 */ 2146 ldw TF_FLAGS(t3), arg0 2147 dep r0, 24, 25, arg0 2148 copy t3, arg1 2149 2150#if defined(DDB) || defined(KGDB) 2151 ldo -HPPA_FRAME_SIZE(sp), r3 2152#endif 2153 .import trap, code 2154 ldil L%trap,t1 2155 ldo R%trap(t1),t1 2156 .call 2157 blr r0,rp 2158 bv,n r0(t1) 2159 nop 2160 2161 ldw -HPPA_FRAME_SIZE+4(sp), t3 2162 /* see if curproc have changed */ 2163 ldw TF_FLAGS(t3), arg0 2164 bb,>=,n arg0, TFF_LAST_POS, $trap_return 2165 nop 2166 2167 /* see if curproc have really changed */ 2168 ldil L%curproc, t1 2169 ldw R%curproc(t1), t2 2170 comb,=,n r0, t2, $trap_return 2171 2172 /* means curproc have actually changed */ 2173 ldw P_MD(t2), t3 2174 2175$trap_return 2176 ldil L%$syscall_return, t1 2177 ldo R%$syscall_return(t1), t1 2178 bv,n r0(t1) 2179 nop 2180 2181 .export $trap$all$end, entry 2182$trap$all$end 2183EXIT(TLABEL(all)) 2184 2185 .align 32 2186 .export TLABEL(ibrk), entry 2187ENTRY(TLABEL(ibrk),0) 2188 mtctl t1, tr2 2189 mtctl t2, tr3 2190 2191 /* If called by a user process then always pass it to trap() */ 2192 mfctl pcoq, t1 2193 extru,= t1, 31, 2, r0 2194 b,n $ibrk_bad 2195 2196 /* don't accept breaks from data segments */ 2197 .import etext 2198 ldil L%etext, t2 2199 ldo R%etext(t2), t2 2200 comb,>>=,n t1, t2, $ibrk_bad 2201 2202 mfctl iir, t1 2203 extru t1, 31, 5, t2 2204 comib,<>,n HPPA_BREAK_KERNEL, t2, $ibrk_bad 2205 2206 /* now process all those `break' calls we make */ 2207 extru t1, 18, 13, t2 2208 comib,=,n HPPA_BREAK_GET_PSW, t2, $ibrk_getpsw 2209 comib,=,n HPPA_BREAK_SET_PSW, t2, $ibrk_setpsw 2210 2211$ibrk_bad 2212 /* illegal (unimplemented) break entry point */ 2213 mfctl tr3, t2 2214 b TLABEL(all) 2215 mfctl tr2, t1 2216 2217$ibrk_getpsw 2218 b $ibrk_exit 2219 mfctl ipsw, ret0 2220 2221$ibrk_setpsw 2222 mfctl ipsw, ret0 2223 b $ibrk_exit 2224 mtctl arg0, ipsw 2225 2226 /* insert other fast breaks here */ 2227 nop ! nop 2228 2229$ibrk_exit 2230 /* skip the break */ 2231 mtctl r0, pcoq 2232 mfctl pcoq, t1 2233 mtctl t1, pcoq 2234 ldo 4(t1), t1 2235 mtctl t1, pcoq 2236 mfctl tr3, t2 2237 mfctl tr2, t1 2238 mfctl tr7, r1 2239 rfi 2240 nop 2241EXIT(TLABEL(ibrk)) 2242 2243/* 2244 * This macro changes the tlbpage register from a tlbpage 2245 * value into the struct pv_head * for that page. It also 2246 * junks another register. 2247 * 2248 * The extru gets the physical page number out of the tlbpage, 2249 * and since sizeof(struct pv_head) == 8, we can use sh3add to 2250 * generate the final struct pv_head *. 2251 */ 2252#define PV_HEAD(tlbpage, junk) \ 2253 ldil L%pv_head_tbl, junk ! \ 2254 extru tlbpage, 26, 20, tlbpage ! \ 2255 ldw R%pv_head_tbl(junk), junk ! \ 2256 sh3add tlbpage, junk, tlbpage 2257 2258/* 2259 * This macro copies the referenced and dirty information 2260 * from a TLB protection to a pv_head_writable_dirty_ref 2261 * value, but only if the TLB protection is managed. The 2262 * magic 12 targets the instruction after the macro. 2263 */ 2264#define PV_MODREF(tlbprot, pv_head_wdr) \ 2265 bb,<,n tlbprot, TLB_UNMANAGED_POS, 12 ! \ 2266 extru,= tlbprot, TLB_REF_POS, 1, %r0 ! \ 2267 depi 1, PV_HEAD_REF_POS, 1, pv_head_wdr ! \ 2268 extru,= tlbprot, TLB_DIRTY_POS, 1, %r0 ! \ 2269 depi 1, PV_HEAD_DIRTY_POS, 1, pv_head_wdr 2270 2271/* 2272 * This subroutine flushes all mappings of a page out of the TLB 2273 * and cache, in order to install a writable mapping. Only shadowed 2274 * registers are available, and they are: 2275 * 2276 * %r1 = INPUT: return address, OUTPUT: preserved 2277 * %r8 = INPUT: undefined, OUTPUT: destroyed 2278 * %r9 = INPUT: undefined, OUTPUT: destroyed 2279 * %r16 = INPUT: undefined, OUTPUT: destroyed 2280 * %r17 = INPUT: undefined, OUTPUT: destroyed 2281 * %r24 = INPUT: struct pv_entry * of writable mapping, OUTPUT: preserved 2282 * %r25 = INPUT: undefined, OUTPUT: destroyed 2283 */ 2284$flush_all_tlbd 2285 2286 /* 2287 * Find the struct pv_head for this physical page. 2288 * If this writable mapping is managed, we know 2289 * for sure that this page is now referenced 2290 * and dirty. The ldi sets both PV_HEAD_REF_POS 2291 * and PV_HEAD_DIRTY_POS. 2292 */ 2293 ldw PV_TLBPAGE(%r24), %r17 2294 ldw PV_TLBPROT(%r24), %r25 2295 PV_HEAD(%r17, %r16) 2296 ldi 3, %r16 2297 bb,>=,n %r25, TLB_UNMANAGED_POS, $flush_all_tlbd_set_wdr 2298 2299 /* 2300 * Otherwise, this writable mapping is unmanaged, 2301 * which means we need to save referenced and dirty 2302 * information from all managed mappings that we're 2303 * about to flush. 2304 */ 2305 copy %r0, %r16 2306 ldw PV_HEAD_PVS(%r17), %r8 2307 ldw PV_TLBPROT(%r8), %r25 2308$flush_all_tlbd_modref_loop 2309 ldw PV_NEXT(%r8), %r8 2310 PV_MODREF(%r25, %r16) 2311 comb,<>,n %r0, %r8, $flush_all_tlbd_modref_loop 2312 ldw PV_TLBPROT(%r8), %r25 2313 2314$flush_all_tlbd_set_wdr 2315 /* 2316 * Now set the pv_head_writable_dirty_ref field, 2317 * preserving any previously set referenced and 2318 * dirty bits, and noting that this writable 2319 * mapping is the current writable mapping. 2320 */ 2321 ldw PV_HEAD_WRITABLE_DIRTY_REF(%r17), %r8 2322 or %r24, %r16, %r16 2323 depi 0, PV_HEAD_WRITABLE_POS, 30, %r8 2324 or %r16, %r8, %r8 2325 stw %r8, PV_HEAD_WRITABLE_DIRTY_REF(%r17) 2326 2327 /* 2328 * Now flush all other mappings out of the cache. 2329 */ 2330 ldw PV_HEAD_PVS(%r17), %r17 2331 bl 0, %r16 2332$flush_all_tlbd_loop 2333 comb,<> %r17, %r24, $flush_mapping 2334 nop 2335 ldw PV_NEXT(%r17), %r17 2336 comb,<> %r17, %r0, $flush_all_tlbd_loop 2337 nop 2338 2339 /* Return to our caller. */ 2340 bv %r0(%r1) 2341 nop 2342 2343/* 2344 * This subroutine flushes any writable mapping of a page out of the 2345 * TLB and cache, in order to install a readable mapping. Only shadowed 2346 * registers are available, and they are: 2347 * 2348 * %r1 = INPUT: return address, OUTPUT: preserved 2349 * %r8 = INPUT: undefined, OUTPUT: destroyed 2350 * %r9 = INPUT: undefined, OUTPUT: destroyed 2351 * %r16 = INPUT: undefined, OUTPUT: destroyed 2352 * %r17 = INPUT: undefined, OUTPUT: destroyed 2353 * %r24 = INPUT: struct pv_entry * of readable mapping, OUTPUT: preserved 2354 * %r25 = INPUT: undefined, OUTPUT: destroyed 2355 */ 2356$flush_writable 2357 2358 /* Find the struct pv_head for this physical page. */ 2359 ldw PV_TLBPAGE(%r24), %r17 2360 PV_HEAD(%r17, %r16) 2361 2362 /* 2363 * If this page doesn't have a writable mapping 2364 * entered into the TLB and cache, return. The 2365 * single depi clears both PV_HEAD_REF_POS and 2366 * PV_HEAD_DIRTY_POS. 2367 */ 2368 ldw PV_HEAD_WRITABLE_DIRTY_REF(%r17), %r16 2369 copy %r16, %r8 2370 depi,<> 0, PV_HEAD_REF_POS, 2, %r16 2371 bv,n %r0(%r1) 2372 2373 /* 2374 * Clear the writable mapping, preserving the 2375 * current referenced and dirty bits. 2376 */ 2377 depi 0, PV_HEAD_WRITABLE_POS, 30, %r8 2378 stw %r8, PV_HEAD_WRITABLE_DIRTY_REF(%r17) 2379 2380 /* 2381 * Flush the writable mapping. We have $flush_mapping 2382 * return directly to our caller. 2383 */ 2384 copy %r16, %r17 2385 b $flush_mapping 2386 copy %r1, %r16 2387 2388/* 2389 * This flushes a mapping out of the TLB and cache. Only shadowed 2390 * registers are available, and on entry they are: 2391 * 2392 * %r1 = INPUT: undefined, OUTPUT: preserved 2393 * %r8 = INPUT: undefined, OUTPUT: destroyed 2394 * %r9 = INPUT: undefined, OUTPUT: destroyed 2395 * %r16 = INPUT: return address, OUTPUT: preserved 2396 * %r17 = INPUT: mapping to flush, OUTPUT: preserved 2397 * %r24 = INPUT: undefined, OUTPUT: preserved 2398 * %r25 = INPUT: undefined, OUTPUT: destroyed 2399 * 2400 * NB: this function assumes that, once inserted, a TLB entry 2401 * remains inserted as long as the only virtual references made 2402 * use that TLB entry. This function must be called in physical 2403 * mode. 2404 */ 2405$flush_mapping 2406 2407 /* 2408 * If this mapping has not been referenced, it cannot 2409 * be in the TLB and cache, so just return. 2410 */ 2411 ldw PV_TLBPROT(%r17), %r25 2412 extru,<> %r25, TLB_REF_POS, 1, %r0 2413 bv,n %r0(%r16) 2414 2415 /* 2416 * Clear the referenced and dirty bits, save %sr1 2417 * into %r8, load the space into %sr1, load the 2418 * virtual address into %r9. If the mapping is 2419 * not executable, skip the instruction cache flush. 2420 * (Bit 6 is the "execute" bit in the TLB protection, 2421 * assuming that we never see gateway page protections.) 2422 */ 2423 ldw PV_SPACE(%r17), %r9 2424 depi 0, TLB_REF_POS, 1, %r25 2425 mfsp %sr1, %r8 2426 depi 0, TLB_DIRTY_POS, 1, %r25 2427 mtsp %r9, %sr1 2428 ldw PV_VA(%r17), %r9 2429 bb,>= %r25, 6, $flush_mapping_data 2430 stw %r25, PV_TLBPROT(%r17) 2431 2432 /* 2433 * Load this mapping into the ITLB and the DTLB, since 2434 * fic may use the DTLB. 2435 */ 2436 ldw PV_TLBPAGE(%r17), %r25 2437 iitlba %r25, (%sr1, %r9) 2438 idtlba %r25, (%sr1, %r9) 2439 ldw PV_TLBPROT(%r17), %r25 2440 iitlbp %r25, (%sr1, %r9) 2441 idtlbp %r25, (%sr1, %r9) 2442 nop 2443 nop 2444 2445 /* Load the instruction cache stride. */ 2446 ldil L%icache_stride, %r25 2447 ldw R%icache_stride(%r25), %r25 2448 2449 /* 2450 * Enable data address translation (fic explicitly uses 2451 * the D-bit to determine whether virtual or absolute 2452 * addresses are used), and flush the instruction cache 2453 * using a loop of 16 fic instructions. */ 2454 ssm PSW_D, %r0 2455$flush_mapping_fic_loop 2456 fic,m %r25(%sr1, %r9) 2457 fic,m %r25(%sr1, %r9) 2458 fic,m %r25(%sr1, %r9) 2459 fic,m %r25(%sr1, %r9) 2460 fic,m %r25(%sr1, %r9) 2461 fic,m %r25(%sr1, %r9) 2462 fic,m %r25(%sr1, %r9) 2463 fic,m %r25(%sr1, %r9) 2464 fic,m %r25(%sr1, %r9) 2465 fic,m %r25(%sr1, %r9) 2466 fic,m %r25(%sr1, %r9) 2467 fic,m %r25(%sr1, %r9) 2468 fic,m %r25(%sr1, %r9) 2469 fic,m %r25(%sr1, %r9) 2470 fic,m %r25(%sr1, %r9) 2471 fic,m %r25(%sr1, %r9) 2472 /* Stop looping if the page offset bits are all zero. */ 2473 extru,= %r9, 31, PGSHIFT, %r0 2474 b,n $flush_mapping_fic_loop 2475 2476 /* Sync. */ 2477 sync 2478 nop 2479 nop 2480 syncdma 2481 2482 /* Disable data address translation. */ 2483 rsm PSW_D, %r0 2484 2485 /* Reload the virtual address and purge the ITLB. */ 2486 ldw PV_VA(%r17), %r9 2487 pitlb %r0(%sr1, %r9) 2488 2489$flush_mapping_data 2490 2491 /* Load this mapping into the DTLB. */ 2492 ldw PV_TLBPAGE(%r17), %r25 2493 idtlba %r25, (%sr1, %r9) 2494 ldw PV_TLBPROT(%r17), %r25 2495 idtlbp %r25, (%sr1, %r9) 2496 nop 2497 nop 2498 2499 /* Load the data cache stride. */ 2500 ldil L%dcache_stride, %r25 2501 ldw R%dcache_stride(%r25), %r25 2502 2503 /* 2504 * Enable data address translation and flush the data cache 2505 * using a loop of 16 fdc instructions. */ 2506 ssm PSW_D, %r0 2507$flush_mapping_fdc_loop 2508 fdc,m %r25(%sr1, %r9) 2509 fdc,m %r25(%sr1, %r9) 2510 fdc,m %r25(%sr1, %r9) 2511 fdc,m %r25(%sr1, %r9) 2512 fdc,m %r25(%sr1, %r9) 2513 fdc,m %r25(%sr1, %r9) 2514 fdc,m %r25(%sr1, %r9) 2515 fdc,m %r25(%sr1, %r9) 2516 fdc,m %r25(%sr1, %r9) 2517 fdc,m %r25(%sr1, %r9) 2518 fdc,m %r25(%sr1, %r9) 2519 fdc,m %r25(%sr1, %r9) 2520 fdc,m %r25(%sr1, %r9) 2521 fdc,m %r25(%sr1, %r9) 2522 fdc,m %r25(%sr1, %r9) 2523 fdc,m %r25(%sr1, %r9) 2524 /* Stop looping if the page offset bits are all zero. */ 2525 extru,= %r9, 31, PGSHIFT, %r0 2526 b,n $flush_mapping_fdc_loop 2527 2528 /* Sync. */ 2529 sync 2530 nop 2531 nop 2532 syncdma 2533 2534 /* Disable data address translation. */ 2535 rsm PSW_D, %r0 2536 2537 /* Reload the virtual address and purge the DTLB. */ 2538 ldw PV_VA(%r17), %r9 2539 pdtlb %r0(%sr1, %r9) 2540 2541 /* Restore %sr1. */ 2542 mtsp %r8, %sr1 2543 2544 /* 2545 * If this mapping is in the HPT, invalidate the 2546 * HPT entry. 2547 */ 2548 ldw PV_SPACE(%r17), %r8 2549 ldw PV_HPT(%r17), %r25 2550 VTAG(%r8, %r9, %r9) 2551 ldw HPT_TAG(%r25), %r8 2552 comb,<>,n %r8, %r9, $flush_mapping_done 2553 zdepi -1, 31, 16, %r8 /* Make an invalid HPT tag. */ 2554 stw %r8, HPT_TAG(%r25) 2555 2556$flush_mapping_done 2557 /* Return. */ 2558 bv %r0(%r16) 2559 nop 2560 2561/* 2562 * void __pmap_pv_update(paddr_t pa, struct pv_entry *pv, 2563 * u_int tlbprot_clear, u_int tlbprot_set); 2564 * 2565 * This is the helper function for _pmap_pv_update. It flushes 2566 * one or more mappings of page pa and changes their protection. 2567 * tlbprot_clear and tlbprot_set describe the protection changes. 2568 * If pv is non-NULL, that mapping is flushed and takes all of 2569 * the protection changes. If tlbprot_clear features any of 2570 * TLB_REF, TLB_DIRTY, and TLB_NO_RW_ALIAS, all other mappings of 2571 * the page are flushed and take only those protection changes. 2572 * 2573 * All of this work is done in physical mode. 2574 */ 2575ENTRY(__pmap_pv_update,64) 2576 2577 /* Start stack calling convention. */ 2578 stw %rp, HPPA_FRAME_CRP(%sp) 2579 copy %r3, %r1 2580 copy %sp, %r3 2581 stw,ma %r1, HPPA_FRAME_SIZE*2(%sp) 2582 2583 /* 2584 * Save various callee-saved registers. Note that as 2585 * part of the stack calling convention, the caller's 2586 * %r3 was saved at 0(%r3). 2587 */ 2588 stw %r8, 4(%r3) 2589 stw %r9, 8(%r3) 2590 stw %r16, 12(%r3) 2591 stw %r17, 16(%r3) 2592 2593 /* 2594 * Disable interrupts and enter physical mode, but leave the 2595 * interruption queues on. This will leave the previous PSW 2596 * in %ret0, where it will remain untouched until we're ready 2597 * to return to virtual mode. 2598 */ 2599 copy arg0, t1 2600 ldi PSW_Q, arg0 2601 break HPPA_BREAK_KERNEL, HPPA_BREAK_SET_PSW 2602 copy t1, arg0 2603 2604 /* 2605 * Find the struct pv_head for this physical page. 2606 * If this is a page in I/O space, conjure up a fake 2607 * struct pv_head on the stack. 2608 */ 2609 shd %r0, arg0, (PGSHIFT - 5), t1 /* t1 = tlbbtop(arg0) */ 2610 ldil L%HPPA_IOSPACE, t2 2611 copy %r0, %r1 /* fake pv_head_wrd value */ 2612 comb,<<= t2, arg0, $pmap_pv_update_given 2613 ldo 20(%r3), arg0 /* fake pv_head pointer */ 2614 copy t1, arg0 2615 PV_HEAD(arg0, t1) 2616 ldw PV_HEAD_WRITABLE_DIRTY_REF(arg0), %r1 2617 2618 /* 2619 * This helper macro saves TLB_REF and TLB_DIRTY from 2620 * a managed mapping, and if that mapping is the currently 2621 * loaded writable mapping, clears that. Then it 2622 * flushes the mapping (saving %r25 around the call 2623 * to $flush_mapping) and updates its protection. 2624 * It destroys the t1 register. 2625 */ 2626#define PV_UPDATE(pv) \ 2627 ldw PV_TLBPROT(pv), t1 ! \ 2628 PV_MODREF(t1, %r1) ! \ 2629 copy %r1, t1 ! \ 2630 depi 0, PV_HEAD_REF_POS, 2, t1 ! \ 2631 comb,<>,n t1, pv, 0 ! \ 2632 depi 0, PV_HEAD_WRITABLE_POS, 30, %r1 ! \ 2633 copy %r25, t1 ! \ 2634 bl $flush_mapping, %r16 ! \ 2635 copy pv, %r17 ! \ 2636 copy t1, %r25 ! \ 2637 ldw PV_TLBPROT(pv), t1 ! \ 2638 andcm t1, arg2, t1 ! \ 2639 or t1, arg3, t1 ! \ 2640 stw t1, PV_TLBPROT(pv) 2641 2642$pmap_pv_update_given 2643 2644 /* If pv is non-NULL, flush and update that mapping. */ 2645 comb,=,n %r0, arg1, $pmap_pv_update_others 2646 PV_UPDATE(arg1) 2647 2648$pmap_pv_update_others 2649 2650 /* 2651 * If none of TLB_REF, TLB_DIRTY, or TLB_NO_RW_ALIAS are 2652 * set in tlbprot_clear, we're done. 2653 */ 2654 zdepi 1, TLB_REF_POS, 1, t1 2655 depi 1, TLB_DIRTY_POS, 1, t1 2656 depi 1, TLB_NO_RW_ALIAS_POS, 1, t1 2657 and,<> arg2, t1, arg2 2658 b $pmap_pv_update_done 2659 and arg3, t1, arg3 2660 2661 /* 2662 * Otherwise, update all of the mappings of this page, 2663 * skipping any mapping we did above. 2664 */ 2665 ldw PV_HEAD_PVS(arg0), %r17 2666$pmap_pv_update_loop 2667 comb,=,n %r17, %r0, $pmap_pv_update_done 2668 comb,=,n %r17, arg1, $pmap_pv_update_loop 2669 ldw PV_NEXT(%r17), %r17 2670 PV_UPDATE(%r17) 2671 b $pmap_pv_update_loop 2672 ldw PV_NEXT(%r17), %r17 2673 2674$pmap_pv_update_done 2675 2676 /* Store the new pv_head_writable_ref_dirty value. */ 2677 stw %r1, PV_HEAD_WRITABLE_DIRTY_REF(arg0) 2678 2679 /* 2680 * Return to virtual mode and reenable interrupts. 2681 */ 2682 copy ret0, arg0 2683 break HPPA_BREAK_KERNEL, HPPA_BREAK_SET_PSW 2684 2685 /* 2686 * Restore various callee-saved registers. Note that 2687 * as part of the stack calling convention, the caller's 2688 * %r3 was saved at 0(%r3) and is restored at the end. 2689 */ 2690 ldw 4(%r3), %r8 2691 ldw 8(%r3), %r9 2692 ldw 12(%r3), %r16 2693 ldw 16(%r3), %r17 2694 2695 /* End stack calling convention. */ 2696 ldw HPPA_FRAME_CRP(%r3), %rp 2697 ldo HPPA_FRAME_SIZE(%r3), %sp 2698 ldw,mb -HPPA_FRAME_SIZE(%sp), %r3 2699 2700 /* Return. */ 2701 bv %r0(%rp) 2702 nop 2703EXIT(__pmap_pv_update) 2704