1/* $NetBSD: locore.s,v 1.89 2002/05/14 02:03:02 matt Exp $ */ 2 3/* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1980, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah $Hdr: locore.s 1.66 92/12/22$ 41 * 42 * @(#)locore.s 8.6 (Berkeley) 5/27/94 43 */ 44 45#include "opt_compat_netbsd.h" 46#include "opt_compat_svr4.h" 47#include "opt_compat_sunos.h" 48#include "opt_fpsp.h" 49#include "opt_ddb.h" 50#include "opt_kgdb.h" 51#include "opt_lockdebug.h" 52 53#include "assym.h" 54#include <machine/asm.h> 55#include <machine/trap.h> 56 57 58/* 59 * Temporary stack for a variety of purposes. 60 * Try and make this the first thing is the data segment so it 61 * is page aligned. Note that if we overflow here, we run into 62 * our text segment. 63 */ 64 .data 65 .space NBPG 66ASLOCAL(tmpstk) 67 68ASLOCAL(bug_vbr) 69 .long 0 70 71#include <mvme68k/mvme68k/vectors.s> 72 73 74/* 75 * Macro to relocate a symbol, used before MMU is enabled. 76 */ 77#define _RELOC(var, ar) \ 78 lea var,ar 79 80#define RELOC(var, ar) _RELOC(_C_LABEL(var), ar) 81#define ASRELOC(var, ar) _RELOC(_ASM_LABEL(var), ar) 82 83/* 84 * Macro to call into the Bug ROM monitor 85 */ 86#define CALLBUG(func) \ 87 trap #15; .short func 88 89/* 90 * Initialization 91 * 92 * The bootstrap loader loads us in starting at 0, and VBR is non-zero. 93 * On entry, args on stack are boot device, boot filename, console unit, 94 * boot flags (howto), boot device name, filesystem type name. 95 */ 96BSS(lowram,4) 97BSS(esym,4) 98 99 .globl _C_LABEL(edata) 100 .globl _C_LABEL(etext),_C_LABEL(end) 101 102 103/* 104 * This is for kvm_mkdb, and should be the address of the beginning 105 * of the kernel text segment (not necessarily the same as kernbase). 106 */ 107 .text 108GLOBAL(kernel_text) 109 110/* 111 * start of kernel and .text! 112 */ 113ASENTRY_NOPROFILE(start) 114 movw #PSL_HIGHIPL,%sr | no interrupts 115 movl #0,%a5 | RAM starts at 0 (a5) 116 movl %sp@(4), %d7 | get boothowto 117 movl %sp@(8), %d6 | get bootaddr 118 movl %sp@(12),%d5 | get bootctrllun 119 movl %sp@(16),%d4 | get bootdevlun 120 movl %sp@(20),%d3 | get bootpart 121 movl %sp@(24),%d2 | get esyms 122 123 RELOC(bootpart,%a0) 124 movl %d3, %a0@ | save bootpart 125 RELOC(bootdevlun,%a0) 126 movl %d4, %a0@ | save bootdevlun 127 RELOC(bootctrllun,%a0) 128 movl %d5, %a0@ | save booctrllun 129 RELOC(bootaddr,%a0) 130 movl %d6, %a0@ | save bootaddr 131 RELOC(boothowto,%a0) 132 movl %d7, %a0@ | save boothowto 133 /* note: d3-d7 free, d2 still in use */ 134 135 ASRELOC(tmpstk, %a0) 136 movl %a0,%sp | give ourselves a temporary stack 137 138 RELOC(edata,%a0) | clear out BSS 139 movl #_C_LABEL(end) - 4, %d0 | (must be <= 256 kB) 140 subl #_C_LABEL(edata), %d0 141 lsrl #2,%d0 1421: clrl %a0@+ 143 dbra %d0,1b 144 145 RELOC(esym, %a0) 146 movl %d2,%a0@ | store end of symbol table 147 /* d2 now free */ 148 RELOC(lowram, %a0) 149 movl %a5,%a0@ | store start of physical memory 150 movl #CACHE_OFF,%d0 151 movc %d0,%cacr | clear and disable on-chip cache(s) 152 153 /* ask the Bug what we are... */ 154 clrl %sp@- 155 CALLBUG(MVMEPROM_GETBRDID) 156 movl %sp@+,%a1 157 158 /* copy to a struct mvmeprom_brdid */ 159 movl #MVMEPROM_BRDID_SIZE,%d0 160 RELOC(boardid,%a0) 1611: movb %a1@+,%a0@+ 162 subql #1,%d0 163 jbne 1b 164 165 /* 166 * Grab the model number from _boardid and use the value 167 * to setup machineid, cputype, and mmutype. 168 */ 169 clrl %d0 170 RELOC(boardid,%a1) 171 movw %a1@(MVMEPROM_BRDID_MODEL_OFFSET),%d0 172 RELOC(machineid,%a0) 173 movl %d0,%a0@ 174 175 ASRELOC(Lbrdid2mach,%a0) 176Lbrdmatch: 177 cmpw %a0@+,%d0 178 jbeq Lgotmatch 179 addw #0x12,%a0 | Each entry is 20-2 bytes long 180 tstw %a0@ 181 jbne Lbrdmatch 182 183 /* 184 * If we fall to here, the board is not supported. 185 * Print a warning, then drop out to the Bug. 186 */ 187 movl #Lenotconf,%sp@- 188 movl #Lnotconf,%sp@- 189 CALLBUG(MVMEPROM_OUTSTRCRLF) 190 addql #8,%sp | clean up stack after call 191 192 CALLBUG(MVMEPROM_EXIT) 193 /* NOTREACHED */ 194 195 .data 196Lnotconf: 197 .ascii "Sorry, the kernel isn't configured for this model." 198Lenotconf: 199 .even 200 201ASLOCAL(Lbrdid2mach) 202#ifdef MVME147 203 .word MVME_147 204 .word CPU_68030 205 .word MMU_68030 206 .word FPU_68882 207 .long _C_LABEL(busaddrerr2030) 208 .long _C_LABEL(busaddrerr2030) 209 .long Linit147 210#endif 211#ifdef MVME162 212 .word MVME_162 213 .word CPU_68040 214 .word MMU_68040 215 .word FPU_68040 216 .long _C_LABEL(buserr40) 217 .long _C_LABEL(addrerr4060) 218 .long Linit1x2 219#endif 220#ifdef MVME167 221 .word MVME_167 222 .word CPU_68040 223 .word MMU_68040 224 .word FPU_68040 225 .long _C_LABEL(buserr40) 226 .long _C_LABEL(addrerr4060) 227 .long Linit1x7 228#endif 229#ifdef MVME172 230 .word MVME_172 231 .word CPU_68060 232 .word MMU_68040 233 .word FPU_68060 234 .long _C_LABEL(buserr60) 235 .long _C_LABEL(addrerr4060) 236 .long Linit1x2 237#endif 238#ifdef MVME177 239 .word MVME_177 240 .word CPU_68060 241 .word MMU_68040 242 .word FPU_68060 243 .long _C_LABEL(buserr60) 244 .long _C_LABEL(addrerr4060) 245 .long Linit1x7 246#endif 247 .word 0 248 .text 249 .even 250 251/* 252 * We have a match, so the kernel should support this board. 253 * a0 points to the matching entry in Lbrdid2mach. 254 */ 255Lgotmatch: 256 movew %a0@+,%d1 | Copy the CPU type 257 extl %d1 258 RELOC(cputype,%a1) 259 movel %d1,%a1@ 260 movew %a0@+,%d1 | Copy the MMU type 261 extl %d1 262 RELOC(mmutype,%a1) 263 movel %d1,%a1@ 264 movew %a0@+,%d1 | Copy the FPU type 265 extl %d1 266 RELOC(fputype,%a1) 267 movel %d1,%a1@ 268 movel %a0@+,%a2 | Fetch the bus error vector 269 RELOC(vectab,%a1) 270 movl %a2,%a1@(8) 271 movel %a0@+,%a2 | Fetch the address error vector 272 movl %a2,%a1@(12) 273 movel %a0@,%a0 | Finally, the board-specific init code 274 jmp %a0@ 275 276 277#ifdef MVME147 278Linit147: 279 /* MVME-147 - 68030 CPU/MMU, 68882 FPU */ 280 /* XXXCDC SHUTUP 147 CALL */ 281 movb #0, 0xfffe1026 | serial interrupt off 282 movb #0, 0xfffe1018 | timer 1 off 283 movb #0, 0xfffe1028 | ethernet off 284 /* XXXCDC SHUTUP 147 CALL */ 285 286 /* Save our ethernet address */ 287 RELOC(mvme_ea, %a0) 288 lea 0xfffe0778,%a1 | XXXCDC -- HARDWIRED HEX 289 movb #0x08,%a0@+ 290 clrb %a0@+ 291 movb #0x3e,%a0@+ 292 movql #0x0f,%d0 293 andb %a1@+,%d0 294 orb #0x20,%d0 295 movb %d0,%a0@+ 296 movb %a1@+,%a0@+ 297 movb %a1@,%a0@ 298 299 /* 300 * Fix up the physical addresses of the MVME147's onboard 301 * I/O registers. 302 */ 303 RELOC(intiobase_phys, %a0); 304 movl #INTIOBASE147,%a0@ 305 RELOC(intiotop_phys, %a0); 306 movl #INTIOTOP147,%a0@ 307 308 /* initialise list of physical memory segments for pmap_bootstrap */ 309 RELOC(phys_seg_list, %a0) 310 movl %a5,%a0@ | phys_seg_list[0].ps_start 311 movl 0xfffe0774,%d1 | End + 1 of onboard memory 312 movl %d1,%a0@(4) | phys_seg_list[0].ps_end 313 clrl %a0@(8) | phys_seg_list[0].ps_startpage 314 315 /* offboard RAM */ 316 clrl %a0@(0x0c) | phys_seg_list[1].ps_start 317 movl #NBPG-1,%d0 318 addl 0xfffe0764,%d0 | Start of offboard segment 319 andl #-NBPG,%d0 | Round up to page boundary 320 jbeq Lsavmaxmem | Jump if none defined 321 movl #NBPG,%d1 | Note: implicit '+1' 322 addl 0xfffe0768,%d1 | End of offboard segment 323 andl #-NBPG,%d1 | Round up to page boundary 324 cmpl %d1,%d0 | Quick and dirty validity check 325 jbcs Loff_ok | Yup, looks good. 326 movel %a0@(4),%d1 | Just use onboard RAM otherwise 327 jbra Lsavmaxmem 328Loff_ok: 329 movl %d0,%a0@(0x0c) | phys_seg_list[1].ps_start 330 movl %d1,%a0@(0x10) | phys_seg_list[1].ps_end 331 clrl %a0@(0x14) | phys_seg_list[1].ps_startpage 332 333 /* 334 * Offboard RAM needs to be cleared to zero to initialise parity 335 * on most VMEbus RAM cards. Without this, some cards will buserr 336 * when first read. 337 */ 338 movel %d0,%a0 | offboard start address again. 339Lclearoff: 340 clrl %a0@+ | zap a word 341 cmpl %a0,%d1 | reached end? 342 jbne Lclearoff 343 344Lsavmaxmem: 345 moveq #PGSHIFT,%d2 346 lsrl %d2,%d1 | convert to page (click) number 347 RELOC(maxmem, %a0) 348 movl %d1,%a0@ | save as maxmem 349 jra Lstart1 350#endif 351 352#if defined(MVME162) || defined(MVME172) 353Linit1x2: 354 /* MVME-162 - 68040 CPU/MMU/FPU */ 355 /* MVME-172 - 68060 CPU/MMU/FPU */ 356 357 /* 358 * Verify the user has removed the GPIO#0 jumper... 359 */ 360 btst #0,0xfff4202d | Clear == jumper installed 361 jne 1f | Ok. 362 363 movl #Le1x2jump,%sp@- 364 movl #L1x2jump,%sp@- 365 CALLBUG(MVMEPROM_OUTSTRCRLF) 366 addql #8,%sp | clean up stack after call 367 368 CALLBUG(MVMEPROM_EXIT) 369 /* NOTREACHED */ 370 3711: 372 /* 373 * Determine if this board has a VMEchip2 374 */ 375 btst #1,0xfff4202e | VMEchip2 presence detect 376 jne 2f | Jump if it doesn't exist. 377 378 /* 379 * Disable all interrupts from VMEchip2. This is especially 380 * useful when the kernel doesn't have the VMEchip2 driver 381 * configured. If we didn't do this, then we're at the mercy 382 * of whatever VMEchip2 interrupts the ROM set up. For example, 383 * hitting the ABORT switch could kill the system... 384 */ 385 movl 0xfff40088,%d0 386 andl #0xff7fffff,%d0 | Clear 'MIEN' 387 movl %d0,0xfff40088 3882: 389 /* 390 * Determine how much onboard memory is installed 391 */ 392 movql #0x07,%d0 393 andb 0xfff42024,%d0 394 ASRELOC(Ldramsize1x2,%a0) 395 movl %a0@(%d0:w:4),%d1 | Lookup the size 396 jeq Lmemcquery | Assume a MEMC chip if this is zero. 397 jra Lis1xx_common 398 399 .data 400 .even 401 /* 402 * Table of DRAM register size values -> actual size in bytes 403 */ 404ASLOCAL(Ldramsize1x2) 405 .long 0x00100000 406 .long 0x00200000 407 .long 0x00000000 408 .long 0x00400000 409 .long 0x00400000 410 .long 0x00800000 411 .long 0x00000000 412 .long 0x01000000 413 414L1x2jump: 415 .ascii "You must remove the jumper from pins 15-16 of J22 (mvme162)" 416 .ascii "or pins 1-2\015\012" 417 .ascii "J11 (mvme162-LX) first! See NetBSD/mvme68k FAQ for details." 418Le1x2jump: 419 .even 420 421 .text 422#endif 423 424#if defined(MVME167) || defined(MVME177) 425Linit1x7: 426 /* MVME-167 - 68040 CPU/MMU/FPU */ 427 /* MVME-177 - 68060 CPU/MMU/FPU */ 428 429 /* 430 * Verify the user has removed the GPIO#0 jumper... 431 */ 432 movel #0x00000001,%d0 433 andl 0xfff40088,%d0 | Clear == jumper installed 434 jne 1f | Ok. 435 436 movl #Le1x7jump,%sp@- 437 movl #L1x7jump,%sp@- 438 CALLBUG(MVMEPROM_OUTSTRCRLF) 439 addql #8,%sp | clean up stack after call 440 441 CALLBUG(MVMEPROM_EXIT) 442 /* NOTREACHED */ 443 4441: 445 /* 446 * Disable all interrupts from VMEchip2. This is especially 447 * useful when the kernel doesn't have the VMEchip2 driver 448 * configured. If we didn't do this, then we're at the mercy 449 * of whatever VMEchip2 interrupts the ROM set up. For example, 450 * hitting the ABORT switch could kill the system... 451 */ 452 movl 0xfff40088,%d0 453 andl #0xff7fffff,%d0 | Clear 'MIEN' 454 movl %d0,0xfff40088 455 456 .data 457 .even 458L1x7jump: 459 .ascii "You must remove the jumper from pins 1-2 of J1!\015\012" 460 .ascii "See NetBSD/mvme68k FAQ for details." 461Le1x7jump: 462 .even 463 464 .text 465#endif 466 467#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177) 468Lmemcquery: 469 /* 470 * Figure out the size of onboard DRAM by querying 471 * the memory controller ASIC(s) 472 */ 473 lea 0xfff43008,%a0 | MEMC040/MEMECC Controller #1 474 jbsr memc040read 475 movl %d0,%d1 476 477 lea 0xfff43108,%a0 | MEMC040/MEMECC Controller #2 478 jbsr memc040read 479 addl %d0,%d1 480 481Lis1xx_common: 482 /* Save our ethernet address */ 483 RELOC(mvme_ea, %a0) 484 lea 0xfffc1f2c,%a1 485 movb %a1@+,%a0@+ 486 movb %a1@+,%a0@+ 487 movb %a1@+,%a0@+ 488 movb %a1@+,%a0@+ 489 movb %a1@+,%a0@+ 490 movb %a1@,%a0@ 491 492 /* 493 * Fix up the physical addresses of the onboard 494 * I/O registers. 495 */ 496 RELOC(intiobase_phys, %a0); 497 movl #INTIOBASE1xx,%a0@ 498 RELOC(intiotop_phys, %a0); 499 movl #INTIOTOP1xx,%a0@ 500 501 /* 502 * Initialise first physical memory segment with onboard RAM details 503 */ 504 RELOC(phys_seg_list, %a0) 505 movl %a5,%a0@ | phys_seg_list[0].ps_start 506 movl %d1,%a0@(4) | phys_seg_list[0].ps_end 507 clrl %a0@(8) | phys_seg_list[0].ps_startpage 508 509 /* offboard RAM */ 510 clrl %a0@(0x0c) | phys_seg_list[1].ps_start 511 movl #NBPG-1,%d0 512 addl 0xfffc0000,%d0 | Start of offboard segment 513 andl #-NBPG,%d0 | Round up to page boundary 514 jbeq Ldone1xx | Jump if none defined 515 movl #NBPG,%d1 | Note: implicit '+1' 516 addl 0xfffc0004,%d1 | End of offboard segment 517 andl #-NBPG,%d1 | Round up to page boundary 518 cmpl %d1,%d0 | Quick and dirty validity check 519 jbcs Lramsave1xx | Yup, looks good. 520 movel %a0@(4),%d1 | Just use onboard RAM otherwise 521 jbra Ldone1xx 522 523Lramsave1xx: 524 movl %d0,%a0@(0x0c) | phys_seg_list[1].ps_start 525 movl %d1,%a0@(0x10) | phys_seg_list[1].ps_end 526 clrl %a0@(0x14) | phys_seg_list[1].ps_startpage 527 528 /* 529 * Offboard RAM needs to be cleared to zero to initialise parity 530 * on most VMEbus RAM cards. Without this, some cards will buserr 531 * when first read. 532 */ 533 movel %d0,%a0 | offboard start address again. 534Lramclr1xx: 535 clrl %a0@+ | zap a word 536 cmpl %a0,%d1 | reached end? 537 jbne Lramclr1xx 538 539Ldone1xx: 540 moveq #PGSHIFT,%d2 541 lsrl %d2,%d1 | convert to page (click) number 542 RELOC(maxmem, %a0) 543 movl %d1,%a0@ | save as maxmem 544 545 /* FALLTHROUGH to Lstart1 */ 546#endif 547 548 549Lstart1: 550/* initialize source/destination control registers for movs */ 551 moveq #FC_USERD,%d0 | user space 552 movc %d0,%sfc | as source 553 movc %d0,%dfc | and destination of transfers 554/* 555 * configure kernel and proc0 VA space so we can get going 556 */ 557#ifdef DDB 558 RELOC(esym,%a0) | end of static kernel text/data syms 559 movl %a0@,%d2 560 jne Lstart2 561#endif 562 movl #_C_LABEL(end),%d2 | end of static kernel text/data 563Lstart2: 564 addl #NBPG-1,%d2 565 andl #PG_FRAME,%d2 | round to a page 566 movl %d2,%a4 567 addl %a5,%a4 | convert to PA 568 pea %a5@ | firstpa 569 pea %a4@ | nextpa 570 RELOC(pmap_bootstrap,%a0) 571 jbsr %a0@ | pmap_bootstrap(firstpa, nextpa) 572 addql #8,%sp 573 574/* 575 * Enable the MMU. 576 * Since the kernel is mapped logical == physical, we just turn it on. 577 */ 578 RELOC(Sysseg, %a0) | system segment table addr 579 movl %a0@,%d1 | read value (a KVA) 580 addl %a5,%d1 | convert to PA 581 RELOC(mmutype, %a0) 582 cmpl #MMU_68040,%a0@ | 68040? 583 jne Lmotommu1 | no, skip 584 .long 0x4e7b1807 | movc d1,srp 585 jra Lstploaddone 586Lmotommu1: 587 RELOC(protorp, %a0) 588 movl #0x80000202,%a0@ | nolimit + share global + 4 byte PTEs 589 movl %d1,%a0@(4) | + segtable address 590 pmove %a0@,%srp | load the supervisor root pointer 591 movl #0x80000002,%a0@ | reinit upper half for CRP loads 592Lstploaddone: 593 RELOC(mmutype, %a0) 594 cmpl #MMU_68040,%a0@ | 68040? 595 jne Lmotommu2 | no, skip 596 moveq #0,%d0 | ensure TT regs are disabled 597 .long 0x4e7b0004 | movc d0,itt0 598 .long 0x4e7b0005 | movc d0,itt1 599 .long 0x4e7b0006 | movc d0,dtt0 600 .long 0x4e7b0007 | movc d0,dtt1 601 .word 0xf4d8 | cinva bc 602 .word 0xf518 | pflusha 603 movl #0x8000,%d0 604 .long 0x4e7b0003 | movc d0,tc 605#ifdef M68060 606 RELOC(cputype, %a0) 607 cmpl #CPU_68060,%a0@ | 68060? 608 jne Lnot060cache 609 movl #1,%d0 610 .long 0x4e7b0808 | movcl d0,pcr 611 movl #0xa0808000,%d0 612 movc %d0,%cacr | enable store buffer, both caches 613 jmp Lenab1 614Lnot060cache: 615#endif 616 movl #0x80008000,%d0 617 movc %d0,%cacr | turn on both caches 618 jmp Lenab1 619Lmotommu2: 620 movl #0x82c0aa00,%sp@- | value to load TC with 621 pmove %sp@,%tc | load it 622 623/* 624 * Should be running mapped from this point on 625 */ 626Lenab1: 627/* Point the cpu VBR at our vector table */ 628 movc %vbr,%d0 | Preserve Bug's VBR address 629 movl %d0,_ASM_LABEL(bug_vbr) 630 movl #_C_LABEL(vectab),%d0 | get our VBR address 631 movc %d0,%vbr 632/* select the software page size now */ 633 lea _ASM_LABEL(tmpstk),%sp | temporary stack 634 jbsr _C_LABEL(uvm_setpagesize) | select software page size 635/* set kernel stack, user SP, and initial pcb */ 636 movl _C_LABEL(proc0paddr),%a1 | get proc0 pcb addr 637 lea %a1@(USPACE-4),%sp | set kernel stack to end of area 638 lea _C_LABEL(proc0),%a2 | initialize proc0.p_addr so that 639 movl %a1,%a2@(P_ADDR) | we don't deref NULL in trap() 640 movl #USRSTACK-4,%a2 641 movl %a2,%usp | init user SP 642 movl %a1,_C_LABEL(curpcb) | proc0 is running 643 tstl _C_LABEL(fputype) | Have an FPU? 644 jeq Lenab2 | No, skip. 645 clrl %a1@(PCB_FPCTX) | ensure null FP context 646 movl %a1,%sp@- 647 jbsr _C_LABEL(m68881_restore) | restore it (does not kill a1) 648 addql #4,%sp 649Lenab2: 650 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 651 jeq Ltbia040 | yes, cache already on 652 pflusha 653 movl #CACHE_ON,%d0 654 movc %d0,%cacr | clear cache(s) 655 jra Lenab3 656Ltbia040: 657 .word 0xf518 658Lenab3: 659/* 660 * final setup for C code: 661 * Create a fake exception frame so that cpu_fork() can copy it. 662 * main() nevers returns; we exit to user mode from a forked process 663 * later on. 664 */ 665 jbsr _C_LABEL(mvme68k_init) | additional pre-main initialization 666 movw #PSL_LOWIPL,%sr | lower SPL 667 clrw %sp@- | vector offset/frame type 668 clrl %sp@- | PC - filled in by "execve" 669 movw #PSL_USER,%sp@- | in user mode 670 clrl %sp@- | stack adjust count and padding 671 lea %sp@(-64),%sp | construct space for D0-D7/A0-A7 672 lea _C_LABEL(proc0),%a0 | save pointer to frame 673 movl %sp,%a0@(P_MD_REGS) | in proc0.p_md.md_regs 674 675 jra _C_LABEL(main) | main() 676 677#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177) 678/* 679 * Probe for a memory controller ASIC (MEMC040 or MEMECC) at the 680 * address in a0. If found, return the size in bytes of any RAM 681 * controlled by the ASIC in d0. Otherwise return zero. 682 */ 683ASLOCAL(memc040read) 684 moveml %d1-%d2/%a1-%a2,%sp@- | save scratch regs 685 movc %vbr,%d2 | Save vbr 686 RELOC(vectab,%a2) | Install our own vectab, temporarily 687 movc %a2,%vbr 688 ASRELOC(Lmemc040berr,%a1) | get address of bus error handler 689 movl %a2@(8),%sp@- | Save current bus error handler addr 690 movl %a1,%a2@(8) | Install our own handler 691 movl %sp,%d0 | Save current stack pointer value 692 movql #0x07,%d1 693 andb %a0@,%d1 | Access MEMC040/MEMECC 694 movl #0x400000,%d0 695 lsll %d1,%d0 | Convert to memory size, in bytes 696Lmemc040ret: 697 movc %d2,%vbr | Restore original vbr 698 movl %sp@+,%a2@(8) | Restore original bus error handler 699 moveml %sp@+,%d1-%d2/%a1-%a2 700 rts 701/* 702 * If the memory controller doesn't exist, we get a bus error trying 703 * to access a0@ above. Control passes here, where we flag 'no bytes', 704 * ditch the exception frame and return as normal. 705 */ 706Lmemc040berr: 707 movl %d0,%sp | Get rid of the exception frame 708 movql #0,%d0 | No ASIC at this location, then! 709 jbra Lmemc040ret | Done 710#endif 711 712/* 713 * proc_trampoline: call function in register a2 with a3 as an arg 714 * and then rei. 715 */ 716GLOBAL(proc_trampoline) 717 movl %a3,%sp@- | push function arg 718 jbsr %a2@ | call function 719 addql #4,%sp | pop arg 720 movl %sp@(FR_SP),%a0 | grab and load 721 movl %a0,%usp | user SP 722 moveml %sp@+,#0x7FFF | restore most user regs 723 addql #8,%sp | toss SP and stack adjust 724 jra _ASM_LABEL(rei) | and return 725 726/* 727 * Trap/interrupt vector routines 728 */ 729#include <m68k/m68k/trap_subr.s> 730 731#if defined(M68040) || defined(M68060) 732ENTRY_NOPROFILE(addrerr4060) 733 clrl %sp@- | stack adjust count 734 moveml #0xFFFF,%sp@- | save user registers 735 movl %usp,%a0 | save the user SP 736 movl %a0,%sp@(FR_SP) | in the savearea 737 movl %sp@(FR_HW+8),%sp@- 738 clrl %sp@- | dummy code 739 movl #T_ADDRERR,%sp@- | mark address error 740 jra _ASM_LABEL(faultstkadj) | and deal with it 741#endif 742 743#if defined(M68060) 744ENTRY_NOPROFILE(buserr60) 745 clrl %sp@- | stack adjust count 746 moveml #0xFFFF,%sp@- | save user registers 747 movl %usp,%a0 | save the user SP 748 movl %a0,%sp@(FR_SP) | in the savearea 749 movel %sp@(FR_HW+12),%d0 | FSLW 750 btst #2,%d0 | branch prediction error? 751 jeq Lnobpe 752 movc %cacr,%d2 753 orl #IC60_CABC,%d2 | clear all branch cache entries 754 movc %d2,%cacr 755 movl %d0,%d1 756 andl #0x7ffd,%d1 757 jeq _ASM_LABEL(faultstkadjnotrap2) 758Lnobpe: 759| we need to adjust for misaligned addresses 760 movl %sp@(FR_HW+8),%d1 | grab VA 761 btst #27,%d0 | check for mis-aligned access 762 jeq Lberr3 | no, skip 763 addl #28,%d1 | yes, get into next page 764 | operand case: 3, 765 | instruction case: 4+12+12 766 andl #PG_FRAME,%d1 | and truncate 767Lberr3: 768 movl %d1,%sp@- 769 movl %d0,%sp@- | code is FSLW now. 770 andw #0x1f80,%d0 771 jeq Lberr60 | it is a bus error 772 movl #T_MMUFLT,%sp@- | show that we are an MMU fault 773 jra _ASM_LABEL(faultstkadj) | and deal with it 774Lberr60: 775 tstl _C_LABEL(nofault) | catch bus error? 776 jeq Lisberr | no, handle as usual 777 movl _C_LABEL(nofault),%sp@- | yes, 778 jbsr _C_LABEL(longjmp) | longjmp(nofault) 779 /* NOTREACHED */ 780#endif 781#if defined(M68040) 782ENTRY_NOPROFILE(buserr40) 783 clrl %sp@- | stack adjust count 784 moveml #0xFFFF,%sp@- | save user registers 785 movl %usp,%a0 | save the user SP 786 movl %a0,%sp@(FR_SP) | in the savearea 787 movl %sp@(FR_HW+20),%d1 | get fault address 788 moveq #0,%d0 789 movw %sp@(FR_HW+12),%d0 | get SSW 790 btst #11,%d0 | check for mis-aligned 791 jeq Lbe1stpg | no skip 792 addl #3,%d1 | get into next page 793 andl #PG_FRAME,%d1 | and truncate 794Lbe1stpg: 795 movl %d1,%sp@- | pass fault address. 796 movl %d0,%sp@- | pass SSW as code 797 btst #10,%d0 | test ATC 798 jeq Lberr40 | it is a bus error 799 movl #T_MMUFLT,%sp@- | show that we are an MMU fault 800 jra _ASM_LABEL(faultstkadj) | and deal with it 801Lberr40: 802 tstl _C_LABEL(nofault) | catch bus error? 803 jeq Lisberr | no, handle as usual 804 movl _C_LABEL(nofault),%sp@- | yes, 805 jbsr _C_LABEL(longjmp) | longjmp(nofault) 806 /* NOTREACHED */ 807#endif 808 809#if defined(M68020) || defined(M68030) 810ENTRY_NOPROFILE(busaddrerr2030) 811 clrl %sp@- | stack adjust count 812 moveml #0xFFFF,%sp@- | save user registers 813 movl %usp,%a0 | save the user SP 814 movl %a0,%sp@(FR_SP) | in the savearea 815 moveq #0,%d0 816 movw %sp@(FR_HW+10),%d0 | grab SSW for fault processing 817 btst #12,%d0 | RB set? 818 jeq LbeX0 | no, test RC 819 bset #14,%d0 | yes, must set FB 820 movw %d0,%sp@(FR_HW+10) | for hardware too 821LbeX0: 822 btst #13,%d0 | RC set? 823 jeq LbeX1 | no, skip 824 bset #15,%d0 | yes, must set FC 825 movw %d0,%sp@(FR_HW+10) | for hardware too 826LbeX1: 827 btst #8,%d0 | data fault? 828 jeq Lbe0 | no, check for hard cases 829 movl %sp@(FR_HW+16),%d1 | fault address is as given in frame 830 jra Lbe10 | thats it 831Lbe0: 832 btst #4,%sp@(FR_HW+6) | long (type B) stack frame? 833 jne Lbe4 | yes, go handle 834 movl %sp@(FR_HW+2),%d1 | no, can use save PC 835 btst #14,%d0 | FB set? 836 jeq Lbe3 | no, try FC 837 addql #4,%d1 | yes, adjust address 838 jra Lbe10 | done 839Lbe3: 840 btst #15,%d0 | FC set? 841 jeq Lbe10 | no, done 842 addql #2,%d1 | yes, adjust address 843 jra Lbe10 | done 844Lbe4: 845 movl %sp@(FR_HW+36),%d1 | long format, use stage B address 846 btst #15,%d0 | FC set? 847 jeq Lbe10 | no, all done 848 subql #2,%d1 | yes, adjust address 849Lbe10: 850 movl %d1,%sp@- | push fault VA 851 movl %d0,%sp@- | and padded SSW 852 movw %sp@(FR_HW+8+6),%d0 | get frame format/vector offset 853 andw #0x0FFF,%d0 | clear out frame format 854 cmpw #12,%d0 | address error vector? 855 jeq Lisaerr | yes, go to it 856 movl %d1,%a0 | fault address 857 movl %sp@,%d0 | function code from ssw 858 btst #8,%d0 | data fault? 859 jne Lbe10a 860 movql #1,%d0 | user program access FC 861 | (we dont separate data/program) 862 btst #5,%sp@(FR_HW+8) | supervisor mode? 863 jeq Lbe10a | if no, done 864 movql #5,%d0 | else supervisor program access 865Lbe10a: 866 ptestr %d0,%a0@,#7 | do a table search 867 pmove %psr,%sp@ | save result 868 movb %sp@,%d1 869 btst #2,%d1 | invalid (incl. limit viol. and berr)? 870 jeq Lmightnotbemerr | no -> wp check 871 btst #7,%d1 | is it MMU table berr? 872 jne Lisberr1 | yes, needs not be fast. 873Lismerr: 874 movl #T_MMUFLT,%sp@- | show that we are an MMU fault 875 jra _ASM_LABEL(faultstkadj) | and deal with it 876Lmightnotbemerr: 877 btst #3,%d1 | write protect bit set? 878 jeq Lisberr1 | no: must be bus error 879 movl %sp@,%d0 | ssw into low word of d0 880 andw #0xc0,%d0 | Write protect is set on page: 881 cmpw #0x40,%d0 | was it read cycle? 882 jne Lismerr | no, was not WPE, must be MMU fault 883 jra Lisberr1 | real bus err needs not be fast. 884Lisaerr: 885 movl #T_ADDRERR,%sp@- | mark address error 886 jra _ASM_LABEL(faultstkadj) | and deal with it 887Lisberr1: 888 clrw %sp@ | re-clear pad word 889 tstl _C_LABEL(nofault) | catch bus error? 890 jeq Lisberr | no, handle as usual 891 movl _C_LABEL(nofault),%sp@- | yes, 892 jbsr _C_LABEL(longjmp) | longjmp(nofault) 893 /* NOTREACHED */ 894#endif /* M68020 || M68030 */ 895 896Lisberr: | also used by M68040/60 897 movl #T_BUSERR,%sp@- | mark bus error 898 jra _ASM_LABEL(faultstkadj) | and deal with it 899 900/* 901 * FP exceptions. 902 */ 903ENTRY_NOPROFILE(fpfline) 904#if defined(M68040) 905 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 906 jne Lfp_unimp | no, skip FPSP 907 cmpw #0x202c,%sp@(6) | format type 2? 908 jne _C_LABEL(illinst) | no, not an FP emulation 909#ifdef FPSP 910 jmp _ASM_LABEL(fpsp_unimp) | yes, go handle it 911#else 912 clrl %sp@- | stack adjust count 913 moveml #0xFFFF,%sp@- | save registers 914 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 915 jra _ASM_LABEL(fault) | do it 916#endif 917Lfp_unimp: 918#endif /* M68040 */ 919 jra _C_LABEL(illinst) 920 921ENTRY_NOPROFILE(fpunsupp) 922#if defined(M68040) 923 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 924 jne Lfp_unsupp | No, skip FPSP 925#ifdef FPSP 926 jmp _ASM_LABEL(fpsp_unsupp) | yes, go handle it 927#else 928 clrl %sp@- | stack adjust count 929 moveml #0xFFFF,%sp@- | save registers 930 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 931 jra _ASM_LABEL(fault) | do it 932#endif 933Lfp_unsupp: 934#endif /* M68040 */ 935 jra _C_LABEL(illinst) 936 937/* 938 * Handles all other FP coprocessor exceptions. 939 * Note that since some FP exceptions generate mid-instruction frames 940 * and may cause signal delivery, we need to test for stack adjustment 941 * after the trap call. 942 */ 943ENTRY_NOPROFILE(fpfault) 944 clrl %sp@- | stack adjust count 945 moveml #0xFFFF,%sp@- | save user registers 946 movl %usp,%a0 | and save 947 movl %a0,%sp@(FR_SP) | the user stack pointer 948 clrl %sp@- | no VA arg 949 movl _C_LABEL(curpcb),%a0 | current pcb 950 lea %a0@(PCB_FPCTX),%a0 | address of FP savearea 951 fsave %a0@ | save state 952#if defined(M68040) || defined(M68060) 953 /* always null state frame on 68040, 68060 */ 954 cmpl #FPU_68040,_C_LABEL(fputype) 955 jle Lfptnull 956#endif 957 tstb %a0@ | null state frame? 958 jeq Lfptnull | yes, safe 959 clrw %d0 | no, need to tweak BIU 960 movb %a0@(1),%d0 | get frame size 961 bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU 962Lfptnull: 963 fmovem %fpsr,%sp@- | push fpsr as code argument 964 frestore %a0@ | restore state 965 movl #T_FPERR,%sp@- | push type arg 966 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup 967 968 969/* 970 * Other exceptions only cause four and six word stack frame and require 971 * no post-trap stack adjustment. 972 */ 973 974ENTRY_NOPROFILE(badtrap) 975 moveml #0xC0C0,%sp@- | save scratch regs 976 movw %sp@(22),%sp@- | push exception vector info 977 clrw %sp@- 978 movl %sp@(22),%sp@- | and PC 979 jbsr _C_LABEL(straytrap) | report 980 addql #8,%sp | pop args 981 moveml %sp@+,#0x0303 | restore regs 982 jra _ASM_LABEL(rei) | all done 983 984ENTRY_NOPROFILE(trap0) 985 clrl %sp@- | stack adjust count 986 moveml #0xFFFF,%sp@- | save user registers 987 movl %usp,%a0 | save the user SP 988 movl %a0,%sp@(FR_SP) | in the savearea 989 movl %d0,%sp@- | push syscall number 990 jbsr _C_LABEL(syscall) | handle it 991 addql #4,%sp | pop syscall arg 992 tstl _C_LABEL(astpending) | AST pending? 993 jne Lrei1 | Yup, go deal with it. 994 movl %sp@(FR_SP),%a0 | grab and restore 995 movl %a0,%usp | user SP 996 moveml %sp@+,#0x7FFF | restore most registers 997 addql #8,%sp | pop SP and stack adjust 998 rte 999 1000/* 1001 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) 1002 * cachectl(command, addr, length) 1003 * command in d0, addr in a1, length in d1 1004 */ 1005ENTRY_NOPROFILE(trap12) 1006 movl _C_LABEL(curproc),%sp@- | push curproc pointer 1007 movl %d1,%sp@- | push length 1008 movl %a1,%sp@- | push addr 1009 movl %d0,%sp@- | push command 1010 jbsr _C_LABEL(cachectl1) | do it 1011 lea %sp@(16),%sp | pop args 1012 jra _ASM_LABEL(rei) | all done 1013 1014/* 1015 * Trace (single-step) trap. Kernel-mode is special. 1016 * User mode traps are simply passed on to trap(). 1017 */ 1018ENTRY_NOPROFILE(trace) 1019 clrl %sp@- | stack adjust count 1020 moveml #0xFFFF,%sp@- 1021 moveq #T_TRACE,%d0 1022 1023 | Check PSW and see what happen. 1024 | T=0 S=0 (should not happen) 1025 | T=1 S=0 trace trap from user mode 1026 | T=0 S=1 trace trap on a trap instruction 1027 | T=1 S=1 trace trap from system mode (kernel breakpoint) 1028 1029 movw %sp@(FR_HW),%d1 | get PSW 1030 notw %d1 | XXX no support for T0 on 680[234]0 1031 andw #PSL_TS,%d1 | from system mode (T=1, S=1)? 1032 jeq Lkbrkpt | yes, kernel breakpoint 1033 jra _ASM_LABEL(fault) | no, user-mode fault 1034 1035/* 1036 * Trap 15 is used for: 1037 * - GDB breakpoints (in user programs) 1038 * - KGDB breakpoints (in the kernel) 1039 * - trace traps for SUN binaries (not fully supported yet) 1040 * User mode traps are simply passed to trap(). 1041 */ 1042ENTRY_NOPROFILE(trap15) 1043 clrl %sp@- | stack adjust count 1044 moveml #0xFFFF,%sp@- 1045 moveq #T_TRAP15,%d0 1046 movw %sp@(FR_HW),%d1 | get PSW 1047 andw #PSL_S,%d1 | from system mode? 1048 jne Lkbrkpt | yes, kernel breakpoint 1049 jra _ASM_LABEL(fault) | no, user-mode fault 1050 1051Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type) 1052 | Save the system sp rather than the user sp. 1053 movw #PSL_HIGHIPL,%sr | lock out interrupts 1054 lea %sp@(FR_SIZE),%a6 | Save stack pointer 1055 movl %a6,%sp@(FR_SP) | from before trap 1056 1057 | If were are not on tmpstk switch to it. 1058 | (so debugger can change the stack pointer) 1059 movl %a6,%d1 1060 cmpl #_ASM_LABEL(tmpstk),%d1 1061 jls Lbrkpt2 | already on tmpstk 1062 | Copy frame to the temporary stack 1063 movl %sp,%a0 | a0=src 1064 lea _ASM_LABEL(tmpstk)-96,%a1 | a1=dst 1065 movl %a1,%sp | sp=new frame 1066 movql #FR_SIZE,%d1 1067Lbrkpt1: 1068 movl %a0@+,%a1@+ 1069 subql #4,%d1 1070 jbgt Lbrkpt1 1071 1072Lbrkpt2: 1073 | Call the trap handler for the kernel debugger. 1074 | Do not call trap() to do it, so that we can 1075 | set breakpoints in trap() if we want. We know 1076 | the trap type is either T_TRACE or T_BREAKPOINT. 1077 | If we have both DDB and KGDB, let KGDB see it first, 1078 | because KGDB will just return 0 if not connected. 1079 | Save args in d2, a2 1080 movl %d0,%d2 | trap type 1081 movl %sp,%a2 | frame ptr 1082#ifdef KGDB 1083 | Let KGDB handle it (if connected) 1084 movl %a2,%sp@- | push frame ptr 1085 movl %d2,%sp@- | push trap type 1086 jbsr _C_LABEL(kgdb_trap) | handle the trap 1087 addql #8,%sp | pop args 1088 cmpl #0,%d0 | did kgdb handle it? 1089 jne Lbrkpt3 | yes, done 1090#endif 1091#ifdef DDB 1092 | Let DDB handle it 1093 movl %a2,%sp@- | push frame ptr 1094 movl %d2,%sp@- | push trap type 1095 jbsr _C_LABEL(kdb_trap) | handle the trap 1096 addql #8,%sp | pop args 1097#endif 1098 /* Sun 3 drops into PROM here. */ 1099Lbrkpt3: 1100 | The stack pointer may have been modified, or 1101 | data below it modified (by kgdb push call), 1102 | so push the hardware frame at the current sp 1103 | before restoring registers and returning. 1104 1105 movl %sp@(FR_SP),%a0 | modified sp 1106 lea %sp@(FR_SIZE),%a1 | end of our frame 1107 movl %a1@-,%a0@- | copy 2 longs with 1108 movl %a1@-,%a0@- | ... predecrement 1109 movl %a0,%sp@(FR_SP) | sp = h/w frame 1110 moveml %sp@+,#0x7FFF | restore all but sp 1111 movl %sp@,%sp | ... and sp 1112 rte | all done 1113 1114/* 1115 * Use common m68k sigreturn routine. 1116 */ 1117#include <m68k/m68k/sigreturn.s> 1118 1119/* 1120 * Interrupt handlers. 1121 * 1122 * For auto-vectored interrupts, the CPU provides the 1123 * vector 0x18+level. 1124 * 1125 * intrhand_autovec is the entry point for auto-vectored 1126 * interrupts. 1127 * 1128 * For vectored interrupts, we pull the pc, evec, and exception frame 1129 * and pass them to the vectored interrupt dispatcher. The vectored 1130 * interrupt dispatcher will deal with strays. 1131 * 1132 * intrhand_vectored is the entry point for vectored interrupts. 1133 */ 1134 1135#define INTERRUPT_SAVEREG moveml #0xC0C0,%sp@- 1136#define INTERRUPT_RESTOREREG moveml %sp@+,#0x0303 1137 1138ENTRY_NOPROFILE(intrhand_autovec) 1139 addql #1,_C_LABEL(interrupt_depth) 1140 INTERRUPT_SAVEREG 1141 lea %sp@(16),%a1 | get pointer to frame 1142 movl %a1,%sp@- 1143 jbsr _C_LABEL(isrdispatch_autovec) | call dispatcher 1144 addql #4,%sp 1145 jbra Lintrhand_exit 1146 1147ENTRY_NOPROFILE(intrhand_vectored) 1148 addql #1,_C_LABEL(interrupt_depth) 1149 INTERRUPT_SAVEREG 1150 lea %sp@(16),%a1 | get pointer to frame 1151 movl %a1,%sp@- 1152 movw %sr,%d0 1153 bfextu %d0,21,3,%d0 | Get current ipl 1154 movl %d0,%sp@- | Push it 1155 jbsr _C_LABEL(isrdispatch_vectored) | call dispatcher 1156 addql #8,%sp 1157Lintrhand_exit: 1158 INTERRUPT_RESTOREREG 1159 subql #1,_C_LABEL(interrupt_depth) 1160 1161 /* FALLTHROUGH to rei */ 1162 1163#undef INTERRUPT_SAVEREG 1164#undef INTERRUPT_RESTOREREG 1165 1166/* 1167 * Emulation of VAX REI instruction. 1168 * 1169 * This code deals with checking for and servicing ASTs 1170 * (profiling, scheduling). 1171 * After identifing that we need an AST we drop the IPL to allow device 1172 * interrupts. 1173 * 1174 * This code is complicated by the fact that sendsig may have been called 1175 * necessitating a stack cleanup. 1176 */ 1177ASENTRY_NOPROFILE(rei) 1178 tstl _C_LABEL(astpending) | AST pending? 1179 jeq Ldorte | Nope. Just return. 1180 btst #5,%sp@ | Returning to kernel mode? 1181 jne Ldorte | Yup. Can't do ASTs 1182 movw #PSL_LOWIPL,%sr | lower SPL 1183 clrl %sp@- | stack adjust 1184 moveml #0xFFFF,%sp@- | save all registers 1185 movl %usp,%a1 | including 1186 movl %a1,%sp@(FR_SP) | the users SP 1187Lrei1: clrl %sp@- | VA == none 1188 clrl %sp@- | code == none 1189 movl #T_ASTFLT,%sp@- | type == async system trap 1190 jbsr _C_LABEL(trap) | go handle it 1191 lea %sp@(12),%sp | pop value args 1192 movl %sp@(FR_SP),%a0 | restore user SP 1193 movl %a0,%usp | from save area 1194 movw %sp@(FR_ADJ),%d0 | need to adjust stack? 1195 jne Laststkadj | yes, go to it 1196 moveml %sp@+,#0x7FFF | no, restore most user regs 1197 addql #8,%sp | toss SP and stack adjust 1198Ldorte: rte | and do real RTE 1199 1200Laststkadj: 1201 lea %sp@(FR_HW),%a1 | pointer to HW frame 1202 addql #8,%a1 | source pointer 1203 movl %a1,%a0 | source 1204 addw %d0,%a0 | + hole size = dest pointer 1205 movl %a1@-,%a0@- | copy 1206 movl %a1@-,%a0@- | 8 bytes 1207 movl %a0,%sp@(FR_SP) | new SSP 1208 moveml %sp@+,#0x7FFF | restore user registers 1209 movl %sp@,%sp | and our SP 1210 rte | and do real RTE 1211 1212/* 1213 * Use common m68k sigcode. 1214 */ 1215#include <m68k/m68k/sigcode.s> 1216#ifdef COMPAT_SUNOS 1217#include <m68k/m68k/sunos_sigcode.s> 1218#endif 1219#ifdef COMPAT_SVR4 1220#include <m68k/m68k/svr4_sigcode.s> 1221#endif 1222 1223/* 1224 * Primitives 1225 */ 1226 1227/* 1228 * Use common m68k support routines. 1229 */ 1230#include <m68k/m68k/support.s> 1231 1232/* 1233 * Use common m68k process manipulation routines. 1234 */ 1235#include <m68k/m68k/proc_subr.s> 1236 1237 .data 1238GLOBAL(curpcb) 1239GLOBAL(masterpaddr) | XXXcompatibility (debuggers) 1240 .long 0 1241 1242ASLOCAL(mdpflag) 1243 .byte 0 | copy of proc md_flags low byte 1244#ifdef __ELF__ 1245 .align 4 1246#else 1247 .align 2 1248#endif 1249 1250ASBSS(nullpcb,SIZEOF_PCB) 1251 1252/* 1253 * At exit of a process, do a switch for the last time. 1254 * Switch to a safe stack and PCB, and select a new process to run. The 1255 * old stack and u-area will be freed by the reaper. 1256 * 1257 * MUST BE CALLED AT SPLHIGH! 1258 */ 1259ENTRY(switch_exit) 1260 movl %sp@(4),%a0 1261 /* save state into garbage pcb */ 1262 movl #_ASM_LABEL(nullpcb),_C_LABEL(curpcb) 1263 lea _ASM_LABEL(tmpstk),%sp | goto a tmp stack 1264 1265 /* Schedule the vmspace and stack to be freed. */ 1266 movl %a0,%sp@- | exit2(p) 1267 jbsr _C_LABEL(exit2) 1268 lea %sp@(4),%sp | pop args 1269 1270#if defined(LOCKDEBUG) 1271 /* Acquire sched_lock */ 1272 jbsr _C_LABEL(sched_lock_idle) 1273#endif 1274 1275 jra _C_LABEL(cpu_switch) 1276 1277/* 1278 * When no processes are on the runq, Swtch branches to Idle 1279 * to wait for something to come ready. 1280 */ 1281ASENTRY_NOPROFILE(Idle) 1282#if defined(LOCKDEBUG) 1283 /* Release sched_lock */ 1284 jbsr _C_LABEL(sched_unlock_idle) 1285#endif 1286 stop #PSL_LOWIPL 1287 movw #PSL_HIGHIPL,%sr 1288#if defined(LOCKDEBUG) 1289 /* Acquire sched_lock */ 1290 jbsr _C_LABEL(sched_lock_idle) 1291#endif 1292 movl _C_LABEL(sched_whichqs),%d0 1293 jeq _ASM_LABEL(Idle) 1294 jra Lsw1 1295 1296Lbadsw: 1297 PANIC("switch") 1298 /*NOTREACHED*/ 1299 1300/* 1301 * cpu_switch() 1302 * 1303 * NOTE: With the new VM layout we now no longer know if an inactive 1304 * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag 1305 * bit). For now, we just always flush the full ATC. 1306 */ 1307ENTRY(cpu_switch) 1308 movl _C_LABEL(curpcb),%a0 | current pcb 1309 movw %sr,%a0@(PCB_PS) | save sr before changing ipl 1310#ifdef notyet 1311 movl _C_LABEL(curproc),%sp@- | remember last proc running 1312#endif 1313 clrl _C_LABEL(curproc) 1314 1315 /* 1316 * Find the highest-priority queue that isn't empty, 1317 * then take the first proc from that queue. 1318 */ 1319 movl _C_LABEL(sched_whichqs),%d0 1320 jeq _ASM_LABEL(Idle) 1321Lsw1: 1322 /* 1323 * Interrupts are blocked, sched_lock is held. If 1324 * we come here via Idle, %d0 contains the contents 1325 * of a non-zero sched_whichqs. 1326 */ 1327 movl %d0,%d1 1328 negl %d0 1329 andl %d1,%d0 1330 bfffo %d0{#0:#32},%d1 1331 eorib #31,%d1 1332 1333 movl %d1,%d0 1334 lslb #3,%d1 | convert queue number to index 1335 addl #_C_LABEL(sched_qs),%d1 | locate queue (q) 1336 movl %d1,%a1 1337 movl %a1@(P_FORW),%a0 | p = q->p_forw 1338 cmpal %d1,%a0 | anyone on queue? 1339 jeq Lbadsw | no, panic 1340#ifdef DIAGNOSTIC 1341 tstl %a0@(P_WCHAN) 1342 jne Lbadsw 1343 cmpb #SRUN,%a0@(P_STAT) 1344 jne Lbadsw 1345#endif 1346 movl %a0@(P_FORW),%a1@(P_FORW) | q->p_forw = p->p_forw 1347 movl %a0@(P_FORW),%a1 | n = p->p_forw 1348 movl %d1,%a1@(P_BACK) | n->p_back = q 1349 cmpal %d1,%a1 | anyone left on queue? 1350 jne Lsw2 | yes, skip 1351 movl _C_LABEL(sched_whichqs),%d1 1352 bclr %d0,%d1 | no, clear bit 1353 movl %d1,_C_LABEL(sched_whichqs) 1354Lsw2: 1355 /* p->p_cpu initialized in fork1() for single-processor */ 1356 movb #SONPROC,%a0@(P_STAT) | p->p_stat = SONPROC 1357 movl %a0,_C_LABEL(curproc) 1358 clrl _C_LABEL(want_resched) 1359#ifdef notyet 1360 movl %sp@+,%a1 1361 cmpl %a0,%a1 | switching to same proc? 1362 jeq Lswdone | yes, skip save and restore 1363#endif 1364 /* 1365 * Save state of previous process in its pcb. 1366 */ 1367 movl _C_LABEL(curpcb),%a1 1368 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers 1369 movl %usp,%a2 | grab USP (a2 has been saved) 1370 movl %a2,%a1@(PCB_USP) | and save it 1371 1372 tstl _C_LABEL(fputype) | Do we have an FPU? 1373 jeq Lswnofpsave | No Then don't attempt save. 1374 lea %a1@(PCB_FPCTX),%a2 | pointer to FP save area 1375 fsave %a2@ | save FP state 1376#if defined(M68020) || defined(M68030) || defined(M68040) 1377#if defined(M68060) 1378 cmpl #FPU_68060,_C_LABEL(fputype) 1379 jeq Lsavfp60 1380#endif 1381 tstb %a2@ | null state frame? 1382 jeq Lswnofpsave | yes, all done 1383 fmovem %fp0-%fp7,%a2@(FPF_REGS) | save FP general registers 1384 fmovem %fpcr/%fpsr/%fpi,%a2@(FPF_FPCR) | save FP control registers 1385#if defined(M68060) 1386 jra Lswnofpsave 1387Lsavfp60: 1388#endif 1389#endif 1390#if defined(M68060) 1391 tstb %a2@(2) | null state frame? 1392 jeq Lswnofpsave | yes, all done 1393 fmovem %fp0-%fp7,%a2@(FPF_REGS) | save FP general registers 1394 fmovem %fpcr,%a2@(FPF_FPCR) | save FP control registers 1395 fmovem %fpsr,%a2@(FPF_FPSR) 1396 fmovem %fpi,%a2@(FPF_FPI) 1397#endif 1398Lswnofpsave: 1399 1400 clrl %a0@(P_BACK) | clear back link 1401 /* low byte of p_md.md_flags */ 1402 movb %a0@(P_MD_FLAGS+3),_ASM_LABEL(mdpflag) 1403 movl %a0@(P_ADDR),%a1 | get p_addr 1404 movl %a1,_C_LABEL(curpcb) 1405 1406#if defined(LOCKDEBUG) 1407 /* 1408 * Done mucking with the run queues, release the 1409 * scheduler lock, but keep interrupts out. 1410 */ 1411 movl %a0,%sp@- | not args... 1412 movl %a1,%sp@- | ...just saving 1413 jbsr _C_LABEL(sched_unlock_idle) 1414 movl %sp@+,%a1 1415 movl %sp@+,%a0 1416#endif 1417 1418 /* 1419 * Activate process's address space. 1420 * XXX Should remember the last USTP value loaded, and call this 1421 * XXX only of it has changed. 1422 */ 1423 pea %a0@ | push proc 1424 jbsr _C_LABEL(pmap_activate) | pmap_activate(p) 1425 addql #4,%sp 1426 movl _C_LABEL(curpcb),%a1 | restore p_addr 1427 1428 lea _ASM_LABEL(tmpstk),%sp | now goto a tmp stack for NMI 1429 1430 moveml %a1@(PCB_REGS),#0xFCFC | and registers 1431 movl %a1@(PCB_USP),%a0 1432 movl %a0,%usp | and USP 1433 tstl _C_LABEL(fputype) | Do we have an FPU? 1434 jeq Lnofprest | No Then don't attempt restore. 1435 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area 1436#if defined(M68020) || defined(M68030) || defined(M68040) 1437#if defined(M68060) 1438 cmpl #FPU_68060,_C_LABEL(fputype) 1439 jeq Lresfp60rest1 1440#endif 1441 tstb %a0@ | null state frame? 1442 jeq Lresfprest | yes, easy 1443 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers 1444 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers 1445#if defined(M68060) 1446 jra Lresfprest 1447#endif 1448#endif 1449 1450#if defined(M68060) 1451Lresfp60rest1: 1452 tstb %a0@(2) | null state frame? 1453 jeq Lresfprest | yes, easy 1454 fmovem %a0@(FPF_FPCR),%fpcr | restore FP control registers 1455 fmovem %a0@(FPF_FPSR),%fpsr 1456 fmovem %a0@(FPF_FPI),%fpi 1457 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers 1458#endif 1459Lresfprest: 1460 frestore %a0@ | restore state 1461Lnofprest: 1462 movw %a1@(PCB_PS),%sr | no, restore PS 1463 moveq #1,%d0 | return 1 (for alternate returns) 1464 rts 1465 1466/* 1467 * savectx(pcb) 1468 * Update pcb, saving current processor state. 1469 */ 1470ENTRY(savectx) 1471 movl %sp@(4),%a1 1472 movw %sr,%a1@(PCB_PS) 1473 movl %usp,%a0 | grab USP 1474 movl %a0,%a1@(PCB_USP) | and save it 1475 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers 1476 1477 tstl _C_LABEL(fputype) | Do we have FPU? 1478 jeq Lsvnofpsave | No? Then don't save state. 1479 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area 1480 fsave %a0@ | save FP state 1481#if defined(M68020) || defined(M68030) || defined(M68040) 1482#if defined(M68060) 1483 cmpl #FPU_68060,_C_LABEL(fputype) 1484 jeq Lsvsavfp60 1485#endif 1486 tstb %a0@ | null state frame? 1487 jeq Lsvnofpsave | yes, all done 1488 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers 1489 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers 1490#if defined(M68060) 1491 jra Lsvnofpsave 1492Lsvsavfp60: 1493#endif 1494#endif 1495#if defined(M68060) 1496 tstb %a0@(2) | null state frame? 1497 jeq Lsvnofpsave | yes, all done 1498 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers 1499 fmovem %fpcr,%a0@(FPF_FPCR) | save FP control registers 1500 fmovem %fpsr,%a0@(FPF_FPSR) 1501 fmovem %fpi,%a0@(FPF_FPI) 1502#endif 1503Lsvnofpsave: 1504 moveq #0,%d0 | return 0 1505 rts 1506 1507#if defined(M68040) || defined(M68060) 1508ENTRY(suline) 1509 movl %sp@(4),%a0 | address to write 1510 movl _C_LABEL(curpcb),%a1 | current pcb 1511 movl #Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault 1512 movl %sp@(8),%a1 | address of line 1513 movl %a1@+,%d0 | get lword 1514 movsl %d0,%a0@+ | put lword 1515 nop | sync 1516 movl %a1@+,%d0 | get lword 1517 movsl %d0,%a0@+ | put lword 1518 nop | sync 1519 movl %a1@+,%d0 | get lword 1520 movsl %d0,%a0@+ | put lword 1521 nop | sync 1522 movl %a1@+,%d0 | get lword 1523 movsl %d0,%a0@+ | put lword 1524 nop | sync 1525 moveq #0,%d0 | indicate no fault 1526 jra Lsldone 1527Lslerr: 1528 moveq #-1,%d0 1529Lsldone: 1530 movl _C_LABEL(curpcb),%a1 | current pcb 1531 clrl %a1@(PCB_ONFAULT) | clear fault address 1532 rts 1533#endif 1534 1535 1536ENTRY(ecacheon) 1537 rts 1538 1539ENTRY(ecacheoff) 1540 rts 1541 1542/* 1543 * Get callers current SP value. 1544 * Note that simply taking the address of a local variable in a C function 1545 * doesn't work because callee saved registers may be outside the stack frame 1546 * defined by A6 (e.g. GCC generated code). 1547 */ 1548ENTRY_NOPROFILE(getsp) 1549 movl %sp,%d0 | get current SP 1550 addql #4,%d0 | compensate for return address 1551 movl %d0,%a0 1552 rts 1553 1554ENTRY_NOPROFILE(getsfc) 1555 movc %sfc,%d0 1556 movl %d0,%a0 1557 rts 1558 1559ENTRY_NOPROFILE(getdfc) 1560 movc %dfc,%d0 1561 movl %d0,%a0 1562 rts 1563 1564/* 1565 * Load a new user segment table pointer. 1566 */ 1567ENTRY(loadustp) 1568 movl %sp@(4),%d0 | new USTP 1569 moveq #PGSHIFT, %d1 1570 lsll %d1,%d0 | convert to addr 1571#if defined(M68040) || defined(M68060) 1572 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 1573 jne LmotommuC | no, skip 1574 .word 0xf518 | pflusha 1575 .long 0x4e7b0806 | movc d0,urp 1576#ifdef M68060 1577 cmpl #CPU_68060,_C_LABEL(cputype) 1578 jne Lldno60 1579 movc %cacr,%d0 1580 orl #IC60_CUBC,%d0 | clear user branch cache entries 1581 movc %d0,%cacr 1582Lldno60: 1583#endif 1584 rts 1585LmotommuC: 1586#endif 1587 pflusha | flush entire TLB 1588 lea _C_LABEL(protorp),%a0 | CRP prototype 1589 movl %d0,%a0@(4) | stash USTP 1590 pmove %a0@,%crp | load root pointer 1591 movl #CACHE_CLR,%d0 1592 movc %d0,%cacr | invalidate cache(s) 1593 rts 1594 1595ENTRY(ploadw) 1596#ifdef M68030 1597#if defined(M68040) || defined(M68060) 1598 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 1599 jeq Lploadwskp | yes, skip 1600#endif 1601 movl %sp@(4),%a0 | address to load 1602 ploadw #1,%a0@ | pre-load translation 1603Lploadwskp: 1604#endif 1605 rts 1606 1607ENTRY(getsr) 1608 moveq #0,%d0 1609 movw %sr,%d0 1610 rts 1611 1612/* 1613 * _delay(unsigned N) 1614 * 1615 * Delay for at least (N/1024) microseconds. 1616 * This routine depends on the variable: delay_divisor 1617 * which should be set based on the CPU clock rate. 1618 */ 1619ENTRY_NOPROFILE(_delay) 1620 | d0 = arg = (usecs << 10) 1621 movl %sp@(4),%d0 1622 | d1 = delay_divisor 1623 movl _C_LABEL(delay_divisor),%d1 1624 jra L_delay /* Jump into the loop! */ 1625 1626 /* 1627 * Align the branch target of the loop to a half-line (8-byte) 1628 * boundary to minimize cache effects. This guarantees both 1629 * that there will be no prefetch stalls due to cache line burst 1630 * operations and that the loop will run from a single cache 1631 * half-line. 1632 */ 1633#ifdef __ELF__ 1634 .align 8 1635#else 1636 .align 3 1637#endif 1638L_delay: 1639 subl %d1,%d0 1640 jgt L_delay 1641 rts 1642 1643/* 1644 * Save and restore 68881 state. 1645 */ 1646ENTRY(m68881_save) 1647 movl %sp@(4),%a0 | save area pointer 1648 fsave %a0@ | save state 1649#if defined(M68020) || defined(M68030) || defined(M68040) 1650#if defined(M68060) 1651 cmpl #FPU_68060,_C_LABEL(fputype) 1652 jeq Lm68060fpsave 1653#endif 1654Lm68881fpsave: 1655 tstb %a0@ | null state frame? 1656 jeq Lm68881sdone | yes, all done 1657 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers 1658 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers 1659Lm68881sdone: 1660 rts 1661#endif 1662#if defined(M68060) 1663Lm68060fpsave: 1664 tstb %a0@(2) | null state frame? 1665 jeq Lm68060sdone | yes, all done 1666 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers 1667 fmovem %fpcr,%a0@(FPF_FPCR) | save FP control registers 1668 fmovem %fpsr,%a0@(FPF_FPSR) 1669 fmovem %fpi,%a0@(FPF_FPI) 1670Lm68060sdone: 1671 rts 1672#endif 1673 1674ENTRY(m68881_restore) 1675 movl %sp@(4),%a0 | save area pointer 1676#if defined(M68020) || defined(M68030) || defined(M68040) 1677#if defined(M68060) 1678 cmpl #FPU_68060,_C_LABEL(fputype) 1679 jeq Lm68060fprestore 1680#endif 1681Lm68881fprestore: 1682 tstb %a0@ | null state frame? 1683 jeq Lm68881rdone | yes, easy 1684 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers 1685 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers 1686Lm68881rdone: 1687 frestore %a0@ | restore state 1688 rts 1689#endif 1690#if defined(M68060) 1691Lm68060fprestore: 1692 tstb %a0@(2) | null state frame? 1693 jeq Lm68060fprdone | yes, easy 1694 fmovem %a0@(FPF_FPCR),%fpcr | restore FP control registers 1695 fmovem %a0@(FPF_FPSR),%fpsr 1696 fmovem %a0@(FPF_FPI),%fpi 1697 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers 1698Lm68060fprdone: 1699 frestore %a0@ | restore state 1700 rts 1701#endif 1702 1703/* 1704 * Handle the nitty-gritty of rebooting the machine. 1705 * Basically we just turn off the MMU, restore the Bug's initial VBR 1706 * and either return to Bug or jump through the ROM reset vector 1707 * depending on how the system was halted. 1708 */ 1709ENTRY_NOPROFILE(doboot) 1710 movw #PSL_HIGHIPL,%sr 1711 movl _C_LABEL(boothowto),%d1 | load howto 1712 movl %sp@(4),%d2 | arg 1713 movl _ASM_LABEL(bug_vbr),%d3 | Fetch Bug's original VBR value 1714 movl _C_LABEL(machineid),%d4 | What type of board is this? 1715 movl #CACHE_OFF,%d0 1716#if defined(M68040) || defined(M68060) 1717 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040/68060? 1718 jne Lnocache0 | no, skip 1719 .word 0xf4f8 | cpusha bc - push and invalidate caches 1720 nop 1721 movl #CACHE40_OFF,%d0 1722#endif 1723Lnocache0: 1724 movc %d0,%cacr | disable on-chip cache(s) 1725 1726#if defined(M68040) || defined(M68060) 1727 cmpl #MMU_68040,_C_LABEL(mmutype) 1728 jne LmotommuF 1729 movql #0,%d0 1730 movc %d0,%cacr 1731 .long 0x4e7b0003 | movc d0,tc 1732 jra Lbootcommon 1733LmotommuF: 1734#endif 1735 clrl %sp@- | value for pmove to TC (turn off MMU) 1736 pmove %sp@,%tc | disable MMU 1737 addql #4,%sp 1738 1739Lbootcommon: 1740 /* 1741 * MMU Switched off by now, so relocate all absolute references 1742 */ 1743 ASRELOC(tmpstk, %sp) | physical SP in case of NMI 1744 movc %d3,%vbr | Restore Bug's VBR 1745 andl #RB_SBOOT, %d1 | mask off 1746 jbne Lsboot | sboot? 1747 /* NOT sboot */ 1748 tstl %d2 | autoboot? 1749 jbeq Ldoreset | yes! 1750 CALLBUG(MVMEPROM_EXIT) | return to bug 1751 /* NOTREACHED */ 1752 1753Ldoreset: 1754 movl #0xff800000,%a0 | Bug's reset vector address 1755 movl %a0@+, %a7 | get SP 1756 movl %a0@, %a0 | get PC 1757 jmp %a0@ | go! 1758 1759Lsboot: /* sboot */ 1760 tstl %d2 | autoboot? 1761 jbeq 1f | yes! 1762 jmp 0x4000 | back to sboot 17631: jmp 0x400a | tell sboot to reboot us 1764 1765 1766/* 1767 * Misc. global variables. 1768 */ 1769 .data 1770 1771GLOBAL(machineid) 1772 .long MVME_147 | default to MVME_147 1773 1774GLOBAL(mmutype) 1775 .long MMU_68030 | default to MMU_68030 1776 1777GLOBAL(cputype) 1778 .long CPU_68030 | default to CPU_68030 1779 1780GLOBAL(fputype) 1781 .long FPU_68882 | default to FPU_68882 1782 1783GLOBAL(protorp) 1784 .long 0,0 | prototype root pointer 1785 1786/* 1787 * Information from first stage boot program 1788 */ 1789GLOBAL(bootpart) 1790 .long 0 1791GLOBAL(bootdevlun) 1792 .long 0 1793GLOBAL(bootctrllun) 1794 .long 0 1795GLOBAL(bootaddr) 1796 .long 0 1797 1798GLOBAL(want_resched) 1799 .long 0 1800 1801GLOBAL(proc0paddr) 1802 .long 0 | KVA of proc0 u-area 1803 1804GLOBAL(intiobase) 1805 .long 0 | KVA of base of internal IO space 1806 1807GLOBAL(intiolimit) 1808 .long 0 | KVA of end of internal IO space 1809 1810GLOBAL(intiobase_phys) 1811 .long 0 | PA of board's I/O registers 1812 1813GLOBAL(intiotop_phys) 1814 .long 0 | PA of top of board's I/O registers 1815 1816/* 1817 * interrupt counters. 1818 * XXXSCW: Will go away soon; kept here to keep vmstat happy 1819 */ 1820GLOBAL(intrnames) 1821 .asciz "spur" 1822 .asciz "lev1" 1823 .asciz "lev2" 1824 .asciz "lev3" 1825 .asciz "lev4" 1826 .asciz "clock" 1827 .asciz "lev6" 1828 .asciz "nmi" 1829 .asciz "statclock" 1830GLOBAL(eintrnames) 1831 .even 1832 1833GLOBAL(intrcnt) 1834 .long 0,0,0,0,0,0,0,0,0,0 1835GLOBAL(eintrcnt) 1836