1/* $NetBSD: locore.s,v 1.131 2024/01/18 05:12:30 thorpej 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. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: locore.s 1.66 92/12/22$ 37 * 38 * @(#)locore.s 8.6 (Berkeley) 5/27/94 39 */ 40 41#include "opt_compat_netbsd.h" 42#include "opt_compat_sunos.h" 43#include "opt_fpsp.h" 44#include "opt_ddb.h" 45#include "opt_kgdb.h" 46#include "opt_lockdebug.h" 47#include "opt_m68k_arch.h" 48#include "opt_mvmeconf.h" 49 50#include "assym.h" 51#include <machine/asm.h> 52#include <machine/trap.h> 53 54#include "ksyms.h" 55 56/* 57 * Temporary stack for a variety of purposes. 58 * Try and make this the first thing is the data segment so it 59 * is page aligned. Note that if we overflow here, we run into 60 * our text segment. 61 */ 62 .data 63 .space PAGE_SIZE 64ASLOCAL(tmpstk) 65 66/* 67 * Macro to relocate a symbol, used before MMU is enabled. 68 */ 69#define _RELOC(var, ar) \ 70 lea var,ar 71 72#define RELOC(var, ar) _RELOC(_C_LABEL(var), ar) 73#define ASRELOC(var, ar) _RELOC(_ASM_LABEL(var), ar) 74 75/* 76 * Macro to call into the Bug ROM monitor 77 */ 78#define CALLBUG(func) \ 79 trap #15; .short func 80 81/* 82 * Initialization 83 * 84 * The bootstrap loader loads us in starting at 0, and VBR is non-zero. 85 * On entry, args on stack are boot device, boot filename, console unit, 86 * boot flags (howto), boot device name, filesystem type name. 87 */ 88BSS(lowram,4) 89BSS(esym,4) 90 91 .globl _C_LABEL(edata) 92 .globl _C_LABEL(etext),_C_LABEL(end) 93 94 95/* 96 * This is for kvm_mkdb, and should be the address of the beginning 97 * of the kernel text segment (not necessarily the same as kernbase). 98 */ 99 .text 100GLOBAL(kernel_text) 101 102/* 103 * start of kernel and .text! 104 */ 105ASENTRY_NOPROFILE(start) 106 movw #PSL_HIGHIPL,%sr | no interrupts 107 movl #0,%a5 | RAM starts at 0 (a5) 108 movl %sp@(4), %d7 | get boothowto 109 movl %sp@(8), %d6 | get bootaddr 110 movl %sp@(12),%d5 | get bootctrllun 111 movl %sp@(16),%d4 | get bootdevlun 112 movl %sp@(20),%d3 | get bootpart 113 movl %sp@(24),%d2 | get esyms 114 115 RELOC(bootpart,%a0) 116 movl %d3, %a0@ | save bootpart 117 RELOC(bootdevlun,%a0) 118 movl %d4, %a0@ | save bootdevlun 119 RELOC(bootctrllun,%a0) 120 movl %d5, %a0@ | save booctrllun 121 RELOC(bootaddr,%a0) 122 movl %d6, %a0@ | save bootaddr 123 RELOC(boothowto,%a0) 124 movl %d7, %a0@ | save boothowto 125 /* note: d3-d7 free, d2 still in use */ 126 127 ASRELOC(tmpstk, %a0) 128 movl %a0,%sp | give ourselves a temporary stack 129 130 RELOC(edata,%a0) | clear out BSS 131 movl #_C_LABEL(end) - 4, %d0 | (must be <= 256 kB) 132 subl #_C_LABEL(edata), %d0 133 lsrl #2,%d0 1341: clrl %a0@+ 135 dbra %d0,1b 136 137 RELOC(esym, %a0) 138 movl %d2,%a0@ | store end of symbol table 139 /* d2 now free */ 140 RELOC(lowram, %a0) 141 movl %a5,%a0@ | store start of physical memory 142 movl #CACHE_OFF,%d0 143 movc %d0,%cacr | clear and disable on-chip cache(s) 144 145 /* ask the Bug what we are... */ 146 clrl %sp@- 147 CALLBUG(MVMEPROM_GETBRDID) 148 movl %sp@+,%a1 149 150 /* copy to a struct mvmeprom_brdid */ 151 movl #MVMEPROM_BRDID_SIZE,%d0 152 RELOC(boardid,%a0) 1531: movb %a1@+,%a0@+ 154 subql #1,%d0 155 jbne 1b 156 157 /* 158 * Grab the model number from _boardid and use the value 159 * to setup machineid, cputype, and mmutype. 160 */ 161 clrl %d0 162 RELOC(boardid,%a1) 163 movw %a1@(MVMEPROM_BRDID_MODEL_OFFSET),%d0 164 RELOC(machineid,%a0) 165 movl %d0,%a0@ 166 167 ASRELOC(Lbrdid2mach,%a0) 168Lbrdmatch: 169 cmpw %a0@+,%d0 170 jbeq Lgotmatch 171 addw #0x12,%a0 | Each entry is 20-2 bytes long 172 tstw %a0@ 173 jbne Lbrdmatch 174 175 /* 176 * If we fall to here, the board is not supported. 177 * Print a warning, then drop out to the Bug. 178 */ 179 movl #Lenotconf,%sp@- 180 movl #Lnotconf,%sp@- 181 CALLBUG(MVMEPROM_OUTSTRCRLF) 182 addql #8,%sp | clean up stack after call 183 184 CALLBUG(MVMEPROM_EXIT) 185 /* NOTREACHED */ 186 187 .data 188Lnotconf: 189 .ascii "Sorry, the kernel isn't configured for this model." 190Lenotconf: 191 .even 192 193ASLOCAL(Lbrdid2mach) 194#ifdef MVME147 195 .word MVME_147 196 .word CPU_68030 197 .word MMU_68030 198 .word FPU_68882 199 .long Linit147 200#endif 201#ifdef MVME162 202 .word MVME_162 203 .word CPU_68040 204 .word MMU_68040 205 .word FPU_68040 206 .long Linit1x2 207#endif 208#ifdef MVME167 209 .word MVME_167 210 .word CPU_68040 211 .word MMU_68040 212 .word FPU_68040 213 .long Linit1x7 214#endif 215#ifdef MVME172 216 .word MVME_172 217 .word CPU_68060 218 .word MMU_68040 219 .word FPU_68060 220 .long Linit1x2 221#endif 222#ifdef MVME177 223 .word MVME_177 224 .word CPU_68060 225 .word MMU_68040 226 .word FPU_68060 227 .long Linit1x7 228#endif 229 .word 0 230 .text 231 .even 232 233/* 234 * We have a match, so the kernel should support this board. 235 * a0 points to the matching entry in Lbrdid2mach. 236 */ 237Lgotmatch: 238 movew %a0@+,%d1 | Copy the CPU type 239 extl %d1 240 RELOC(cputype,%a1) 241 movel %d1,%a1@ 242 243 movew %a0@+,%d1 | Copy the MMU type 244 extl %d1 245 RELOC(mmutype,%a1) 246 movel %d1,%a1@ 247 248 movew %a0@+,%d1 | Copy the FPU type 249 extl %d1 250 RELOC(fputype,%a1) 251 movel %d1,%a1@ 252 253 movel %a0@,%a0 | Finally, the board-specific init code 254 jmp %a0@ 255 256 257#ifdef MVME147 258Linit147: 259 /* MVME-147 - 68030 CPU/MMU, 68882 FPU */ 260 /* XXXCDC SHUTUP 147 CALL */ 261 movb #0, 0xfffe1026 | serial interrupt off 262 movb #0, 0xfffe1018 | timer 1 off 263 movb #0, 0xfffe1028 | ethernet off 264 /* XXXCDC SHUTUP 147 CALL */ 265 266 /* Save our ethernet address */ 267 RELOC(mvme_ea, %a0) 268 lea 0xfffe0778,%a1 | XXXCDC -- HARDWIRED HEX 269 movb #0x08,%a0@+ 270 clrb %a0@+ 271 movb #0x3e,%a0@+ 272 movql #0x0f,%d0 273 andb %a1@+,%d0 274 orb #0x20,%d0 275 movb %d0,%a0@+ 276 movb %a1@+,%a0@+ 277 movb %a1@,%a0@ 278 279 /* 280 * Fix up the physical addresses of the MVME147's onboard 281 * I/O registers. 282 */ 283 RELOC(intiobase_phys, %a0); 284 movl #INTIOBASE147,%a0@ 285 RELOC(intiotop_phys, %a0); 286 movl #INTIOTOP147,%a0@ 287 288 /* initialise list of physical memory segments for pmap_bootstrap */ 289 RELOC(phys_seg_list, %a0) 290 movl %a5,%a0@ | phys_seg_list[0].ps_start 291 movl 0xfffe0774,%d1 | End + 1 of onboard memory 292 movl %d1,%a0@(4) | phys_seg_list[0].ps_end 293 clrl %a0@(8) | phys_seg_list[0].ps_startpage 294 295 /* offboard RAM */ 296 clrl %a0@(0x0c) | phys_seg_list[1].ps_start 297 movl #PAGE_SIZE-1,%d0 298 addl 0xfffe0764,%d0 | Start of offboard segment 299 andl #-PAGE_SIZE,%d0 | Round up to page boundary 300 jbeq Lsavmaxmem | Jump if none defined 301 movl #PAGE_SIZE,%d1 | Note: implicit '+1' 302 addl 0xfffe0768,%d1 | End of offboard segment 303 andl #-PAGE_SIZE,%d1 | Round up to page boundary 304 cmpl %d1,%d0 | Quick and dirty validity check 305 jbcs Loff_ok | Yup, looks good. 306 movel %a0@(4),%d1 | Just use onboard RAM otherwise 307 jbra Lsavmaxmem 308Loff_ok: 309 movl %d0,%a0@(0x0c) | phys_seg_list[1].ps_start 310 movl %d1,%a0@(0x10) | phys_seg_list[1].ps_end 311 clrl %a0@(0x14) | phys_seg_list[1].ps_startpage 312 313 /* 314 * Offboard RAM needs to be cleared to zero to initialise parity 315 * on most VMEbus RAM cards. Without this, some cards will buserr 316 * when first read. 317 */ 318 movel %d0,%a0 | offboard start address again. 319Lclearoff: 320 clrl %a0@+ | zap a word 321 cmpl %a0,%d1 | reached end? 322 jbne Lclearoff 323 324Lsavmaxmem: 325 moveq #PGSHIFT,%d2 326 lsrl %d2,%d1 | convert to page (click) number 327 RELOC(maxmem, %a0) 328 movl %d1,%a0@ | save as maxmem 329 jra Lstart1 330#endif 331 332#if defined(MVME162) || defined(MVME172) 333Linit1x2: 334 /* MVME-162 - 68040 CPU/MMU/FPU */ 335 /* MVME-172 - 68060 CPU/MMU/FPU */ 336 337 /* 338 * Verify the user has removed the GPIO#0 jumper... 339 */ 340 btst #0,0xfff4202d | Clear == jumper installed 341 jne 1f | Ok. 342 343 movl #Le1x2jump,%sp@- 344 movl #L1x2jump,%sp@- 345 CALLBUG(MVMEPROM_OUTSTRCRLF) 346 addql #8,%sp | clean up stack after call 347 348 CALLBUG(MVMEPROM_EXIT) 349 /* NOTREACHED */ 350 3511: 352 /* 353 * Determine if this board has a VMEchip2 354 */ 355 btst #1,0xfff4202e | VMEchip2 presence detect 356 jne 2f | Jump if it doesn't exist. 357 358 /* 359 * Disable all interrupts from VMEchip2. This is especially 360 * useful when the kernel doesn't have the VMEchip2 driver 361 * configured. If we didn't do this, then we're at the mercy 362 * of whatever VMEchip2 interrupts the ROM set up. For example, 363 * hitting the ABORT switch could kill the system... 364 */ 365 movl 0xfff40088,%d0 366 andl #0xff7fffff,%d0 | Clear 'MIEN' 367 movl %d0,0xfff40088 3682: 369 /* 370 * Determine how much onboard memory is installed 371 */ 372 movql #0x07,%d0 373 andb 0xfff42024,%d0 374 ASRELOC(Ldramsize1x2,%a0) 375 movl %a0@(%d0:w:4),%d1 | Lookup the size 376 jeq Lmemcquery | Assume a MEMC chip if this is zero. 377 jra Lis1xx_common 378 379 .data 380 .even 381 /* 382 * Table of DRAM register size values -> actual size in bytes 383 */ 384ASLOCAL(Ldramsize1x2) 385 .long 0x00100000 386 .long 0x00200000 387 .long 0x00000000 388 .long 0x00400000 389 .long 0x00400000 390 .long 0x00800000 391 .long 0x00000000 392 .long 0x01000000 393 394L1x2jump: 395 .ascii "You must remove the jumper from pins 15-16 of J22 (mvme162)" 396 .ascii "or pins 1-2\015\012" 397 .ascii "J11 (mvme162-LX) first! See NetBSD/mvme68k FAQ for details." 398Le1x2jump: 399 .even 400 401 .text 402#endif 403 404#if defined(MVME167) || defined(MVME177) 405Linit1x7: 406 /* MVME-167 - 68040 CPU/MMU/FPU */ 407 /* MVME-177 - 68060 CPU/MMU/FPU */ 408 409 /* 410 * Verify the user has removed the GPIO#0 jumper... 411 */ 412 movel #0x00000001,%d0 413 andl 0xfff40088,%d0 | Clear == jumper installed 414 jne 1f | Ok. 415 416 movl #Le1x7jump,%sp@- 417 movl #L1x7jump,%sp@- 418 CALLBUG(MVMEPROM_OUTSTRCRLF) 419 addql #8,%sp | clean up stack after call 420 421 CALLBUG(MVMEPROM_EXIT) 422 /* NOTREACHED */ 423 4241: 425 /* 426 * Disable all interrupts from VMEchip2. This is especially 427 * useful when the kernel doesn't have the VMEchip2 driver 428 * configured. If we didn't do this, then we're at the mercy 429 * of whatever VMEchip2 interrupts the ROM set up. For example, 430 * hitting the ABORT switch could kill the system... 431 */ 432 movl 0xfff40088,%d0 433 andl #0xff7fffff,%d0 | Clear 'MIEN' 434 movl %d0,0xfff40088 435 436 .data 437 .even 438L1x7jump: 439 .ascii "You must remove the jumper from pins 1-2 of J1!\015\012" 440 .ascii "See NetBSD/mvme68k FAQ for details." 441Le1x7jump: 442 .even 443 444 .text 445#endif 446 447#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177) 448Lmemcquery: 449 /* 450 * Figure out the size of onboard DRAM by querying 451 * the memory controller ASIC(s) 452 */ 453 lea 0xfff43008,%a0 | MEMC040/MEMECC Controller #1 454 jbsr memc040read 455 movl %d0,%d1 456 457 lea 0xfff43108,%a0 | MEMC040/MEMECC Controller #2 458 jbsr memc040read 459 addl %d0,%d1 460 461Lis1xx_common: 462 /* Save our ethernet address */ 463 RELOC(mvme_ea, %a0) 464 lea 0xfffc1f2c,%a1 465 movb %a1@+,%a0@+ 466 movb %a1@+,%a0@+ 467 movb %a1@+,%a0@+ 468 movb %a1@+,%a0@+ 469 movb %a1@+,%a0@+ 470 movb %a1@,%a0@ 471 472 /* 473 * Fix up the physical addresses of the onboard 474 * I/O registers. 475 */ 476 RELOC(intiobase_phys, %a0); 477 movl #INTIOBASE1xx,%a0@ 478 RELOC(intiotop_phys, %a0); 479 movl #INTIOTOP1xx,%a0@ 480 481 /* 482 * Initialise first physical memory segment with onboard RAM details 483 */ 484 RELOC(phys_seg_list, %a0) 485 movl %a5,%a0@ | phys_seg_list[0].ps_start 486 movl %d1,%a0@(4) | phys_seg_list[0].ps_end 487 clrl %a0@(8) | phys_seg_list[0].ps_startpage 488 489 /* offboard RAM */ 490 clrl %a0@(0x0c) | phys_seg_list[1].ps_start 491 movl #PAGE_SIZE-1,%d0 492 addl 0xfffc0000,%d0 | Start of offboard segment 493 andl #-PAGE_SIZE,%d0 | Round up to page boundary 494 jbeq Ldone1xx | Jump if none defined 495 movl #PAGE_SIZE,%d1 | Note: implicit '+1' 496 addl 0xfffc0004,%d1 | End of offboard segment 497 andl #-PAGE_SIZE,%d1 | Round up to page boundary 498 cmpl %d1,%d0 | Quick and dirty validity check 499 jbcs Lramsave1xx | Yup, looks good. 500 movel %a0@(4),%d1 | Just use onboard RAM otherwise 501 jbra Ldone1xx 502 503Lramsave1xx: 504 movl %d0,%a0@(0x0c) | phys_seg_list[1].ps_start 505 movl %d1,%a0@(0x10) | phys_seg_list[1].ps_end 506 clrl %a0@(0x14) | phys_seg_list[1].ps_startpage 507 508 /* 509 * Offboard RAM needs to be cleared to zero to initialise parity 510 * on most VMEbus RAM cards. Without this, some cards will buserr 511 * when first read. 512 */ 513 movel %d0,%a0 | offboard start address again. 514Lramclr1xx: 515 clrl %a0@+ | zap a word 516 cmpl %a0,%d1 | reached end? 517 jbne Lramclr1xx 518 519Ldone1xx: 520 moveq #PGSHIFT,%d2 521 lsrl %d2,%d1 | convert to page (click) number 522 RELOC(maxmem, %a0) 523 movl %d1,%a0@ | save as maxmem 524 525 /* FALLTHROUGH to Lstart1 */ 526#endif 527 528 529Lstart1: 530/* initialize source/destination control registers for movs */ 531 moveq #FC_USERD,%d0 | user space 532 movc %d0,%sfc | as source 533 movc %d0,%dfc | and destination of transfers 534/* 535 * configure kernel and lwp0 VA space so we can get going 536 */ 537#if NKSYMS || defined(DDB) || defined(MODULAR) 538 RELOC(esym,%a0) | end of static kernel text/data syms 539 movl %a0@,%d2 540 jne Lstart2 541#endif 542 movl #_C_LABEL(end),%d2 | end of static kernel text/data 543Lstart2: 544 addl #PAGE_SIZE-1,%d2 545 andl #PG_FRAME,%d2 | round to a page 546 movl %d2,%a4 547 addl %a5,%a4 | convert to PA 548 pea %a5@ | firstpa 549 pea %a4@ | nextpa 550 RELOC(pmap_bootstrap,%a0) 551 jbsr %a0@ | pmap_bootstrap(firstpa, nextpa) 552 addql #8,%sp 553 554/* 555 * Enable the MMU. 556 * Since the kernel is mapped logical == physical, we just turn it on. 557 */ 558 RELOC(Sysseg_pa, %a0) | system segment table addr 559 movl %a0@,%d1 | read value (a PA) 560 RELOC(mmutype, %a0) 561 cmpl #MMU_68040,%a0@ | 68040? 562 jne Lmotommu1 | no, skip 563 .long 0x4e7b1807 | movc d1,srp 564 jra Lstploaddone 565Lmotommu1: 566#ifdef M68030 567 RELOC(protorp, %a0) 568 movl %d1,%a0@(4) | segtable address 569 pmove %a0@,%srp | load the supervisor root pointer 570#endif /* M68030 */ 571Lstploaddone: 572 RELOC(mmutype, %a0) 573 cmpl #MMU_68040,%a0@ | 68040? 574 jne Lmotommu2 | no, skip 575 moveq #0,%d0 | ensure TT regs are disabled 576 .long 0x4e7b0004 | movc d0,itt0 577 .long 0x4e7b0005 | movc d0,itt1 578 .long 0x4e7b0006 | movc d0,dtt0 579 .long 0x4e7b0007 | movc d0,dtt1 580 .word 0xf4d8 | cinva bc 581 .word 0xf518 | pflusha 582 movl #0x8000,%d0 583 .long 0x4e7b0003 | movc d0,tc 584#ifdef M68060 585 RELOC(cputype, %a0) 586 cmpl #CPU_68060,%a0@ | 68060? 587 jne Lnot060cache 588 movl #1,%d0 589 .long 0x4e7b0808 | movcl d0,pcr 590 movl #0xa0808000,%d0 591 movc %d0,%cacr | enable store buffer, both caches 592 jmp Lenab1 593Lnot060cache: 594#endif 595 movl #0x80008000,%d0 596 movc %d0,%cacr | turn on both caches 597 jmp Lenab1 598Lmotommu2: 599 pflusha 600 movl #MMU51_TCR_BITS,%sp@- | value to load TC with 601 pmove %sp@,%tc | load it 602 603/* 604 * Should be running mapped from this point on 605 */ 606Lenab1: 607/* Point the CPU VBR at our vector table */ 608 lea _ASM_LABEL(tmpstk),%sp | re-load temporary stack 609 jbsr _C_LABEL(vec_init) | initialize vector table 610/* call final pmap setup */ 611 jbsr _C_LABEL(pmap_bootstrap_finalize) 612/* set kernel stack, user SP */ 613 movl _C_LABEL(lwp0uarea),%a1 | get lwp0 uarea 614 lea %a1@(USPACE-4),%sp | set kernel stack to end of area 615 movl #USRSTACK-4,%a2 616 movl %a2,%usp | init user SP 617 tstl _C_LABEL(fputype) | Have an FPU? 618 jeq Lenab2 | No, skip. 619 clrl %a1@(PCB_FPCTX) | ensure null FP context 620 movl %a1,%sp@- 621 jbsr _C_LABEL(m68881_restore) | restore it (does not kill a1) 622 addql #4,%sp 623Lenab2: 624 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? 625 jeq Ltbia040 | yes, cache already on 626 pflusha 627 movl #CACHE_ON,%d0 628 movc %d0,%cacr | clear cache(s) 629 jra Lenab3 630Ltbia040: 631 .word 0xf518 632Lenab3: 633/* 634 * final setup for C code: 635 * Create a fake exception frame so that cpu_lwp_fork() can copy it. 636 * main() nevers returns; we exit to user mode from a forked process 637 * later on. 638 */ 639 jbsr _C_LABEL(mvme68k_init) | additional pre-main initialization 640 movw #PSL_LOWIPL,%sr | lower SPL 641 clrw %sp@- | vector offset/frame type 642 clrl %sp@- | PC - filled in by "execve" 643 movw #PSL_USER,%sp@- | in user mode 644 clrl %sp@- | stack adjust count and padding 645 lea %sp@(-64),%sp | construct space for D0-D7/A0-A7 646 lea _C_LABEL(lwp0),%a0 | save pointer to frame 647 movl %sp,%a0@(L_MD_REGS) | in lwp0.l_md.md_regs 648 649 jra _C_LABEL(main) | main() 650 651#if defined(MVME162) || defined(MVME167) || defined(MVME172) || defined(MVME177) 652/* 653 * Probe for a memory controller ASIC (MEMC040 or MEMECC) at the 654 * address in a0. If found, return the size in bytes of any RAM 655 * controlled by the ASIC in d0. Otherwise return zero. 656 */ 657ASLOCAL(memc040read) 658 moveml %d1-%d2/%a1-%a2,%sp@- | save scratch regs 659 movc %vbr,%d2 | Save vbr 660 RELOC(vectab,%a2) | Install our own vectab, temporarily 661 movc %a2,%vbr 662 ASRELOC(Lmemc040berr,%a1) | get address of bus error handler 663 movl %a2@(8),%sp@- | Save current bus error handler addr 664 movl %a1,%a2@(8) | Install our own handler 665 movl %sp,%d0 | Save current stack pointer value 666 movql #0x07,%d1 667 andb %a0@,%d1 | Access MEMC040/MEMECC 668 movl #0x400000,%d0 669 lsll %d1,%d0 | Convert to memory size, in bytes 670Lmemc040ret: 671 movc %d2,%vbr | Restore original vbr 672 movl %sp@+,%a2@(8) | Restore original bus error handler 673 moveml %sp@+,%d1-%d2/%a1-%a2 674 rts 675/* 676 * If the memory controller doesn't exist, we get a bus error trying 677 * to access a0@ above. Control passes here, where we flag 'no bytes', 678 * ditch the exception frame and return as normal. 679 */ 680Lmemc040berr: 681 movl %d0,%sp | Get rid of the exception frame 682 movql #0,%d0 | No ASIC at this location, then! 683 jbra Lmemc040ret | Done 684#endif 685 686/* 687 * Trap/interrupt vector routines 688 */ 689#include <m68k/m68k/trap_subr.s> 690 691/* 692 * Use common m68k bus error and address error handlers. 693 */ 694#include <m68k/m68k/busaddrerr.s> 695 696/* 697 * FP exceptions. 698 */ 699ENTRY_NOPROFILE(fpfline) 700#if defined(M68040) 701 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 702 jne Lfp_unimp | no, skip FPSP 703 cmpw #0x202c,%sp@(6) | format type 2? 704 jne _C_LABEL(illinst) | no, not an FP emulation 705#ifdef FPSP 706 jmp _ASM_LABEL(fpsp_unimp) | yes, go handle it 707#else 708 clrl %sp@- | stack adjust count 709 moveml #0xFFFF,%sp@- | save registers 710 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 711 jra _ASM_LABEL(fault) | do it 712#endif 713Lfp_unimp: 714#endif /* M68040 */ 715 jra _C_LABEL(illinst) 716 717ENTRY_NOPROFILE(fpunsupp) 718#if defined(M68040) 719 cmpl #FPU_68040,_C_LABEL(fputype) | 68040 FPU? 720 jne Lfp_unsupp | No, skip FPSP 721#ifdef FPSP 722 jmp _ASM_LABEL(fpsp_unsupp) | yes, go handle it 723#else 724 clrl %sp@- | stack adjust count 725 moveml #0xFFFF,%sp@- | save registers 726 moveq #T_FPEMULD,%d0 | denote as FP emulation trap 727 jra _ASM_LABEL(fault) | do it 728#endif 729Lfp_unsupp: 730#endif /* M68040 */ 731 jra _C_LABEL(illinst) 732 733/* 734 * Handles all other FP coprocessor exceptions. 735 * Note that since some FP exceptions generate mid-instruction frames 736 * and may cause signal delivery, we need to test for stack adjustment 737 * after the trap call. 738 */ 739ENTRY_NOPROFILE(fpfault) 740 clrl %sp@- | stack adjust count 741 moveml #0xFFFF,%sp@- | save user registers 742 movl %usp,%a0 | and save 743 movl %a0,%sp@(FR_SP) | the user stack pointer 744 clrl %sp@- | no VA arg 745 movl _C_LABEL(curpcb),%a0 | current pcb 746 lea %a0@(PCB_FPCTX),%a0 | address of FP savearea 747 fsave %a0@ | save state 748#if defined(M68040) || defined(M68060) 749 /* always null state frame on 68040, 68060 */ 750 cmpl #FPU_68040,_C_LABEL(fputype) 751 jge Lfptnull 752#endif 753 tstb %a0@ | null state frame? 754 jeq Lfptnull | yes, safe 755 clrw %d0 | no, need to tweak BIU 756 movb %a0@(1),%d0 | get frame size 757 bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU 758Lfptnull: 759 fmovem %fpsr,%sp@- | push fpsr as code argument 760 frestore %a0@ | restore state 761 movl #T_FPERR,%sp@- | push type arg 762 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup 763 764 765/* 766 * Other exceptions only cause four and six word stack frame and require 767 * no post-trap stack adjustment. 768 */ 769 770ENTRY_NOPROFILE(badtrap) 771 moveml #0xC0C0,%sp@- | save scratch regs 772 movw %sp@(22),%sp@- | push exception vector info 773 clrw %sp@- 774 movl %sp@(22),%sp@- | and PC 775 jbsr _C_LABEL(straytrap) | report 776 addql #8,%sp | pop args 777 moveml %sp@+,#0x0303 | restore regs 778 jra _ASM_LABEL(rei) | all done 779 780ENTRY_NOPROFILE(trap0) 781 clrl %sp@- | stack adjust count 782 moveml #0xFFFF,%sp@- | save user registers 783 movl %usp,%a0 | save the user SP 784 movl %a0,%sp@(FR_SP) | in the savearea 785 movl %d0,%sp@- | push syscall number 786 jbsr _C_LABEL(syscall) | handle it 787 addql #4,%sp | pop syscall arg 788 tstl _C_LABEL(astpending) | AST pending? 789 jne Lrei1 | Yup, go deal with it. 790 movl %sp@(FR_SP),%a0 | grab and restore 791 movl %a0,%usp | user SP 792 moveml %sp@+,#0x7FFF | restore most registers 793 addql #8,%sp | pop SP and stack adjust 794 rte 795 796/* 797 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) 798 * cachectl(command, addr, length) 799 * command in d0, addr in a1, length in d1 800 */ 801ENTRY_NOPROFILE(trap12) 802 movl _C_LABEL(curlwp),%a0 803 movl %a0@(L_PROC),%sp@- | push current proc pointer 804 movl %d1,%sp@- | push length 805 movl %a1,%sp@- | push addr 806 movl %d0,%sp@- | push command 807 jbsr _C_LABEL(cachectl1) | do it 808 lea %sp@(16),%sp | pop args 809 jra _ASM_LABEL(rei) | all done 810 811/* 812 * Trace (single-step) trap. Kernel-mode is special. 813 * User mode traps are simply passed on to trap(). 814 */ 815ENTRY_NOPROFILE(trace) 816 clrl %sp@- | stack adjust count 817 moveml #0xFFFF,%sp@- 818 moveq #T_TRACE,%d0 819 820 | Check PSW and see what happen. 821 | T=0 S=0 (should not happen) 822 | T=1 S=0 trace trap from user mode 823 | T=0 S=1 trace trap on a trap instruction 824 | T=1 S=1 trace trap from system mode (kernel breakpoint) 825 826 movw %sp@(FR_HW),%d1 | get PSW 827 notw %d1 | XXX no support for T0 on 680[234]0 828 andw #PSL_TS,%d1 | from system mode (T=1, S=1)? 829 jeq Lkbrkpt | yes, kernel breakpoint 830 jra _ASM_LABEL(fault) | no, user-mode fault 831 832/* 833 * Trap 15 is used for: 834 * - GDB breakpoints (in user programs) 835 * - KGDB breakpoints (in the kernel) 836 * - trace traps for SUN binaries (not fully supported yet) 837 * User mode traps are simply passed to trap(). 838 */ 839ENTRY_NOPROFILE(trap15) 840 clrl %sp@- | stack adjust count 841 moveml #0xFFFF,%sp@- 842 moveq #T_TRAP15,%d0 843 movw %sp@(FR_HW),%d1 | get PSW 844 andw #PSL_S,%d1 | from system mode? 845 jne Lkbrkpt | yes, kernel breakpoint 846 jra _ASM_LABEL(fault) | no, user-mode fault 847 848Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type) 849 | Save the system sp rather than the user sp. 850 movw #PSL_HIGHIPL,%sr | lock out interrupts 851 lea %sp@(FR_SIZE),%a6 | Save stack pointer 852 movl %a6,%sp@(FR_SP) | from before trap 853 854 | If were are not on tmpstk switch to it. 855 | (so debugger can change the stack pointer) 856 movl %a6,%d1 857 cmpl #_ASM_LABEL(tmpstk),%d1 858 jls Lbrkpt2 | already on tmpstk 859 | Copy frame to the temporary stack 860 movl %sp,%a0 | a0=src 861 lea _ASM_LABEL(tmpstk)-96,%a1 | a1=dst 862 movl %a1,%sp | sp=new frame 863 movql #FR_SIZE,%d1 864Lbrkpt1: 865 movl %a0@+,%a1@+ 866 subql #4,%d1 867 jbgt Lbrkpt1 868 869Lbrkpt2: 870 | Call the trap handler for the kernel debugger. 871 | Do not call trap() to do it, so that we can 872 | set breakpoints in trap() if we want. We know 873 | the trap type is either T_TRACE or T_BREAKPOINT. 874 | If we have both DDB and KGDB, let KGDB see it first, 875 | because KGDB will just return 0 if not connected. 876 | Save args in d2, a2 877 movl %d0,%d2 | trap type 878 movl %sp,%a2 | frame ptr 879#ifdef KGDB 880 | Let KGDB handle it (if connected) 881 movl %a2,%sp@- | push frame ptr 882 movl %d2,%sp@- | push trap type 883 jbsr _C_LABEL(kgdb_trap) | handle the trap 884 addql #8,%sp | pop args 885 cmpl #0,%d0 | did kgdb handle it? 886 jne Lbrkpt3 | yes, done 887#endif 888#ifdef DDB 889 | Let DDB handle it 890 movl %a2,%sp@- | push frame ptr 891 movl %d2,%sp@- | push trap type 892 jbsr _C_LABEL(kdb_trap) | handle the trap 893 addql #8,%sp | pop args 894#endif 895 /* Sun 3 drops into PROM here. */ 896Lbrkpt3: 897 | The stack pointer may have been modified, or 898 | data below it modified (by kgdb push call), 899 | so push the hardware frame at the current sp 900 | before restoring registers and returning. 901 902 movl %sp@(FR_SP),%a0 | modified sp 903 lea %sp@(FR_SIZE),%a1 | end of our frame 904 movl %a1@-,%a0@- | copy 2 longs with 905 movl %a1@-,%a0@- | ... predecrement 906 movl %a0,%sp@(FR_SP) | sp = h/w frame 907 moveml %sp@+,#0x7FFF | restore all but sp 908 movl %sp@,%sp | ... and sp 909 rte | all done 910 911/* 912 * Emulation of VAX REI instruction. 913 * 914 * This code deals with checking for and servicing ASTs 915 * (profiling, scheduling). 916 * After identifying that we need an AST we drop the IPL to allow device 917 * interrupts. 918 * 919 * This code is complicated by the fact that sendsig may have been called 920 * necessitating a stack cleanup. 921 */ 922ASENTRY_NOPROFILE(rei) 923 tstl _C_LABEL(astpending) | AST pending? 924 jeq Ldorte | Nope. Just return. 925 btst #5,%sp@ | Returning to kernel mode? 926 jne Ldorte | Yup. Can't do ASTs 927 movw #PSL_LOWIPL,%sr | lower SPL 928 clrl %sp@- | stack adjust 929 moveml #0xFFFF,%sp@- | save all registers 930 movl %usp,%a1 | including 931 movl %a1,%sp@(FR_SP) | the users SP 932Lrei1: clrl %sp@- | VA == none 933 clrl %sp@- | code == none 934 movl #T_ASTFLT,%sp@- | type == async system trap 935 pea %sp@(12) | fp == address of trap frame 936 jbsr _C_LABEL(trap) | go handle it 937 lea %sp@(16),%sp | pop value args 938 movl %sp@(FR_SP),%a0 | restore user SP 939 movl %a0,%usp | from save area 940 movw %sp@(FR_ADJ),%d0 | need to adjust stack? 941 jne Laststkadj | yes, go to it 942 moveml %sp@+,#0x7FFF | no, restore most user regs 943 addql #8,%sp | toss SP and stack adjust 944Ldorte: rte | and do real RTE 945 946Laststkadj: 947 lea %sp@(FR_HW),%a1 | pointer to HW frame 948 addql #8,%a1 | source pointer 949 movl %a1,%a0 | source 950 addw %d0,%a0 | + hole size = dest pointer 951 movl %a1@-,%a0@- | copy 952 movl %a1@-,%a0@- | 8 bytes 953 movl %a0,%sp@(FR_SP) | new SSP 954 moveml %sp@+,#0x7FFF | restore user registers 955 movl %sp@,%sp | and our SP 956 rte | and do real RTE 957 958/* 959 * Primitives 960 */ 961 962/* 963 * Use common m68k process/lwp switch and context save subroutines. 964 */ 965#define FPCOPROC /* XXX: Temp. Reqd. */ 966#include <m68k/m68k/switch_subr.s> 967 968 969#if defined(M68040) || defined(M68060) 970ENTRY(suline) 971 movl %sp@(4),%a0 | address to write 972 movl _C_LABEL(curpcb),%a1 | current pcb 973 movl #Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault 974 movl %sp@(8),%a1 | address of line 975 movl %a1@+,%d0 | get lword 976 movsl %d0,%a0@+ | put lword 977 nop | sync 978 movl %a1@+,%d0 | get lword 979 movsl %d0,%a0@+ | put lword 980 nop | sync 981 movl %a1@+,%d0 | get lword 982 movsl %d0,%a0@+ | put lword 983 nop | sync 984 movl %a1@+,%d0 | get lword 985 movsl %d0,%a0@+ | put lword 986 nop | sync 987 moveq #0,%d0 | indicate no fault 988 jra Lsldone 989Lslerr: 990 moveq #-1,%d0 991Lsldone: 992 movl _C_LABEL(curpcb),%a1 | current pcb 993 clrl %a1@(PCB_ONFAULT) | clear fault address 994 rts 995#endif 996 997 998ENTRY(ecacheon) 999 rts 1000 1001ENTRY(ecacheoff) 1002 rts 1003 1004/* 1005 * _delay(unsigned N) 1006 * 1007 * Delay for at least (N/1024) microseconds. 1008 * This routine depends on the variable: delay_divisor 1009 * which should be set based on the CPU clock rate. 1010 */ 1011ENTRY_NOPROFILE(_delay) 1012 | d0 = arg = (usecs << 10) 1013 movl %sp@(4),%d0 1014 | d1 = delay_divisor 1015 movl _C_LABEL(delay_divisor),%d1 1016 jra L_delay /* Jump into the loop! */ 1017 1018 /* 1019 * Align the branch target of the loop to a half-line (8-byte) 1020 * boundary to minimize cache effects. This guarantees both 1021 * that there will be no prefetch stalls due to cache line burst 1022 * operations and that the loop will run from a single cache 1023 * half-line. 1024 */ 1025#ifdef __ELF__ 1026 .align 8 1027#else 1028 .align 3 1029#endif 1030L_delay: 1031 subl %d1,%d0 1032 jgt L_delay 1033 rts 1034 1035/* 1036 * Handle the nitty-gritty of rebooting the machine. 1037 * Basically we just turn off the MMU, restore the Bug's initial VBR 1038 * and either return to Bug or jump through the ROM reset vector 1039 * depending on how the system was halted. 1040 */ 1041ENTRY_NOPROFILE(doboot) 1042 movw #PSL_HIGHIPL,%sr 1043 movl _C_LABEL(boothowto),%d1 | load howto 1044 movl %sp@(4),%d2 | arg 1045 movl _C_LABEL(saved_vbr),%d3 | Fetch Bug's original VBR value 1046 movl _C_LABEL(machineid),%d4 | What type of board is this? 1047 movl #CACHE_OFF,%d0 1048#if defined(M68040) || defined(M68060) 1049 cmpl #MMU_68040,_C_LABEL(mmutype) | 68040/68060? 1050 jne Lnocache0 | no, skip 1051 .word 0xf4f8 | cpusha bc - push and invalidate caches 1052 nop 1053 movl #CACHE40_OFF,%d0 1054#endif 1055Lnocache0: 1056 movc %d0,%cacr | disable on-chip cache(s) 1057 1058#if defined(M68040) || defined(M68060) 1059 cmpl #MMU_68040,_C_LABEL(mmutype) 1060 jne LmotommuF 1061 movql #0,%d0 1062 movc %d0,%cacr 1063 .long 0x4e7b0003 | movc d0,tc 1064 jra Lbootcommon 1065LmotommuF: 1066#endif 1067 clrl %sp@- | value for pmove to TC (turn off MMU) 1068 pmove %sp@,%tc | disable MMU 1069 addql #4,%sp 1070 1071Lbootcommon: 1072 /* 1073 * MMU Switched off by now, so relocate all absolute references 1074 */ 1075 ASRELOC(tmpstk, %sp) | physical SP in case of NMI 1076 movc %d3,%vbr | Restore Bug's VBR 1077 andl #RB_SBOOT, %d1 | mask off 1078 jbne Lsboot | sboot? 1079 /* NOT sboot */ 1080 tstl %d2 | autoboot? 1081 jbeq Ldoreset | yes! 1082 CALLBUG(MVMEPROM_EXIT) | return to bug 1083 /* NOTREACHED */ 1084 1085Ldoreset: 1086 movl #0xff800000,%a0 | Bug's reset vector address 1087 movl %a0@+, %a7 | get SP 1088 movl %a0@, %a0 | get PC 1089 jmp %a0@ | go! 1090 1091Lsboot: /* sboot */ 1092 tstl %d2 | autoboot? 1093 jbeq 1f | yes! 1094 jmp 0x4000 | back to sboot 10951: jmp 0x400a | tell sboot to reboot us 1096 1097 1098/* 1099 * Misc. global variables. 1100 */ 1101 .data 1102 1103GLOBAL(machineid) 1104 .long MVME_147 | default to MVME_147 1105 1106GLOBAL(mmutype) 1107 .long MMU_68030 | default to MMU_68030 1108 1109GLOBAL(cputype) 1110 .long CPU_68030 | default to CPU_68030 1111 1112GLOBAL(fputype) 1113 .long FPU_68882 | default to FPU_68882 1114 1115/* 1116 * Information from first stage boot program 1117 */ 1118GLOBAL(bootpart) 1119 .long 0 1120GLOBAL(bootdevlun) 1121 .long 0 1122GLOBAL(bootctrllun) 1123 .long 0 1124GLOBAL(bootaddr) 1125 .long 0 1126 1127GLOBAL(intiobase) 1128 .long 0 | KVA of base of internal IO space 1129 1130GLOBAL(intiolimit) 1131 .long 0 | KVA of end of internal IO space 1132 1133GLOBAL(intiobase_phys) 1134 .long 0 | PA of board's I/O registers 1135 1136GLOBAL(intiotop_phys) 1137 .long 0 | PA of top of board's I/O registers 1138