root/sys/arch/next68k/next68k/locore.s
/*      $NetBSD: locore.s,v 1.114 2026/04/28 03:29:10 thorpej Exp $     */

/*
 * Copyright (c) 1998 Darrin B. Jewell
 * Copyright (c) 1980, 1990, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah $Hdr: locore.s 1.66 92/12/22$
 *
 *      @(#)locore.s    8.6 (Berkeley) 5/27/94
 */

/*
 * Copyright (c) 1994, 1995 Gordon W. Ross
 * Copyright (c) 1988 University of Utah.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah $Hdr: locore.s 1.66 92/12/22$
 *
 *      @(#)locore.s    8.6 (Berkeley) 5/27/94
 */

/* This is currently amid development by
 * Darrin Jewell <jewell@mit.edu>  Fri Jan  2 14:36:47 1998
 * for the next68k port
 */

#include "opt_compat_netbsd.h"
#include "opt_compat_sunos.h"
#include "opt_ddb.h"
#include "opt_fpsp.h"
#include "opt_kgdb.h"
#include "opt_lockdebug.h"
#include "opt_fpu_emulate.h"
#include "opt_useleds.h"
#include "opt_m68k_arch.h"

#include "assym.h"
#include <machine/asm.h>
#include <machine/trap.h>

#if (!defined(M68040))
#error "M68040 is not defined! (check that the generated assym.h is not empty)"
#endif

#include "ksyms.h"

/*
 * This is for kvm_mkdb, and should be the address of the beginning
 * of the kernel text segment (not necessarily the same as kernbase).
 */
        .text
GLOBAL(kernel_text)

 /*
  * Leave page zero empty so it can be unmapped
  */
        .space  PAGE_SIZE

/*
 * Temporary stack for a variety of purposes.
 */
        .data
GLOBAL(endstack)
        .space  PAGE_SIZE
GLOBAL(bgnstack)
ASGLOBAL(tmpstk)

/*
 * Macro to relocate a symbol, used before MMU is enabled.
 * On the NeXT, memory is laid out as in the mach header
 * so therefore we need to relocate symbols until the MMU
 * is turned on.
 */
#define _RELOC(var, ar)         \
        lea     var,ar;         \
        addl    %a5,ar

#define RELOC(var, ar)          _RELOC(_C_LABEL(var), ar)
#define ASRELOC(var, ar)        _RELOC(_ASM_LABEL(var), ar)

/*
 * Initialization info as per grossman's boot loader:
 *
 * We are called from the boot prom, not the boot loader. We have the
 * prom's stack initialized for us and we were called like this:
 * start(mg, mg->mg_console_i, mg->mg_console_o,
 *       mg->mg_boot_dev, mg->mg_boot_arg, mg->mg_boot_info,
 *       mg->mg_sid, mg->mg_pagesize, 4, mg->mg_region,
 *       etheraddr, mg->mg_boot_file);
 * so we actually only really need the first parameter from the stack.
 * Exceptions will be handled by the prom until we feel ready to handle
 * them ourselves.
 * By the way, we get loaded at our final address i.e. PA==VA for the kernel.
 */
 /* I think the PA==VA comment to be a lie, but I have yet to verify it.
  * Darrin B Jewell <jewell@mit.edu>  Sun Jan 11 01:05:54 1998
 */
BSS(lowram,4)
BSS(esym,4)

ASENTRY_NOPROFILE(start)
        movw    #PSL_HIGHIPL,%sr        | no interrupts
        movl    #CACHE_OFF,%d0
        movc    %d0,%cacr               | clear and disable on-chip cache(s)

        moveal  #NEXT_RAMBASE,%a5       | amount to RELOC by.
        RELOC(lowram,%a0)               | store base of memory.
        movl    %a5,%a0@

        | Create a new stack at address tmpstk, and push
        | The existing sp onto it as an arg for next68k_bootargs.
        ASRELOC(tmpstk, %a0)
        movel   %sp,%a0@-
        moveal  %a0,%sp
        moveal  #0,%a6

        /* Read the header to get our segment list */
        RELOC(next68k_bootargs,%a0)
        jbsr    %a0@                    | next68k_bootargs(args)
        addqw   #4,%sp                  | clear arg from stack.

        /*
         * All data registers are now free.  All address registers
         * except %a5 are free.  %a5 is used by the RELOC() macro on hp300
         * and cannot be used until after the MMU is enabled.
         */

/* determine our CPU/MMU combo - check for all regardless of kernel config */
        movl    #0x200,%d0              | data freeze bit
        movc    %d0,%cacr               |   only exists on 68030
        movc    %cacr,%d0               | read it back
        tstl    %d0                     | zero?
        jeq     Lnot68030               | yes, we have 68020/68040

        /*
         * 68030 models
         */

        RELOC(mmutype, %a0)             | no, we have 68030
        movl    #MMU_68030,%a0@         | set to reflect 68030 PMMU
        RELOC(cputype, %a0)
        movl    #CPU_68030,%a0@         | and 68030 CPU
        RELOC(machineid, %a0)
        movl    #30,%a0@                | @@@ useless
        jra     Lstart1

        /*
         * End of 68030 section
         */

