Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * head.S: The initial boot code for the Sparc port of Linux.
0004  *
0005  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
0006  * Copyright (C) 1995,1999 Pete Zaitcev   (zaitcev@yahoo.com)
0007  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
0008  * Copyright (C) 1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
0009  * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
0010  *
0011  * CompactPCI platform by Eric Brower, 1999.
0012  */
0013 
0014 #include <linux/version.h>
0015 #include <linux/init.h>
0016 
0017 #include <asm/head.h>
0018 #include <asm/asi.h>
0019 #include <asm/contregs.h>
0020 #include <asm/ptrace.h>
0021 #include <asm/psr.h>
0022 #include <asm/page.h>
0023 #include <asm/kdebug.h>
0024 #include <asm/winmacro.h>
0025 #include <asm/thread_info.h>    /* TI_UWINMASK */
0026 #include <asm/errno.h>
0027 #include <asm/pgtable.h>    /* PGDIR_SHIFT */
0028 #include <asm/export.h>
0029 
0030     .data
0031 /* The following are used with the prom_vector node-ops to figure out
0032  * the cpu-type
0033  */
0034     .align 4
0035     .globl cputypval
0036 cputypval:
0037     .asciz "sun4m"
0038     .ascii "     "
0039 
0040 /* Tested on SS-5, SS-10 */
0041     .align 4
0042 cputypvar:
0043     .asciz "compatible"
0044 
0045     .align 4
0046 
0047 notsup:
0048     .asciz  "Sparc-Linux sun4/sun4c or MMU-less not supported\n\n"
0049     .align 4
0050 
0051 sun4e_notsup:
0052         .asciz  "Sparc-Linux sun4e support does not exist\n\n"
0053     .align 4
0054 
0055 /* The trap-table - located in the __HEAD section */
0056 #include "ttable_32.S"
0057 
0058     .align PAGE_SIZE
0059 
0060 /* This was the only reasonable way I could think of to properly align
0061  * these page-table data structures.
0062  */
0063     .globl empty_zero_page
0064 empty_zero_page:    .skip PAGE_SIZE
0065 EXPORT_SYMBOL(empty_zero_page)
0066 
0067     .global root_flags
0068     .global ram_flags
0069     .global root_dev
0070     .global sparc_ramdisk_image
0071     .global sparc_ramdisk_size
0072 
0073 /* This stuff has to be in sync with SILO and other potential boot loaders
0074  * Fields should be kept upward compatible and whenever any change is made,
0075  * HdrS version should be incremented.
0076  */
0077     .ascii  "HdrS"
0078     .word   LINUX_VERSION_CODE
0079     .half   0x0203      /* HdrS version */
0080 root_flags:
0081     .half   1
0082 root_dev:
0083     .half   0
0084 ram_flags:
0085     .half   0
0086 sparc_ramdisk_image:
0087     .word   0
0088 sparc_ramdisk_size:
0089     .word   0
0090     .word   reboot_command
0091     .word   0, 0, 0
0092     .word   _end
0093 
0094 /* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
0095  * %g7 and at prom_vector_p. And also quickly check whether we are on
0096  * a v0, v2, or v3 prom.
0097  */
0098 gokernel:
0099         /* Ok, it's nice to know, as early as possible, if we
0100          * are already mapped where we expect to be in virtual
0101          * memory.  The Solaris /boot elf format bootloader
0102          * will peek into our elf header and load us where
0103          * we want to be, otherwise we have to re-map.
0104          *
0105          * Some boot loaders don't place the jmp'rs address
0106          * in %o7, so we do a pc-relative call to a local
0107          * label, then see what %o7 has.
0108          */
0109 
0110         mov %o7, %g4        ! Save %o7
0111 
0112         /* Jump to it, and pray... */
0113 current_pc:
0114         call    1f
0115          nop
0116 
0117 1:
0118         mov %o7, %g3
0119 
0120         tst %o0
0121         be  no_sun4u_here
0122          mov    %g4, %o7        /* Previous %o7. */
0123 
0124         mov %o0, %l0        ! stash away romvec
0125         mov %o0, %g7        ! put it here too
0126         mov %o1, %l1        ! stash away debug_vec too
0127 
0128         /* Ok, let's check out our run time program counter. */
0129         set current_pc, %g5
0130         cmp %g3, %g5
0131         be  already_mapped
0132          nop
0133 
0134         /* %l6 will hold the offset we have to subtract
0135          * from absolute symbols in order to access areas
0136          * in our own image.  If already mapped this is
0137          * just plain zero, else it is KERNBASE.
0138          */
0139         set KERNBASE, %l6
0140         b   copy_prom_lvl14
0141          nop
0142 
0143 already_mapped:
0144         mov 0, %l6
0145 
0146         /* Copy over the Prom's level 14 clock handler. */
0147 copy_prom_lvl14:
0148 #if 1
0149         /* DJHR
0150          * preserve our linked/calculated instructions
0151          */
0152         set lvl14_save, %g1
0153         set t_irq14, %g3
0154         sub %g1, %l6, %g1       ! translate to physical
0155         sub %g3, %l6, %g3       ! translate to physical
0156         ldd [%g3], %g4
0157         std %g4, [%g1]
0158         ldd [%g3+8], %g4
0159         std %g4, [%g1+8]
0160 #endif
0161         rd  %tbr, %g1
0162         andn    %g1, 0xfff, %g1     ! proms trap table base
0163         or  %g0, (0x1e<<4), %g2 ! offset to lvl14 intr
0164         or  %g1, %g2, %g2
0165         set t_irq14, %g3
0166         sub %g3, %l6, %g3
0167         ldd [%g2], %g4
0168         std %g4, [%g3]
0169         ldd [%g2 + 0x8], %g4
0170         std %g4, [%g3 + 0x8]    ! Copy proms handler
0171 
0172 /* DON'T TOUCH %l0 thru %l5 in these remapping routines,
0173  * we need their values afterwards!
0174  */
0175 
0176         /* Now check whether we are already mapped, if we
0177          * are we can skip all this garbage coming up.
0178          */
0179 copy_prom_done:
0180         cmp %l6, 0
0181         be  go_to_highmem       ! this will be a nop then
0182          nop
0183 
0184         /* Validate that we are in fact running on an
0185          * SRMMU based cpu.
0186          */
0187         set 0x4000, %g6
0188         cmp %g7, %g6
0189         bne not_a_sun4
0190          nop
0191 
0192 halt_notsup:
0193         ld  [%g7 + 0x68], %o1
0194         set notsup, %o0
0195         sub %o0, %l6, %o0
0196         call    %o1
0197          nop
0198         ba  halt_me
0199          nop
0200 
0201 not_a_sun4:
0202         /* It looks like this is a machine we support.
0203          * Now find out what MMU we are dealing with
0204          * LEON - identified by the psr.impl field
0205          * Viking - identified by the psr.impl field
0206          * In all other cases a sun4m srmmu.
0207          * We check that the MMU is enabled in all cases.
0208          */
0209 
0210         /* Check if this is a LEON CPU */
0211         rd  %psr, %g3
0212         srl %g3, PSR_IMPL_SHIFT, %g3
0213         and %g3, PSR_IMPL_SHIFTED_MASK, %g3
0214         cmp %g3, PSR_IMPL_LEON
0215         be  leon_remap      /* It is a LEON - jump */
0216          nop
0217 
0218         /* Sanity-check, is MMU enabled */
0219         lda [%g0] ASI_M_MMUREGS, %g1
0220         andcc   %g1, 1, %g0
0221         be  halt_notsup
0222          nop
0223 
0224         /* Check for a viking (TI) module. */
0225         cmp %g3, PSR_IMPL_TI
0226         bne srmmu_not_viking
0227          nop
0228 
0229         /* Figure out what kind of viking we are on.
0230          * We need to know if we have to play with the
0231          * AC bit and disable traps or not.
0232          */
0233 
0234         /* I've only seen MicroSparc's on SparcClassics with this
0235          * bit set.
0236          */
0237         set 0x800, %g2
0238         lda [%g0] ASI_M_MMUREGS, %g3    ! peek in the control reg
0239         and %g2, %g3, %g3
0240         subcc   %g3, 0x0, %g0
0241         bnz srmmu_not_viking            ! is in mbus mode
0242          nop
0243 
0244         rd  %psr, %g3           ! DO NOT TOUCH %g3
0245         andn    %g3, PSR_ET, %g2
0246         wr  %g2, 0x0, %psr
0247         WRITE_PAUSE
0248 
0249         /* Get context table pointer, then convert to
0250          * a physical address, which is 36 bits.
0251          */
0252         set AC_M_CTPR, %g4
0253         lda [%g4] ASI_M_MMUREGS, %g4
0254         sll %g4, 0x4, %g4           ! We use this below
0255                             ! DO NOT TOUCH %g4
0256 
0257         /* Set the AC bit in the Viking's MMU control reg. */
0258         lda [%g0] ASI_M_MMUREGS, %g5    ! DO NOT TOUCH %g5
0259         set 0x8000, %g6         ! AC bit mask
0260         or  %g5, %g6, %g6           ! Or it in...
0261         sta %g6, [%g0] ASI_M_MMUREGS    ! Close your eyes...
0262 
0263         /* Grrr, why does it seem like every other load/store
0264          * on the sun4m is in some ASI space...
0265          * Fine with me, let's get the pointer to the level 1
0266          * page table directory and fetch its entry.
0267          */
0268         lda [%g4] ASI_M_BYPASS, %o1     ! This is a level 1 ptr
0269         srl %o1, 0x4, %o1           ! Clear low 4 bits
0270         sll %o1, 0x8, %o1           ! Make physical
0271 
0272         /* Ok, pull in the PTD. */
0273         lda [%o1] ASI_M_BYPASS, %o2     ! This is the 0x0 16MB pgd
0274 
0275         /* Calculate to KERNBASE entry. */
0276         add %o1, KERNBASE >> (PGDIR_SHIFT - 2), %o3
0277 
0278         /* Poke the entry into the calculated address. */
0279         sta %o2, [%o3] ASI_M_BYPASS
0280 
0281         /* I don't get it Sun, if you engineered all these
0282          * boot loaders and the PROM (thank you for the debugging
0283          * features btw) why did you not have them load kernel
0284          * images up in high address space, since this is necessary
0285          * for ABI compliance anyways?  Does this low-mapping provide
0286          * enhanced interoperability?
0287          *
0288          * "The PROM is the computer."
0289          */
0290 
0291         /* Ok, restore the MMU control register we saved in %g5 */
0292         sta %g5, [%g0] ASI_M_MMUREGS    ! POW... ouch
0293 
0294         /* Turn traps back on.  We saved it in %g3 earlier. */
0295         wr  %g3, 0x0, %psr          ! tick tock, tick tock
0296 
0297         /* Now we burn precious CPU cycles due to bad engineering. */
0298         WRITE_PAUSE
0299 
0300         /* Wow, all that just to move a 32-bit value from one
0301          * place to another...  Jump to high memory.
0302          */
0303         b   go_to_highmem
0304          nop
0305 
0306 srmmu_not_viking:
0307         /* This works on viking's in Mbus mode and all
0308          * other MBUS modules.  It is virtually the same as
0309          * the above madness sans turning traps off and flipping
0310          * the AC bit.
0311          */
0312         set AC_M_CTPR, %g1
0313         lda [%g1] ASI_M_MMUREGS, %g1    ! get ctx table ptr
0314         sll %g1, 0x4, %g1           ! make physical addr
0315         lda [%g1] ASI_M_BYPASS, %g1     ! ptr to level 1 pg_table
0316         srl %g1, 0x4, %g1
0317         sll %g1, 0x8, %g1           ! make phys addr for l1 tbl
0318 
0319         lda [%g1] ASI_M_BYPASS, %g2     ! get level1 entry for 0x0
0320         add %g1, KERNBASE >> (PGDIR_SHIFT - 2), %g3
0321         sta %g2, [%g3] ASI_M_BYPASS     ! place at KERNBASE entry
0322         b   go_to_highmem
0323          nop                    ! wheee....
0324 
0325 
0326 leon_remap:
0327         /* Sanity-check, is MMU enabled */
0328         lda [%g0] ASI_LEON_MMUREGS, %g1
0329         andcc   %g1, 1, %g0
0330         be  halt_notsup
0331          nop
0332 
0333         /* Same code as in the srmmu_not_viking case,
0334          * with the LEON ASI for mmuregs
0335          */
0336         set AC_M_CTPR, %g1
0337         lda [%g1] ASI_LEON_MMUREGS, %g1 ! get ctx table ptr
0338         sll %g1, 0x4, %g1           ! make physical addr
0339         lda [%g1] ASI_M_BYPASS, %g1     ! ptr to level 1 pg_table
0340         srl %g1, 0x4, %g1
0341         sll %g1, 0x8, %g1           ! make phys addr for l1 tbl
0342 
0343         lda [%g1] ASI_M_BYPASS, %g2     ! get level1 entry for 0x0
0344         add %g1, KERNBASE >> (PGDIR_SHIFT - 2), %g3
0345         sta %g2, [%g3] ASI_M_BYPASS     ! place at KERNBASE entry
0346         b   go_to_highmem
0347          nop                    ! wheee....
0348 
0349 /* Now do a non-relative jump so that PC is in high-memory */
0350 go_to_highmem:
0351         set execute_in_high_mem, %g1
0352         jmpl    %g1, %g0
0353          nop
0354 
0355 /* The code above should be at beginning and we have to take care about
0356  * short jumps, as branching to .init.text section from .text is usually
0357  * impossible */
0358         __INIT
0359 /* Acquire boot time privileged register values, this will help debugging.
0360  * I figure out and store nwindows and nwindowsm1 later on.
0361  */
0362 execute_in_high_mem:
0363         mov %l0, %o0        ! put back romvec
0364         mov %l1, %o1        ! and debug_vec
0365 
0366         sethi   %hi(prom_vector_p), %g1
0367         st  %o0, [%g1 + %lo(prom_vector_p)]
0368 
0369         sethi   %hi(linux_dbvec), %g1
0370         st  %o1, [%g1 + %lo(linux_dbvec)]
0371 
0372         /* Get the machine type via the romvec
0373          * getprops node operation
0374          */
0375         add %g7, 0x1c, %l1
0376         ld  [%l1], %l0
0377         ld  [%l0], %l0
0378         call    %l0
0379          or %g0, %g0, %o0       ! next_node(0) = first_node
0380         or  %o0, %g0, %g6
0381 
0382         sethi   %hi(cputypvar), %o1 ! First node has cpu-arch
0383         or  %o1, %lo(cputypvar), %o1
0384         sethi   %hi(cputypval), %o2 ! information, the string
0385         or  %o2, %lo(cputypval), %o2
0386         ld  [%l1], %l0      ! 'compatible' tells
0387         ld  [%l0 + 0xc], %l0    ! that we want 'sun4x' where
0388         call    %l0         ! x is one of 'm', 'd' or 'e'.
0389          nop                ! %o2 holds pointer
0390                         ! to a buf where above string
0391                         ! will get stored by the prom.
0392 
0393 
0394         /* Check value of "compatible" property.
0395          * "value" => "model"
0396          * leon => sparc_leon
0397          * sun4m => sun4m
0398          * sun4s => sun4m
0399          * sun4d => sun4d
0400          * sun4e => "no_sun4e_here"
0401          * '*'   => "no_sun4u_here"
0402          * Check single letters only
0403          */
0404 
0405         set cputypval, %o2
0406         /* If cputypval[0] == 'l' (lower case letter L) this is leon */
0407         ldub    [%o2], %l1
0408         cmp %l1, 'l'
0409         be  leon_init
0410          nop
0411 
0412         /* Check cputypval[4] to find the sun model */
0413         ldub    [%o2 + 0x4], %l1
0414 
0415         cmp %l1, 'm'
0416         be  sun4m_init
0417          cmp    %l1, 's'
0418         be  sun4m_init
0419          cmp    %l1, 'd'
0420         be  sun4d_init
0421          cmp    %l1, 'e'
0422         be  no_sun4e_here       ! Could be a sun4e.
0423          nop
0424         b   no_sun4u_here       ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :))
0425          nop
0426 
0427 leon_init:
0428         /* LEON CPU - set boot_cpu_id */
0429         sethi   %hi(boot_cpu_id), %g2   ! boot-cpu index
0430 
0431 #ifdef CONFIG_SMP
0432         ldub    [%g2 + %lo(boot_cpu_id)], %g1
0433         cmp %g1, 0xff       ! unset means first CPU
0434         bne leon_smp_cpu_startup    ! continue only with master
0435          nop
0436 #endif
0437         /* Get CPU-ID from most significant 4-bit of ASR17 */
0438         rd     %asr17, %g1
0439         srl    %g1, 28, %g1
0440 
0441         /* Update boot_cpu_id only on boot cpu */
0442         stub    %g1, [%g2 + %lo(boot_cpu_id)]
0443 
0444         ba continue_boot
0445          nop
0446 
0447 /* CPUID in bootbus can be found at PA 0xff0140000 */
0448 #define SUN4D_BOOTBUS_CPUID     0xf0140000
0449 
0450 sun4d_init:
0451     /* Need to patch call to handler_irq */
0452     set patch_handler_irq, %g4
0453     set sun4d_handler_irq, %g5
0454     sethi   %hi(0x40000000), %g3        ! call
0455     sub %g5, %g4, %g5
0456     srl %g5, 2, %g5
0457     or  %g5, %g3, %g5
0458     st  %g5, [%g4]
0459 
0460 #ifdef CONFIG_SMP
0461     /* Get our CPU id out of bootbus */
0462     set     SUN4D_BOOTBUS_CPUID, %g3
0463     lduba   [%g3] ASI_M_CTL, %g3
0464     and     %g3, 0xf8, %g3
0465     srl     %g3, 3, %g4
0466     sta     %g4, [%g0] ASI_M_VIKING_TMP1
0467     sethi   %hi(boot_cpu_id), %g5
0468     stb %g4, [%g5 + %lo(boot_cpu_id)]
0469 #endif
0470 
0471     /* Fall through to sun4m_init */
0472 
0473 sun4m_init:
0474 /* Ok, the PROM could have done funny things and apple cider could still
0475  * be sitting in the fault status/address registers.  Read them all to
0476  * clear them so we don't get magic faults later on.
0477  */
0478 /* This sucks, apparently this makes Vikings call prom panic, will fix later */
0479 2:
0480         rd  %psr, %o1
0481         srl %o1, PSR_IMPL_SHIFT, %o1    ! Get a type of the CPU
0482 
0483         subcc   %o1, PSR_IMPL_TI, %g0       ! TI: Viking or MicroSPARC
0484         be  continue_boot
0485          nop
0486 
0487         set AC_M_SFSR, %o0
0488         lda [%o0] ASI_M_MMUREGS, %g0
0489         set AC_M_SFAR, %o0
0490         lda [%o0] ASI_M_MMUREGS, %g0
0491 
0492         /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */
0493         subcc   %o1, 0, %g0
0494         be  continue_boot
0495          nop
0496 
0497         set AC_M_AFSR, %o0
0498         lda [%o0] ASI_M_MMUREGS, %g0
0499         set AC_M_AFAR, %o0
0500         lda [%o0] ASI_M_MMUREGS, %g0
0501          nop
0502 
0503 
0504 continue_boot:
0505 
0506 /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
0507  * show-time!
0508  */
0509         /* Turn on Supervisor, EnableFloating, and all the PIL bits.
0510          * Also puts us in register window zero with traps off.
0511          */
0512         set (PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
0513         wr  %g2, 0x0, %psr
0514         WRITE_PAUSE
0515 
0516         /* I want a kernel stack NOW! */
0517         set init_thread_union, %g1
0518         set (THREAD_SIZE - STACKFRAME_SZ - TRACEREG_SZ), %g2
0519         add %g1, %g2, %sp
0520         mov 0, %fp          /* And for good luck */
0521 
0522         /* Zero out our BSS section. */
0523         set __bss_start , %o0   ! First address of BSS
0524         set _end , %o1      ! Last address of BSS
0525         add %o0, 0x1, %o0
0526 1:
0527         stb %g0, [%o0]
0528         subcc   %o0, %o1, %g0
0529         bl  1b
0530          add    %o0, 0x1, %o0
0531 
0532         /* If boot_cpu_id has not been setup by machine specific
0533          * init-code above we default it to zero.
0534          */
0535         sethi   %hi(boot_cpu_id), %g2
0536         ldub    [%g2 + %lo(boot_cpu_id)], %g3
0537         cmp %g3, 0xff
0538         bne 1f
0539          nop
0540         mov %g0, %g3
0541         stub    %g3, [%g2 + %lo(boot_cpu_id)]
0542 
0543 1:      sll %g3, 2, %g3
0544 
0545         /* Initialize the uwinmask value for init task just in case.
0546          * But first make current_set[boot_cpu_id] point to something useful.
0547          */
0548         set init_thread_union, %g6
0549         set current_set, %g2
0550 #ifdef CONFIG_SMP
0551         st  %g6, [%g2]
0552         add %g2, %g3, %g2
0553 #endif
0554         st  %g6, [%g2]
0555 
0556         st  %g0, [%g6 + TI_UWINMASK]
0557 
0558 /* Compute NWINDOWS and stash it away. Now uses %wim trick explained
0559  * in the V8 manual. Ok, this method seems to work, Sparc is cool...
0560  * No, it doesn't work, have to play the save/readCWP/restore trick.
0561  */
0562 
0563         wr  %g0, 0x0, %wim          ! so we do not get a trap
0564         WRITE_PAUSE
0565 
0566         save
0567 
0568         rd  %psr, %g3
0569 
0570         restore
0571 
0572         and %g3, 0x1f, %g3
0573         add %g3, 0x1, %g3
0574 
0575         mov 2, %g1
0576         wr  %g1, 0x0, %wim          ! make window 1 invalid
0577         WRITE_PAUSE
0578 
0579         cmp %g3, 0x7
0580         bne 2f
0581          nop
0582 
0583         /* Adjust our window handling routines to
0584          * do things correctly on 7 window Sparcs.
0585          */
0586 
0587 #define     PATCH_INSN(src, dest) \
0588         set src, %g5; \
0589         set dest, %g2; \
0590         ld  [%g5], %g4; \
0591         st  %g4, [%g2];
0592 
0593         /* Patch for window spills... */
0594         PATCH_INSN(spnwin_patch1_7win, spnwin_patch1)
0595         PATCH_INSN(spnwin_patch2_7win, spnwin_patch2)
0596         PATCH_INSN(spnwin_patch3_7win, spnwin_patch3)
0597 
0598         /* Patch for window fills... */
0599         PATCH_INSN(fnwin_patch1_7win, fnwin_patch1)
0600         PATCH_INSN(fnwin_patch2_7win, fnwin_patch2)
0601 
0602         /* Patch for trap entry setup... */
0603         PATCH_INSN(tsetup_7win_patch1, tsetup_patch1)
0604         PATCH_INSN(tsetup_7win_patch2, tsetup_patch2)
0605         PATCH_INSN(tsetup_7win_patch3, tsetup_patch3)
0606         PATCH_INSN(tsetup_7win_patch4, tsetup_patch4)
0607         PATCH_INSN(tsetup_7win_patch5, tsetup_patch5)
0608         PATCH_INSN(tsetup_7win_patch6, tsetup_patch6)
0609 
0610         /* Patch for returning from traps... */
0611         PATCH_INSN(rtrap_7win_patch1, rtrap_patch1)
0612         PATCH_INSN(rtrap_7win_patch2, rtrap_patch2)
0613         PATCH_INSN(rtrap_7win_patch3, rtrap_patch3)
0614         PATCH_INSN(rtrap_7win_patch4, rtrap_patch4)
0615         PATCH_INSN(rtrap_7win_patch5, rtrap_patch5)
0616 
0617         /* Patch for killing user windows from the register file. */
0618         PATCH_INSN(kuw_patch1_7win, kuw_patch1)
0619 
0620         /* Now patch the kernel window flush sequences.
0621          * This saves 2 traps on every switch and fork.
0622          */
0623         set 0x01000000, %g4
0624         set flush_patch_one, %g5
0625         st  %g4, [%g5 + 0x18]
0626         st  %g4, [%g5 + 0x1c]
0627         set flush_patch_two, %g5
0628         st  %g4, [%g5 + 0x18]
0629         st  %g4, [%g5 + 0x1c]
0630         set flush_patch_three, %g5
0631         st  %g4, [%g5 + 0x18]
0632         st  %g4, [%g5 + 0x1c]
0633         set flush_patch_four, %g5
0634         st  %g4, [%g5 + 0x18]
0635         st  %g4, [%g5 + 0x1c]
0636         set flush_patch_exception, %g5
0637         st  %g4, [%g5 + 0x18]
0638         st  %g4, [%g5 + 0x1c]
0639         set flush_patch_switch, %g5
0640         st  %g4, [%g5 + 0x18]
0641         st  %g4, [%g5 + 0x1c]
0642 
0643 2:
0644         sethi   %hi(nwindows), %g4
0645         st  %g3, [%g4 + %lo(nwindows)]  ! store final value
0646         sub %g3, 0x1, %g3
0647         sethi   %hi(nwindowsm1), %g4
0648         st  %g3, [%g4 + %lo(nwindowsm1)]
0649 
0650         /* Here we go, start using Linux's trap table... */
0651         set trapbase, %g3
0652         wr  %g3, 0x0, %tbr
0653         WRITE_PAUSE
0654 
0655         /* Finally, turn on traps so that we can call c-code. */
0656         rd  %psr, %g3
0657         wr  %g3, 0x0, %psr
0658         WRITE_PAUSE
0659 
0660         wr  %g3, PSR_ET, %psr
0661         WRITE_PAUSE
0662 
0663         /* Call sparc32_start_kernel(struct linux_romvec *rp) */
0664         sethi   %hi(prom_vector_p), %g5
0665         ld  [%g5 + %lo(prom_vector_p)], %o0
0666         call    sparc32_start_kernel
0667          nop
0668 
0669         /* We should not get here. */
0670         call    halt_me
0671          nop
0672 
0673 no_sun4e_here:
0674         ld  [%g7 + 0x68], %o1
0675         set sun4e_notsup, %o0
0676         call    %o1
0677          nop
0678         b   halt_me
0679          nop
0680 
0681         __INITDATA
0682 
0683 sun4u_1:
0684         .asciz "finddevice"
0685         .align  4
0686 sun4u_2:
0687         .asciz "/chosen"
0688         .align  4
0689 sun4u_3:
0690         .asciz "getprop"
0691         .align  4
0692 sun4u_4:
0693         .asciz "stdout"
0694         .align  4
0695 sun4u_5:
0696         .asciz "write"
0697         .align  4
0698 sun4u_6:
0699         .asciz  "\n\rOn sun4u you have to use sparc64 kernel\n\rand not a sparc32 version\n\r\n\r"
0700 sun4u_6e:
0701         .align  4
0702 sun4u_7:
0703         .asciz "exit"
0704         .align  8
0705 sun4u_a1:
0706         .word   0, sun4u_1, 0, 1, 0, 1, 0, sun4u_2, 0
0707 sun4u_r1:
0708         .word   0
0709 sun4u_a2:
0710         .word   0, sun4u_3, 0, 4, 0, 1, 0
0711 sun4u_i2:
0712         .word   0, 0, sun4u_4, 0, sun4u_1, 0, 8, 0
0713 sun4u_r2:
0714         .word   0
0715 sun4u_a3:
0716         .word   0, sun4u_5, 0, 3, 0, 1, 0
0717 sun4u_i3:
0718         .word   0, 0, sun4u_6, 0, sun4u_6e - sun4u_6 - 1, 0
0719 sun4u_r3:
0720         .word   0
0721 sun4u_a4:
0722         .word   0, sun4u_7, 0, 0, 0, 0
0723 sun4u_r4:
0724 
0725         __INIT
0726 no_sun4u_here:
0727         set sun4u_a1, %o0
0728         set current_pc, %l2
0729         cmp %l2, %g3
0730         be  1f
0731          mov    %o4, %l0
0732         sub %g3, %l2, %l6
0733         add %o0, %l6, %o0
0734         mov %o0, %l4
0735         mov sun4u_r4 - sun4u_a1, %l3
0736         ld  [%l4], %l5
0737 2:
0738         add %l4, 4, %l4
0739         cmp %l5, %l2
0740         add %l5, %l6, %l5
0741         bgeu,a  3f
0742          st %l5, [%l4 - 4]
0743 3:
0744         subcc   %l3, 4, %l3
0745         bne 2b
0746          ld [%l4], %l5
0747 1:
0748         call    %l0
0749          mov    %o0, %l1
0750 
0751         ld  [%l1 + (sun4u_r1 - sun4u_a1)], %o1
0752         add %l1, (sun4u_a2 - sun4u_a1), %o0
0753         call    %l0
0754          st %o1, [%o0 + (sun4u_i2 - sun4u_a2)]
0755 
0756         ld  [%l1 + (sun4u_1 - sun4u_a1)], %o1
0757         add %l1, (sun4u_a3 - sun4u_a1), %o0
0758         call    %l0
0759         st  %o1, [%o0 + (sun4u_i3 - sun4u_a3)]
0760 
0761         call    %l0
0762          add    %l1, (sun4u_a4 - sun4u_a1), %o0
0763 
0764         /* Not reached */
0765 halt_me:
0766         ld  [%g7 + 0x74], %o0
0767         call    %o0         ! Get us out of here...
0768          nop                ! Apparently Solaris is better.
0769 
0770 /* Ok, now we continue in the .data/.text sections */
0771 
0772     .data
0773     .align 4
0774 
0775 /*
0776  * Fill up the prom vector, note in particular the kind first element,
0777  * no joke. I don't need all of them in here as the entire prom vector
0778  * gets initialized in c-code so all routines can use it.
0779  */
0780 
0781 prom_vector_p:
0782         .word 0
0783 
0784 /* We calculate the following at boot time, window fills/spills and trap entry
0785  * code uses these to keep track of the register windows.
0786  */
0787 
0788     .align 4
0789     .globl  nwindows
0790     .globl  nwindowsm1
0791 nwindows:
0792     .word   8
0793 nwindowsm1:
0794     .word   7
0795 
0796 /* Boot time debugger vector value.  We need this later on. */
0797 
0798     .align 4
0799     .globl  linux_dbvec
0800 linux_dbvec:
0801     .word   0
0802     .word   0
0803 
0804     .align 8
0805 
0806     .globl  lvl14_save
0807 lvl14_save:
0808     .word   0
0809     .word   0
0810     .word   0
0811     .word   0
0812     .word   t_irq14