Home | History | Annotate | Line # | Download | only in mac68k
      1 /*	$NetBSD: locore.s,v 1.210 2026/06/13 15:28:08 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988 University of Utah.
      5  * Copyright (c) 1982, 1990 The Regents of the University of California.
      6  * 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 
     37 /*-
     38  * Copyright (C) 1993	Allen K. Briggs, Chris P. Caputo,
     39  *			Michael L. Finch, Bradley A. Grantham, and
     40  *			Lawrence A. Kesteloot
     41  * All rights reserved.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  * 3. All advertising materials mentioning features or use of this software
     52  *    must display the following acknowledgement:
     53  *	This product includes software developed by the Alice Group.
     54  * 4. The names of the Alice Group or any of its members may not be used
     55  *    to endorse or promote products derived from this software without
     56  *    specific prior written permission.
     57  *
     58  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
     59  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     60  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     61  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
     62  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     63  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     64  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     65  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     66  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     67  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     68  *
     69  */
     70 
     71 /*
     72  * from: Utah $Hdr: locore.s 1.58 91/04/22$
     73  *
     74  *	@(#)locore.s	7.11 (Berkeley) 5/9/91
     75  */
     76 
     77 #include "opt_compat_netbsd.h"
     78 #include "opt_compat_sunos.h"
     79 #include "opt_ddb.h"
     80 #include "opt_fpu_emulate.h"
     81 #include "opt_kgdb.h"
     82 #include "opt_lockdebug.h"
     83 #include "opt_fpsp.h"
     84 #include "opt_m68k_arch.h"
     85 
     86 #include "assym.h"
     87 
     88 #include <machine/asm.h>
     89 #include <machine/trap.h>
     90 
     91 /*
     92  * This is for kvm_mkdb, and should be the address of the beginning
     93  * of the kernel text segment (not necessarily the same as kernbase).
     94  */
     95 	.text
     96 GLOBAL(kernel_text)
     97 
     98 #include <mac68k/mac68k/vectors.s>
     99 #include <mac68k/mac68k/macglobals.s>
    100 
    101 /*
    102  * Initialization
    103  */
    104 
    105 	.data
    106 | Scratch memory.  Careful when messing with these...
    107 ASLOCAL(longscratch)
    108 	.long	0
    109 ASLOCAL(longscratch2)
    110 	.long	0
    111 ASLOCAL(pte_tmp)			| for get_pte()
    112 	.long	0
    113 GLOBAL(macos_crp1)
    114 	.long	0
    115 GLOBAL(macos_crp2)
    116 	.long	0
    117 GLOBAL(macos_tc)
    118 	.long	0
    119 GLOBAL(macos_tt0)
    120 	.long	0
    121 GLOBAL(macos_tt1)
    122 	.long	0
    123 GLOBAL(bletch)
    124 	.long	0
    125 
    126 BSS(esym,4)
    127 
    128 ASENTRY_NOPROFILE(start)
    129 	movw	#PSL_HIGHIPL,%sr	| no interrupts.  ever.
    130 	lea	_ASM_LABEL(tmpstk),%sp	| give ourselves a temporary stack
    131 
    132 	movl	#CACHE_OFF,%d0
    133 	movc	%d0,%cacr		| clear and disable on-chip cache(s)
    134 
    135 	/* Initialize source/destination control registers for movs */
    136 	movql	#FC_USERD,%d0		| user space
    137 	movc	%d0,%sfc		|   as source
    138 	movc	%d0,%dfc		|   and destination of transfers
    139 
    140 	/*
    141 	 * Some parameters provided by MacOS
    142 	 *
    143 	 * LAK: This section is the new way to pass information from the booter
    144 	 * to the kernel.  At A1 there is an environment variable which has
    145 	 * a bunch of stuff in ascii format, "VAR=value\0VAR=value\0\0".
    146 	 */
    147 	movl	%a1,%sp@-		| Address of buffer
    148 	movl	%d4,%sp@-		| Some flags... (mostly not used)
    149 	jbsr	_C_LABEL(getenvvars)	| Parse the environment buffer
    150 	addql	#8,%sp
    151 
    152 	/* Determine MMU/MPU from what we can test empirically */
    153 	movl	#0x200,%d0		| data freeze bit
    154 	movc	%d0,%cacr		|   only exists on 68030
    155 	movc	%cacr,%d0		| read it back
    156 	tstl	%d0			| zero?
    157 	jeq	Lnot68030		| yes, we have 68020/68040/68060
    158 
    159 	movl	#CACHE_OFF,%d0		| disable and clear both caches
    160 	movc	%d0,%cacr
    161 	lea	_C_LABEL(mmutype),%a0	| no, we have 68030
    162 	movl	#MMU_68030,%a0@		| set to reflect 68030 PMMU
    163 	lea	_C_LABEL(cputype),%a0
    164 	movl	#CPU_68030,%a0@		| and 68030 MPU
    165 	jra	Lstart1
    166 
    167 Lnot68030:
    168 	bset	#31,%d0			| data cache enable bit
    169 	movc	%d0,%cacr		|   only exists on 68040/68060
    170 	movc	%cacr,%d0		| read it back
    171 	tstl	%d0			| zero?
    172 	beq	Lis68020		| yes, we have 68020
    173 
    174 	movql	#CACHE40_OFF,%d0	| now turn it back off
    175 	movc	%d0,%cacr		|   before we access any data
    176 	.word	0xf4f8			| cpusha bc ;push and invalidate caches
    177 	bset	#30,%d0			| data cache no allocate mode bit
    178 	movc	%d0,%cacr		|   only exists on 68060
    179 	movc	%cacr,%d0		| read it back
    180 	tstl	%d0			| zero?
    181 	jeq	Lis68040		| yes, we have 68040
    182 	lea	_C_LABEL(mmutype),%a0	| no, we have 68060
    183 	movl	#MMU_68040,%a0@		| with a 68040 compatible MMU
    184 	lea	_C_LABEL(cputype),%a0
    185 	movl	#CPU_68060,%a0@		| and a 68060 CPU
    186 
    187 	| Mac OS may be running with 060 FPU disabled. Check if we have
    188 	| one and re-enable it.  Assume superscalar execution and loadstore
    189 	| bypass are already enabled if required.
    190 	| XXXJRT revisit this maybe?
    191 	.word	0x4e7a,0x1808		| movc	pcr,d1
    192 	cmpw	#0x0430,%d1		| check ID word
    193 	jne	Lstart1			| no FPU? go to start
    194 	swap	%d1
    195 	bclr	#1,%d1			| ... and switch it on.
    196 	.word	0x4e7b,0x1808		| movc	d1,pcr
    197 	jra	Lstart1
    198 Lis68040:
    199 	lea	_C_LABEL(mmutype),%a0
    200 	movl	#MMU_68040,%a0@		| Reflect 68040 MMU
    201 	lea	_C_LABEL(cputype),%a0
    202 	movl	#CPU_68040,%a0@		| and 68040 MPU
    203 	jra	Lstart1
    204 
    205 Lis68020:
    206 	movl	#CACHE_OFF,%d0		| disable and clear cache
    207 	movc	%d0,%cacr
    208 	lea	_C_LABEL(mmutype),%a0	| Must be 68020+68851
    209 	movl	#MMU_68851,%a0@		| Reflect 68851 PMMU
    210 	lea	_C_LABEL(cputype),%a0
    211 	movl	#CPU_68020,%a0@		| and 68020 MPU
    212 
    213 Lstart1:
    214 	jbsr	_C_LABEL(setmachdep)	| Set some machine-dep stuff
    215 	jbsr	_C_LABEL(consinit)	| XXX Should only be if graybar on
    216 
    217 /*
    218  * Figure out MacOS mappings and bootstrap NetBSD
    219  */
    220 	lea	_C_LABEL(macos_tc),%a0	| get current %TC
    221 	cmpl	#MMU_68040,_C_LABEL(mmutype) | check to see if 68040
    222 	jeq	Lget040TC
    223 
    224 	pmove	%tc,%a0@
    225 	jra	Lstart3
    226 
    227 Lget040TC:
    228 #if 0
    229 	movl	_C_LABEL(current_mac_model),%a1	 | if an AV Mac, save current
    230 	cmpl	#MACH_CLASSAV,%a1@(CPUINFO_CLASS) | %TC so internal video will
    231 	jne	LnotAV				 | get configured
    232 #endif
    233 	.long	0x4e7a0003		| movc %tc,%d0
    234 	jra	LsaveTC
    235 LnotAV:
    236 	movql	#0,%d0			| otherwise,
    237 	.long	0x4e7b0003		| movc %d0,%tc ;Disable MMU
    238 LsaveTC:
    239 	movl	%d0,%a0@
    240 
    241 Lstart3:
    242 	movl	%a0@,%sp@-		| get Mac OS mapping, relocate video,
    243 	jbsr	_C_LABEL(bootstrap_mac68k) |   bootstrap pmap, et al.
    244 	addql	#4,%sp
    245 
    246 	/*
    247 	 * nextpa is returned in %d0.  We need to squirrel that
    248 	 * away in a callee-saved regstier for use later, after
    249 	 * the MMU is enabled.
    250 	 */
    251 	movl	%d0, %d7
    252 
    253 	/* NOTE: %d7 is now off-limits!! */
    254 
    255 	/*
    256 	 * Set up the vector table, and race to get the MMU
    257 	 * enabled.
    258 	 *
    259 	 * XXX Should move vec_init() call to Lloaddone, like other
    260 	 * XXX m68k platforms do.
    261 	 */
    262 	jbsr	_C_LABEL(vec_init)
    263 
    264 	movl	_C_LABEL(Sysseg_pa),%a1	| system segment table PA
    265 	cmpl	#MMU_68040,_C_LABEL(mmutype)
    266 	jne	Lenablepre040MMU	| if not 040, skip
    267 
    268 	movql	#0,%d0
    269 	.long	0x4e7b0003		| movc %d0,%tc   ;Disable MMU
    270 	.long	0x4e7b0004		| movc %d0,%itt0 ;Disable itt0
    271 	.long	0x4e7b0005		| movc %d0,%itt1 ;Disable itt1
    272 	.long	0x4e7b0006		| movc %d0,%dtt0 ;Disable dtt0
    273 	.long	0x4e7b0007		| movc %d0,%dtt1 ;Disable dtt1
    274 	movl	%a1,%d1
    275 	.word	0xf518			| pflusha
    276 	.long	0x4e7b1807		| movc %d1,%srp
    277 
    278 #if defined(DJMEMCMAX)
    279 	movl	%a3,%sp@-
    280 	cmpl	#MACH_MACC610,_C_LABEL(machineid)
    281 	jeq	Ldjmemc610
    282 	cmpl	#MACH_MACQ610,_C_LABEL(machineid)
    283 	jeq	Ldjmemc610
    284 	cmpl	#MACH_MACC650,_C_LABEL(machineid)
    285 	jeq	Ldjmemccfg
    286 	cmpl	#MACH_MACQ650,_C_LABEL(machineid)
    287 	jeq	Ldjmemccfg
    288 	cmpl	#MACH_MACQ800,_C_LABEL(machineid)
    289 	jeq	Ldjmemccfg
    290 
    291 	jra	Lnodjmemc
    292 
    293 Ldjmemccfg:
    294 	movl	#0x50f0e00c,%a0
    295 	movl	%a0@,%d0	| determine where RAM SIMMs start
    296 	andl	#0x000000FF,%d0
    297 	addl	#0x10,%d0	| bank 3 start
    298 	addl	#0x10,%d0	| bank 4 start
    299 
    300 	movl	#0x50f0e014,%a0
    301 	movl	%d0,%a0@+	| bank 4
    302 	addl	#0x10,%d0
    303 	movl	%d0,%a0@+	| bank 5
    304 	addl	#0x10,%d0
    305 
    306 	movl	%d0,%a0@+	| bank 6
    307 	addl	#0x10,%d0
    308 	movl	%d0,%a0@+	| bank 7
    309 	addl	#0x10,%d0
    310 	movl	%d0,%a0@+	| bank 8
    311 	addl	#0x10,%d0
    312 	movl	%d0,%a0@+	| bank 9
    313 	addl	#0x10,%d0
    314 	jra	Ldjmemctop
    315 
    316 Ldjmemc610:
    317 	movl	#0x50f0e00c,%a0
    318 	movl	%a0@,%d0	| determine where RAM SIMMs start
    319 	andl	#0x000000FF,%d0
    320 	addl	#0x10,%d0	| bank 3 start
    321 
    322 	movl	#0x50f0e014,%a0
    323 	movl	%d0,%a0@+	| bank 4
    324 	addl	#0x10,%d0
    325 	movl	%d0,%a0@+	| bank 5
    326 	movl	%d0,%a0@+	| bank 6
    327 	addl	#0x10,%d0
    328 	movl	%d0,%a0@+	| bank 7
    329 	movl	%d0,%a0@+	| bank 8
    330 	addl	#0x10,%d0
    331 	movl	%d0,%a0@+	| bank 9
    332 
    333 Ldjmemctop:
    334 	movl	#0x50F0E02C,%a0
    335 	movl	%d0,%a0@	| memtop
    336 
    337 	| preserve ~512KB beyond 4MB just in case
    338 	movl	#0x400000,%a0
    339 	movl	#0x9000000,%a2
    340 	movl	#0xFFFF,%d0
    341 L1stbankcopy1:
    342 	movl	%a0@+,%a2@+
    343 	dbra	%d0,L1stbankcopy1
    344 	movl	#0xFFFF,%d0
    345 L1stbankcopy2:
    346 	movl	%a0@+,%a2@+
    347 	dbra	%d0,L1stbankcopy2
    348 
    349 	lea	_ASM_LABEL(Lsetup1stbank),%a0
    350 	movl	#0x8800000,%a2	| Pick a location that should be in bank 4
    351 	movl	#0x64,%d0
    352 Ldjcopy:
    353 	movl	%a0@+,%a2@+
    354 	dbra	%d0,Ldjcopy
    355 
    356 	movl	#0x8800000,%a0
    357 	lea	_ASM_LABEL(Ldjmemcdone),%a2
    358 	jmp	%a0@
    359 
    360 Lsetup1stbank:
    361 	| now configure banks 2 & 3
    362 	movl	#0x50f0e00c,%a0
    363 	movl	%a0@,%d0	| determine where RAM SIMMs start
    364 	andl	#0x000000FF,%d0
    365 	movl	%d0,%a0@+
    366 	addl	#0x10,%d0	| bank 3 start
    367 	movl	%d0,%a0@
    368 
    369 	| and return to where we came from.
    370 	jmp	%a2@
    371 
    372 Ldjmemcdone:
    373 	movl	#0x400000,%a2
    374 	movl	#0x9000000,%a0
    375 	movl	#0xFFFF,%d0
    376 Lcopyback1:
    377 	movl	%a0@+,%a2@+
    378 	dbra	%d0,Lcopyback1
    379 	movl	#0xFFFF,%d0
    380 Lcopyback2:
    381 	movl	%a0@+,%a2@+
    382 	dbra	%d0,Lcopyback2
    383 
    384 Lnodjmemc:
    385 	movl	%sp@+,%a3
    386 #endif
    387 
    388 	movl	#MMU40_TCR_BITS,%d0
    389 	.long	0x4e7b0003		| movc %d0,%tc   ;Enable MMU
    390 	movl	#CACHE40_ON,%d0
    391 #ifdef M68060
    392 	cmpl	#CPU_68060,_C_LABEL(cputype)
    393 	jne	Lcacheon
    394 	movl	#CACHE60_ON,%d0
    395 #endif
    396 Lcacheon:
    397 	movc	%d0,%cacr		| turn on both caches
    398 	jra	Lloaddone
    399 
    400 Lenablepre040MMU:
    401 	tstl	_C_LABEL(mmutype)	| TTx instructions will break 68851
    402 	jgt	LnokillTT
    403 
    404 	lea	_ASM_LABEL(longscratch),%a0 | disable TTx registers on 68030
    405 	movl	#0,%a0@
    406 	.long	0xf0100800		| movl %a0@,%tt0
    407 	.long	0xf0100c00		| movl %a0@,%tt1
    408 
    409 LnokillTT:
    410 #if defined(M68020) || defined(M68030)
    411 	lea	_C_LABEL(protorp),%a0
    412 	movl	%a1,%a0@(4)		| segtable address
    413 	pmove	%a0@,%srp		| load the supervisor root pointer
    414 	pflusha
    415 	lea	_ASM_LABEL(longscratch),%a2
    416 	movl	#MMU51_TCR_BITS,%a2@	| value to load %TC with
    417 	pmove	%a2@,%tc		| load it
    418 #endif /* M68020 || M68030 */
    419 
    420 /*
    421  * Should be running mapped from this point on
    422  */
    423 Lloaddone:
    424 	lea	_ASM_LABEL(tmpstk),%sp	| temporary stack
    425 
    426 	/* phase 2 of pmap setup, returns lwp0 SP in %a0 */
    427 	jbsr	_C_LABEL(pmap_bootstrap2)
    428 	movl	%a0,%sp			| now running on lwp0's stack
    429 	movl	#0,%a6			| terminate the stack back trace
    430 
    431 /* flush TLB and turn on caches */
    432 	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040/060?
    433 	jeq	Ltbia040		| yes, cache already on
    434 	pflusha
    435 	movl	#CACHE_ON,%d0
    436 	movc	%d0,%cacr		| clear cache(s)
    437 #ifdef __notyet__
    438 	tstl	_C_LABEL(ectype)
    439 	jeq	Lnocache0
    440 					| Enable external cache here
    441 #endif
    442 	jra	Lnocache0
    443 
    444 Ltbia040:
    445 	.word	0xf518			| pflusha
    446 
    447 Lnocache0:
    448 	movl	%d7,%sp@-		| push nextpa saved above
    449 	jbsr	_C_LABEL(machine_init)	| additional pre-main initialization
    450 	addql	#4,%sp
    451 	jra	_C_LABEL(main)		| main() (never returns)
    452 
    453 /*
    454  * Use common m68k bus error and address error handlers.
    455  */
    456 	.data
    457 GLOBAL(mac68k_a2_fromfault)
    458 	.long	0
    459 GLOBAL(m68k_fault_addr)
    460 	.long	0
    461 
    462 /*
    463  * Interrupt handlers.
    464  *
    465  * Most 68k-based Macintosh computers
    466  *
    467  *      Level 0:        Spurious: ignored
    468  *      Level 1:        VIA1 (clock, ADB)
    469  *      Level 2:        VIA2 (NuBus, SCSI)
    470  *      Level 3:
    471  *      Level 4:        Serial (SCC)
    472  *      Level 5:
    473  *      Level 6:
    474  *      Level 7:        Non-maskable: parity errors, RESET button
    475  *
    476  * On the Q700, Q900 and Q950 in "A/UX mode": this should become:
    477  *
    478  *	Level 0:        Spurious: ignored
    479  *	Level 1:        Software
    480  *	Level 2:        VIA2 (except ethernet, sound)
    481  *	Level 3:        Ethernet
    482  *	Level 4:        Serial (SCC)
    483  *	Level 5:        Sound
    484  *	Level 6:        VIA1
    485  *	Level 7:        NMIs: parity errors, RESET button, YANCC error
    486  *
    487  * On the 660AV and 840AV:
    488  *
    489  *	Level 0:        Spurious: ignored
    490  *	Level 1:        VIA1 (clock, ADB)
    491  *	Level 2:        VIA2 (NuBus, SCSI)
    492  *	Level 3:        PSC device interrupt
    493  *	Level 4:        PSC DMA and serial
    494  *	Level 5:        ???
    495  *	Level 6:        ???
    496  *	Level 7:        NMIs: parity errors?, RESET button
    497  */
    498 
    499 ENTRY_NOPROFILE(spurintr)
    500 	addql	#1,_C_LABEL(intrcnt)+0
    501 	INTERRUPT_SAVEREG
    502 	CPUINFO_INCREMENT(CI_NINTR)
    503 	INTERRUPT_RESTOREREG
    504 	jra	_ASM_LABEL(rei)
    505 
    506 ENTRY_NOPROFILE(intrhand)
    507 	INTERRUPT_SAVEREG
    508 	jbsr	_C_LABEL(intr_dispatch)	| call dispatch routine
    509 	INTERRUPT_RESTOREREG
    510 	jra	_ASM_LABEL(rei)		| all done
    511 
    512 ENTRY_NOPROFILE(lev7intr)
    513 	addql	#1,_C_LABEL(intrcnt)+16
    514 	clrl	%sp@-			| pad %SR to longword
    515 	moveml	#0xFFFF,%sp@-		| save registers
    516 	movl	%usp,%a0		| and save
    517 	movl	%a0,%sp@(FR_SP)		|   the user stack pointer
    518 	jbsr	_C_LABEL(nmihand)	| call handler
    519 	movl	%sp@(FR_SP),%a0		| restore
    520 	movl	%a0,%usp		|   %USP
    521 	moveml	%sp@+,#0x7FFF		| and remaining registers
    522 	addql	#8,%sp			| pop SSP and align word
    523 	jra	_ASM_LABEL(rei)
    524 
    525 /*
    526  * We could tweak rtclock_intr and gain 12 cycles on the 020 and 030 by
    527  * saving the status register directly to the stack, but this would lose
    528  * badly on the 040.  Aligning the stack takes 10 more cycles than this
    529  * code does, so it's a good compromise.
    530  *
    531  * A pointer to the clockframe is passed as an argument in the usual
    532  * fashion.
    533  */
    534 ENTRY_NOPROFILE(rtclock_intr)
    535 	movl	%sp@(4),%a1		| stash pointer to clockframe
    536 	movl	%d2,%sp@-		| save %d2
    537 	movw	%sr,%d2			| save SPL
    538 					| raise SPL to splclock()
    539 	movw	_C_LABEL(ipl2psl_table)+IPL_CLOCK*2,%sr
    540 	movl	%a1,%sp@-		| push pointer to clockframe
    541 	jbsr	_C_LABEL(hardclock)	| call generic clock int routine
    542 	addql	#4,%sp			| pop param
    543 	jbsr	_C_LABEL(mrg_VBLQueue)	| give programs in the VBLqueue a chance
    544 	addql	#1,_C_LABEL(intrcnt)+32	| record a clock interrupt
    545 	INTERRUPT_SAVEREG
    546 	CPUINFO_INCREMENT(CI_NINTR)
    547 	INTERRUPT_RESTOREREG
    548 	movw	%d2,%sr			| restore SPL
    549 	movl	%sp@+,%d2		| restore %d2
    550 	rts				| go back from whence we came
    551 
    552 /*
    553  * delay() - delay for a specified number of microseconds
    554  * _delay() - calibrator helper for delay()
    555  *
    556  * Notice that delay_factor is scaled up by a factor of 128 to avoid loss
    557  * of precision for small delays.  As a result of this we need to avoid
    558  * overflow.
    559  *
    560  * The branch target for the loops must be aligned on a half-line (8-byte)
    561  * boundary to minimize cache effects.  This guarantees both that there
    562  * will be no prefetch stalls due to cache line burst operations and that
    563  * the loops will run from a single cache half-line.
    564  */
    565 	.align	8			| align to half-line boundary
    566 					| (use nop instructions if necessary!)
    567 ALTENTRY(_delay, _delay)
    568 ENTRY(delay)
    569 	movl	%sp@(4),%d0		| get microseconds to delay
    570 	cmpl	#0x40000,%d0		| is it a "large" delay?
    571 	bls	.Ldelayshort		| no, normal calculation
    572 	movql	#0x7f,%d1		| adjust for scaled multiplier (to
    573 	addl	%d1,%d0			|   avoid overflow)
    574 	lsrl	#7,%d0
    575 	mulul	_C_LABEL(delay_factor),%d0 | calculate number of loop iterations
    576 	bra	.Ldelaysetup		| go do it!
    577 .Ldelayshort:
    578 	mulul	_C_LABEL(delay_factor),%d0 | calculate number of loop iterations
    579 	lsrl	#7,%d0			| adjust for scaled multiplier
    580 .Ldelaysetup:
    581 	jeq	.Ldelayexit		| bail out if nothing to do
    582 	movql	#0,%d1			| put bits 15-0 in %d1 for the
    583 	movw	%d0,%d1			|   inner loop, and move bits
    584 	movw	#0,%d0			|   31-16 to the low-order word
    585 	subql	#1,%d1			|   of %d0 for the outer loop
    586 	swap	%d0
    587 .Ldelay:
    588 	tstl	_C_LABEL(delay_flag)	| this never changes for delay()!
    589 	dbeq	%d1,.Ldelay		|   (used only for timing purposes)
    590 	dbeq	%d0,.Ldelay
    591 	addqw	#1,%d1			| adjust end count and
    592 	swap	%d0			|    return the longword result
    593 	orl	%d1,%d0
    594 .Ldelayexit:
    595 	rts
    596 
    597 /*
    598  * Handle the nitty-gritty of rebooting the machine.
    599  * Basically we just turn off the MMU and jump to the appropriate ROM routine.
    600  * Note that we must be running in an address range that is mapped one-to-one
    601  * logical to physical so that the PC is still valid immediately after the MMU
    602  * is turned off.  We have conveniently mapped the last page of physical
    603  * memory this way.
    604  */
    605 ENTRY_NOPROFILE(doboot)
    606 #if defined(M68040) || defined(M68060)
    607 	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040/060?
    608 	jeq	Lnocache5		| yes, skip
    609 #endif
    610 	movl	#CACHE_OFF,%d0
    611 	movc	%d0,%cacr		| disable on-chip cache(s)
    612 Lnocache5:
    613 	movl	_C_LABEL(last_page),%a0	| last page of physical memory
    614 	lea	Lbootcode,%a1		| start of boot code
    615 	lea	Lebootcode,%a3		| end of boot code
    616 Lbootcopy:
    617 	movw	%a1@+,%a0@+		| copy a word
    618 	cmpl	%a3,%a1			| done yet?
    619 	jcs	Lbootcopy		| no, keep going
    620 #if defined(M68040) || defined(M68060)
    621 	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040/060?
    622 	jne	LmotommuE		| no, skip
    623 	.word	0xf4f8			| cpusha bc
    624 LmotommuE:
    625 #endif
    626 	movl	_C_LABEL(last_page),%a0
    627 	jmp	%a0@			| jump to last page
    628 
    629 Lbootcode:
    630 	lea	%a0@(0x800),%sp		| physical %SP in case of NMI
    631 	movl	_C_LABEL(MacOSROMBase),%a1 | Load MacOS ROMBase
    632 
    633 #if defined(M68040) || defined(M68060)
    634 	cmpl	#MMU_68040,_C_LABEL(mmutype) | 68040/060?
    635 	jne	LmotommuF		| no, skip
    636 	movl	#0,%d0
    637 	movc	%d0,%cacr		| caches off
    638 	.long	0x4e7b0003		| movc %d0,%tc (disable MMU)
    639 	jra	Ldoboot1
    640 LmotommuF:
    641 #endif
    642 	lea	_ASM_LABEL(longscratch),%a3
    643 	movl	#0,%a3@			| value for pmove to %TC (turn off MMU)
    644 	pmove	%a3@,%tc		| disable MMU
    645 
    646 Ldoboot1:
    647 	lea	%a1@(0x90),%a1		| offset of ROM reset routine
    648 	jmp	%a1@			| and jump to ROM to reset machine
    649 Lebootcode:
    650 
    651 /*
    652  * u_long plpar060(void *addr, u_int fc);
    653  *
    654  * plpar060() uses the new plpar instruction to resolve a physical address to
    655  * the associated logical address when MMU is enabled. Used by get_physical().
    656  * zzj apr-9-2026
    657  */
    658 ENTRY_NOPROFILE(plpar060)
    659 #if defined(M68060)
    660 	.long	0x4e7a0003		| movc %tc,%d0
    661 	andw	#0x8000,%d0
    662 	jeq	2f			| MMU is disabled
    663 
    664 	movc	%dfc,%d1		| Save %dfc
    665 	movl	%sp@(8),%d0		| Set FC for plpar
    666 	movc	%d0,%dfc
    667 
    668 	movec	%vbr,%a1		| get vbr
    669 	addq.l	#8,%a1			| access error vector
    670 	lea	_ASM_LABEL(L060mmuerr),%a0 | temporary handler address
    671 	move.l	%a1@,%d0		| save old handler into %d0
    672 	move.l	%a0,%a1@		| install temp handler
    673 
    674 	movl	%sp@(4),%a0		| logical address to look up
    675 
    676 	.word	0xf5c8			| plpar %a0@
    677 	move.l	%d0,%a1@		| restore original handler
    678 
    679 	movl	%a0,%d0			| return address in %d0
    680 	movc	%d1,%dfc		| Restore %dfc
    681 	rts
    682 
    683 L060mmuerr:	 | plpa will throw an access error (vect $8) on failure
    684 	movl	#-1, %a0		| return failure
    685 	addq.l	#2,2(%sp)		| advance %pc past plpar insn
    686 	rte
    687 2:
    688 #endif
    689 	movl	#-1,%d0			| return failure
    690 	rts
    691 
    692 /*
    693  * u_long ptest040(void *addr, u_int fc);
    694  *
    695  * ptest040() does an 040 PTESTR (addr) and returns the 040 MMUSR iff
    696  * translation is enabled.  This allows us to find the physical address
    697  * corresponding to a MacOS logical address for get_physical().
    698  * sar  01-oct-1996
    699  */
    700 ENTRY_NOPROFILE(ptest040)
    701 #if defined(M68040)
    702 	.long	0x4e7a0003		| movc %tc,%d0
    703 	andw	#0x8000,%d0
    704 	jeq	Lget_phys1		| MMU is disabled
    705 	movc	%dfc,%d1		| Save %DFC
    706 	movl	%sp@(8),%d0		| Set FC for ptestr
    707 	movc	%d0,%dfc
    708 	movl	%sp@(4),%a0		| logical address to look up
    709 	.word	0xf568			| ptestr (%a0)
    710 	.long	0x4e7a0805		| movc %mmusr,%d0
    711 	movc	%d1,%dfc		| Restore %DFC
    712 	rts
    713 Lget_phys1:
    714 #endif
    715 	movql	#0,%d0			| return failure
    716 	rts
    717 
    718 /*
    719  * LAK: (7/24/94) This routine was added so that the
    720  *  C routine that runs at startup can figure out how MacOS
    721  *  had mapped memory.  We want to keep the same mapping so
    722  *  that when we set our MMU pointer, the PC doesn't point
    723  *  in the middle of nowhere.
    724  *
    725  * long get_pte(void *addr, unsigned long pte[2], unsigned short *psr)
    726  *
    727  *  Takes "addr" and looks it up in the current MMU pages.  Puts
    728  *  the PTE of that address in "pte" and the result of the
    729  *  search in "psr".  "pte" should be 2 longs in case it is
    730  *  a long-format entry.
    731  *
    732  *  One possible problem here is that setting the TT register
    733  *  may screw something up if we access user data space in a
    734  *  called function or in an interrupt service routine.
    735  *
    736  *  Returns -1 on error, 0 if pte is a short-format pte, or
    737  *  1 if pte is a long-format pte.
    738  *
    739  *  Be sure to only call this routine if the MMU is enabled.  This
    740  *  routine is probably more general than it needs to be -- it
    741  *  could simply return the physical address (replacing
    742  *  get_physical() in machdep).
    743  *
    744  *  "gas" does not understand the %tt0 register, so we must hand-
    745  *  assemble the instructions.
    746  */
    747 ENTRY_NOPROFILE(get_pte)
    748 	subql	#4,%sp		| make temporary space
    749 
    750 	lea	_ASM_LABEL(longscratch),%a0
    751 	movl	#MAC68K_TT_GET_PTE,%a0@ | See pmap.h
    752 	.long	0xf0100800	| pmove %a0@,%tt0
    753 
    754 	movl	%sp@(8),%a0	| logical address to look up
    755 	movl	#0,%a1		| clear in case of failure
    756 	ptestr	#FC_USERD,%a0@,#7,%a1 | search for logical address
    757 	pmove	%psr,%sp@	| store processor status register
    758 	movw	%sp@,%d1
    759 	movl	%sp@(16),%a0	| where to store the %psr
    760 	movw	%d1,%a0@	| send back to caller
    761 	andw	#0xc400,%d1	| if bus error, exceeded limit, or invalid
    762 	jne	get_pte_fail1	| leave now
    763 	tstl	%a1		| check address we got back
    764 	jeq	get_pte_fail2	| if 0, then was not set -- fail
    765 
    766 	movl	%a1,%d0
    767 	movl	%d0,_ASM_LABEL(pte_tmp)	| save for later
    768 
    769 	| send first long back to user
    770 	movl	%sp@(12),%a0	| address of where to put pte
    771 	movsl	%a1@,%d0	|
    772 	movl	%d0,%a0@	| first long
    773 
    774 	andl	#3,%d0		| dt bits of pte
    775 	cmpl	#1,%d0		| should be 1 if page descriptor
    776 	jne	get_pte_fail3	| if not, get out now
    777 
    778 	movl	%sp@(16),%a0	| addr of stored %psr
    779 	movw	%a0@,%d0	| get %psr again
    780 	andw	#7,%d0		| number of levels it found
    781 	addw	#-1,%d0		| find previous level
    782 	movl	%sp@(8),%a0	| logical address to look up
    783 	movl	#0,%a1		| clear in case of failure
    784 
    785 	cmpl	#0,%d0
    786 	jeq	pte_level_zero
    787 	cmpl	#1,%d0
    788 	jeq	pte_level_one
    789 	cmpl	#2,%d0
    790 	jeq	pte_level_two
    791 	cmpl	#3,%d0
    792 	jeq	pte_level_three
    793 	cmpl	#4,%d0
    794 	jeq	pte_level_four
    795 	cmpl	#5,%d0
    796 	jeq	pte_level_five
    797 	cmpl	#6,%d0
    798 	jeq	pte_level_six
    799 	jra	get_pte_fail4	| really should have been one of these...
    800 
    801 pte_level_zero:
    802 	| must get CRP to get length of entries at first level
    803 	lea	_ASM_LABEL(longscratch),%a0 | space for two longs
    804 	pmove	%crp,%a0@	| save root pointer
    805 	movl	%a0@,%d0	| load high long
    806 	jra	pte_got_parent
    807 pte_level_one:
    808 	ptestr	#FC_USERD,%a0@,#1,%a1 | search for logical address
    809 	pmove	%psr,%sp@	| store processor status register
    810 	movw	%sp@,%d1
    811 	jra	pte_got_it
    812 pte_level_two:
    813 	ptestr	#FC_USERD,%a0@,#2,%a1 | search for logical address
    814 	pmove	%psr,%sp@	| store processor status register
    815 	movw	%sp@,%d1
    816 	jra	pte_got_it
    817 pte_level_three:
    818 	ptestr	#FC_USERD,%a0@,#3,%a1 | search for logical address
    819 	pmove	%psr,%sp@	| store processor status register
    820 	movw	%sp@,%d1
    821 	jra	pte_got_it
    822 pte_level_four:
    823 	ptestr	#FC_USERD,%a0@,#4,%a1 | search for logical address
    824 	pmove	%psr,%sp@	| store processor status register
    825 	movw	%sp@,%d1
    826 	jra	pte_got_it
    827 pte_level_five:
    828 	ptestr	#FC_USERD,%a0@,#5,%a1 | search for logical address
    829 	pmove	%psr,%sp@	| store processor status register
    830 	movw	%sp@,%d1
    831 	jra	pte_got_it
    832 pte_level_six:
    833 	ptestr	#FC_USERD,%a0@,#6,%a1 | search for logical address
    834 	pmove	%psr,%sp@	| store processor status register
    835 	movw	%sp@,%d1
    836 
    837 pte_got_it:
    838 	andw	#0xc400,%d1	| if bus error, exceeded limit, or invalid
    839 	jne	get_pte_fail5	| leave now
    840 	tstl	%a1		| check address we got back
    841 	jeq	get_pte_fail6	| if 0, then was not set -- fail
    842 
    843 	movsl	%a1@,%d0		| get pte of parent
    844 	movl	%d0,_C_LABEL(macos_tt0)	| XXX for later analysis (kill me)
    845 pte_got_parent:
    846 	andl	#3,%d0		| dt bits of pte
    847 	cmpl	#2,%d0		| child is short-format descriptor
    848 	jeq	short_format
    849 	cmpl	#3,%d0		| child is long-format descriptor
    850 	jne	get_pte_fail7
    851 
    852 	| long_format -- we must go back, change the tt, and get the
    853 	|  second long.  The reason we didn't do this in the first place
    854 	|  is that the first long might have been the last long of RAM.
    855 
    856 	movl	_ASM_LABEL(pte_tmp),%a1	| get address of our original pte
    857 	addql	#4,%a1		| address of ite second long
    858 
    859 	| send second long back to user
    860 	movl	%sp@(12),%a0	| address of where to put pte
    861 	movsl	%a1@,%d0	|
    862 	movl	%d0,%a0@(4)	| write in second long
    863 
    864 	movql	#1,%d0		| return long-format
    865 	jra	get_pte_success
    866 
    867 short_format:
    868 	movql	#0,%d0		| return short-format
    869 	jra	get_pte_success
    870 
    871 get_pte_fail:
    872 	movql	#-1,%d0		| return failure
    873 
    874 get_pte_success:
    875 	lea	_ASM_LABEL(longscratch),%a0 | disable tt
    876 	movl	#0,%a0@
    877 	.long	0xf0100800	| pmove %a0@,%tt0
    878 
    879 	addql	#4,%sp		| return temporary space
    880 	rts
    881 
    882 get_pte_fail1:
    883 	jbsr	_C_LABEL(printstar)
    884 	jra	get_pte_fail
    885 get_pte_fail2:
    886 	jbsr	_C_LABEL(printstar)
    887 	jbsr	_C_LABEL(printstar)
    888 	jra	get_pte_fail
    889 get_pte_fail3:
    890 	jbsr	_C_LABEL(printstar)
    891 	jbsr	_C_LABEL(printstar)
    892 	jbsr	_C_LABEL(printstar)
    893 	jra	get_pte_fail
    894 get_pte_fail4:
    895 	jbsr	_C_LABEL(printstar)
    896 	jbsr	_C_LABEL(printstar)
    897 	jbsr	_C_LABEL(printstar)
    898 	jbsr	_C_LABEL(printstar)
    899 	jra	get_pte_fail
    900 get_pte_fail5:
    901 	jbsr	_C_LABEL(printstar)
    902 	jbsr	_C_LABEL(printstar)
    903 	jbsr	_C_LABEL(printstar)
    904 	jbsr	_C_LABEL(printstar)
    905 	jbsr	_C_LABEL(printstar)
    906 	jra	get_pte_fail
    907 get_pte_fail6:
    908 	jbsr	_C_LABEL(printstar)
    909 	jbsr	_C_LABEL(printstar)
    910 	jbsr	_C_LABEL(printstar)
    911 	jbsr	_C_LABEL(printstar)
    912 	jbsr	_C_LABEL(printstar)
    913 	jbsr	_C_LABEL(printstar)
    914 	jra	get_pte_fail
    915 get_pte_fail7:
    916 	jbsr	_C_LABEL(printstar)
    917 	jbsr	_C_LABEL(printstar)
    918 	jbsr	_C_LABEL(printstar)
    919 	jbsr	_C_LABEL(printstar)
    920 	jbsr	_C_LABEL(printstar)
    921 	jbsr	_C_LABEL(printstar)
    922 	jbsr	_C_LABEL(printstar)
    923 	jra	get_pte_fail
    924 get_pte_fail8:
    925 	jbsr	_C_LABEL(printstar)
    926 	jbsr	_C_LABEL(printstar)
    927 	jbsr	_C_LABEL(printstar)
    928 	jbsr	_C_LABEL(printstar)
    929 	jbsr	_C_LABEL(printstar)
    930 	jbsr	_C_LABEL(printstar)
    931 	jbsr	_C_LABEL(printstar)
    932 	jbsr	_C_LABEL(printstar)
    933 	jra	get_pte_fail
    934 get_pte_fail9:
    935 	jbsr	_C_LABEL(printstar)
    936 	jbsr	_C_LABEL(printstar)
    937 	jbsr	_C_LABEL(printstar)
    938 	jbsr	_C_LABEL(printstar)
    939 	jbsr	_C_LABEL(printstar)
    940 	jbsr	_C_LABEL(printstar)
    941 	jbsr	_C_LABEL(printstar)
    942 	jbsr	_C_LABEL(printstar)
    943 	jbsr	_C_LABEL(printstar)
    944 	jra	get_pte_fail
    945 get_pte_fail10:
    946 	jbsr	_C_LABEL(printstar)
    947 	jbsr	_C_LABEL(printstar)
    948 	jbsr	_C_LABEL(printstar)
    949 	jbsr	_C_LABEL(printstar)
    950 	jbsr	_C_LABEL(printstar)
    951 	jbsr	_C_LABEL(printstar)
    952 	jbsr	_C_LABEL(printstar)
    953 	jbsr	_C_LABEL(printstar)
    954 	jbsr	_C_LABEL(printstar)
    955 	jbsr	_C_LABEL(printstar)
    956 	jra	get_pte_fail
    957 
    958 /*
    959  * Misc. global variables.
    960  */
    961 	.data
    962 GLOBAL(sanity_check)
    963 	.long	0x18621862	| this is our stack overflow checker.
    964 
    965 	.space	4 * PAGE_SIZE
    966 	.align	4
    967 ASGLOBAL(tmpstk)
    968 
    969 GLOBAL(machineid)
    970 	.long	0		| default to 320
    971 
    972 GLOBAL(mmutype)
    973 	.long	MMU_68851	| default to 68851 PMMU
    974 
    975 GLOBAL(cputype)
    976 	.long	CPU_68020	| default to 68020 CPU
    977 
    978 #ifdef __notyet__
    979 GLOBAL(ectype)
    980 	.long	EC_NONE		| external cache type, default to none
    981 #endif
    982 
    983 GLOBAL(intiolimit)
    984 	.long	0		| KVA of end of internal IO space
    985 
    986 GLOBAL(load_addr)
    987 	.long	0		| Physical address of kernel
    988 
    989 ASLOCAL(lastpage)
    990 	.long	0		| LAK: to store the addr of last page in mem
    991 
    992 GLOBAL(MacOSROMBase)
    993 	.long	0x40800000
    994 GLOBAL(mac68k_vrsrc_cnt)
    995 	.long	0
    996 GLOBAL(mac68k_vrsrc_vec)
    997 	.word	0, 0, 0, 0, 0, 0
    998 
    999 #ifdef DEBUG
   1000 ASGLOBAL(fulltflush)
   1001 	.long	0
   1002 
   1003 ASGLOBAL(fullcflush)
   1004 	.long	0
   1005 #endif
   1006 
   1007 /* interrupt counters -- leave some space for overriding the names */
   1008 
   1009 GLOBAL(intrnames)
   1010 	.asciz	"spur    "
   1011 	.asciz	"via1    "
   1012 	.asciz	"via2    "
   1013 	.asciz	"unused1 "
   1014 	.asciz	"scc     "
   1015 	.asciz	"unused2 "
   1016 	.asciz	"unused3 "
   1017 	.asciz	"nmi     "
   1018 	.asciz	"clock   "
   1019 GLOBAL(eintrnames)
   1020 	.even
   1021 
   1022 GLOBAL(intrcnt)
   1023 	.long	0,0,0,0,0,0,0,0,0
   1024 GLOBAL(eintrcnt)
   1025