Lnot68030:
        bset    #31,%d0                 | data cache enable bit
        movc    %d0,%cacr               |   only exists on 68040
        movc    %cacr,%d0               | read it back
        tstl    %d0                     | zero?
        beq     Lis68020                | yes, we have 68020
        moveq   #0,%d0                  | now turn it back off
        movec   %d0,%cacr               |   before we access any data

        /*
         * 68040 models
         */

        RELOC(mmutype, %a0)
        movl    #MMU_68040,%a0@         | with a 68040 MMU
        RELOC(cputype, %a0)
        movl    #CPU_68040,%a0@         | and a 68040 CPU
        RELOC(fputype, %a0)
        movl    #FPU_68040,%a0@         | ...and FPU
        RELOC(machineid, %a0)
        movl    #40,%a0@                | @@@ useless
        jra     Lstart1

        /*
         * End of 68040 section
         */

        /*
         * 68020 models
         * (There are no 68020 models of NeXT, but we'll pretend)
         */

Lis68020:
        RELOC(mmutype, %a0)
        movl    #MMU_68851,%a0@         | no, we have PMMU
        RELOC(fputype, %a0)             | all of the 68020 systems
        movl    #FPU_68881,%a0@         |   have a 68881 FPU
        RELOC(cputype, %a0)
        movl    #CPU_68020,%a0@         | and a 68020 CPU
        RELOC(machineid, %a0)
        movl    #20,%a0@                        | @@@ useless
        jra     Lstart1

        /*
         * End of 68020 section
         */

Lstart1:
/* configure kernel and lwp0 VA space so we can get going */
#if NKSYMS || defined(DDB) || defined(MODULAR)
        RELOC(esym,%a0)                 | end of static kernel test/data/syms
        movl    %a0@,%a4
        tstl    %a4
        jne     Lstart3
#endif
        movl    #_C_LABEL(end),%a4      | end of static kernel text/data

Lstart3:
        addl    %a5,%a4                 | convert to PA
        pea     %a5@                    | reloff
        pea     %a4@                    | nextpa
        RELOC(pmap_bootstrap1,%a0)
        jbsr    %a0@                    | pmap_bootstrap1(nextpa, reloff)
        addql   #8,%sp

        /*
         * Updated nextpa returned in %d0.  We need to squirrel
         * that away in a callee-saved register to use later,
         * after the MMU is enabled.
         */
        movl    %d0, %d7

        /* NOTE: %d7 is now off-limits!! */

/*
 * Prepare to enable MMU.
 * Since the kernel is not mapped logical == physical we must insure
 * that when the MMU is turned on, all prefetched addresses (including
 * the PC) are valid.  In order guarantee that, we use the transparent
 * translation registers (which provide PA == VA mappings) and just
 * turns on the MMU, then jump from the VA == PA address (at 0x40XXXXXX)
 * to the actual kernel virtual address (at 0x00XXXXXX) code via a far
 * jump instruction so that we can defeat the prefetch.
 *
 * The TT register values are pre-initialized in the mmu_tt{30,40}[]
 * arrays (see genassym.cf) and loaded from there before the MMU is
 * turned on.
 */
#include <m68k/m68k/mmu_enable.s>

/*
 * Should be running mapped from this point on
 */
Lmmuenabled:
/*
 * Now that the MMU is enabled, we need to clear out the TT value
 * arrays (so no other code gets confused and thinks we're using them)
 * and disable the TT registers.
 */
        lea     _ASM_LABEL(tmpstk),%sp  | re-load temporary stack
        moveq   #0,%d0
#ifdef M68030
        lea     _C_LABEL(mmu_tt30),%a0  | zap the 2 '030 TT slots
        movl    %d0,%a0@+
        movl    %d0,%a0@+
#endif
#ifdef M68040
        lea     _C_LABEL(mmu_tt40),%a0  | zap the 4 '040 TT slots
        movl    %d0,%a0@+
        movl    %d0,%a0@+
        movl    %d0,%a0@+
        movl    %d0,%a0@+
        cmpl    #MMU_68040,_C_LABEL(mmutype)
        jne     1f
        /* disable '040 TTs */
        pea     _C_LABEL(mmu_tt40)
        jbsr    _C_LABEL(mmu_load_tt40)
        jra     2f
1:
#endif
#ifdef M68030
        /* disable '030 TTs */
        pea     _C_LABEL(mmu_tt30)
        jbsr    _C_LABEL(mmu_load_tt30)
