Back to home page

LXR

 
 

    


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