#endif
2:
        lea     _ASM_LABEL(tmpstk),%sp  | re-load temporary stack
        jbsr    _C_LABEL(vec_init)      | initialize vector table

        /* phase 2 of pmap setup, returns lwp0 SP in %a0 */
        jbsr    _C_LABEL(pmap_bootstrap2)
        movl    %a0,%sp                 | now running on lwp0's stack
        movl    #0,%a6                  | terminate the stack back trace

        movl    %d7,%sp@-               | push nextpa saved above
        jbsr    _C_LABEL(machine_init)  | additional pre-main initialization
        addql   #4,%sp
        jra     _C_LABEL(main)          | main() (never returns)

/*
 * Interrupt handlers.
 *
 * For auto-vectored interrupts, the CPU provides the
 * vector 0x18+level.  Note we count spurious interrupts,
 * but don't do anything else with them.
 *
 * intrhand_autovec is the entry point for auto-vectored
 * interrupts.
 *
 * For vectored interrupts, we pull the pc, evec, and exception frame
 * and pass them to the vectored interrupt dispatcher.  The vectored
 * interrupt dispatcher will deal with strays.
 */

ENTRY_NOPROFILE(lev7intr)       /* level 7: parity errors, reset key */
        addql   #1,_C_LABEL(m68k_intr_evcnt)+NMI_INTRCNT
        clrl    %sp@-
        moveml  #0xFFFF,%sp@-           | save registers
        movl    %usp,%a0                | and save
        movl    %a0,%sp@(FR_SP)         |   the user stack pointer
        jbsr    _C_LABEL(nmihand)       | call handler
        movl    %sp@(FR_SP),%a0         | restore
        movl    %a0,%usp                        |   user SP
        moveml  %sp@+,#0x7FFF           | and remaining registers
        addql   #8,%sp                  | pop SP and stack adjust
        jra     _ASM_LABEL(rei)         | all done

/*
 * Handle the nitty-gritty of rebooting the machine.
 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
 * Note that we must be running in an address range that is mapped one-to-one
 * logical to physical so that the PC is still valid immediately after the MMU
 * is turned off.  We have conveniently mapped the last page of physical
 * memory this way.
 */
ENTRY_NOPROFILE(machine_reboot)
        movw    #PSL_HIGHIPL,%sr        | no interrupts

        movl    #CACHE_OFF,%d0
        movc    %d0,%cacr               | clear and disable on-chip cache(s)

        | Turn on physical memory mapping.
        | @@@ This is also 68040 specific and needs fixing.
        movel   #0x0200c040,%d0         | intio devices are at 0x02000000
        .long   0x4e7b0004              | movc %d0,%itt0
        .long   0x4e7b0006              | movc %d0,%dtt0
        movel   #0x0403c000,%d0         | kernel text and data at 0x04000000
        .long   0x4e7b0005              | movc %d0,%itt1
        .long   0x4e7b0007              | movc %d0,%dtt1

        moveal   #NEXT_RAMBASE,%a5      | amount to RELOC by.

        | Create a new stack at address tmpstk, and push
        | The existing sp onto it for kicks.
        ASRELOC(tmpstk, %a0)
        movel   %sp,%a0@-
        moveal  %a0,%sp
        moveal  #0,%a6

        ASRELOC(Ldoboot1, %a0)
        jmp     %a0@                    | jump into physical address space.
Ldoboot1:
        RELOC(saved_vbr, %a0)
        movl    %a0@,%d0
        movc    %d0,%vbr

        | reset the registers as the boot rom likes them:
        movel   #0x0200c040,%d0         |
        .long   0x4e7b0004              | movc %d0,%itt0
        .long   0x4e7b0006              | movc %d0,%dtt0
        movel   #0x00ffc000,%d0         |
        .long   0x4e7b0005              | movc %d0,%itt1
        .long   0x4e7b0007              | movc %d0,%dtt1

        RELOC(monbootflag, %a0)
        movl    %a0,%d0
        trap    #13
1:
        bra     1b                      | This shouldn't be reached.

/*
 * Misc. global variables.
 */
        .data
GLOBAL(machineid)
        .long   0xdeadbeef      | default to @@@

GLOBAL(mmuid)
        .long   0               | default to nothing

GLOBAL(mmutype)
        .long   0xdeadbeef      | default to 68040 mmu

GLOBAL(cputype)
        .long   0xdeadbeef      | default to 68020 CPU

GLOBAL(prototc)
        .long   0               | prototype translation control

GLOBAL(intiobase)
        .long   0               | KVA of base of internal IO space

GLOBAL(fbbase)
        .long   0               | KVA of base of framebuffer

GLOBAL(fbmapsize)
        .long   0               | size of framebuffer (page-rounded)

GLOBAL(fbbasepa)
        .long   MONOBASE        | PA of base of framebuffer

GLOBAL(monbootflag)
        .long   0

#ifdef DEBUG
ASGLOBAL(fulltflush)
        .long   0

ASGLOBAL(fullcflush)
        .long   0
#endif