/* * srt0.s - standalone startup code * .seg "data" * .asciz "@(#)srt0.s 1.1 94/10/31" * Copyright (c) 1986 by Sun Microsystems, Inc. */ .seg "text" .align 4 #include #include #include #include #include #include #include /* * param.h defines VAC, DELAY, and CDELAY * if we are compiling for the bootblock undef VAC * to save on code size */ #ifdef BOOTBLOCK #undef VAC #endif /* * Initial interrupt priority and how to get there. */ #define PSR_PIL_SHIFT 8 #define PSR_PIL_INIT (13 << PSR_PIL_SHIFT) /* * The following variables are machine-dependent and are set in fiximp. */ .seg "data" .global _Cpudelay /* * This variable is used in usec_delay(). See the chart in lib/sparc/misc.s. * Srt0.s sets this value based on the actual runtime environment encountered. * It's critical that the value be no SMALLER than required, e.g. the * DELAY macro guarantees a MINIMUM delay, not a maximum. */ _Cpudelay: ! count down counter initial value #define CPUDELAY_DEFAULT 7 .word CPUDELAY_DEFAULT ! worst case value (33 Mhz) .global _nwindows _nwindows: #define NWINDOWS_DEFAULT 8 .word NWINDOWS_DEFAULT ! max # windows...mustn't be too small .global _npmgrps _npmgrps: #define NPMGRPS_DEFAULT 512 .word NPMGRPS_DEFAULT ! max # pmegs .global _vac _vac: #define VAC_DEFAULT 1 .word VAC_DEFAULT ! vac is there by default .global _vac_size _vac_size: #define VACSIZE_DEFAULT 0x20000 .word VACSIZE_DEFAULT ! 128K .global _vac_linesize _vac_linesize: #define VACLINESIZE_DEFAULT 16 .word VACLINESIZE_DEFAULT .global _segmask _segmask: #define SEGMASK_DEFAULT 0x1ff .word SEGMASK_DEFAULT ! segmask is 511 by default .global _romp /* * The following variables are more or less machine-independent * (or are set outside of fiximp). */ _romp: .word 0 .global _cpudelay ! old macros: _cpudelay: ! shift right amount to scale (n << 4) .word 0 ! worst case value (25 Mhz) idp: .word 0 ! room for idprom format & mach type .word 0 .global _environ _environ: .word 0 ! satisfy references from libc exitbuf: .skip 5*4 ! (jump_buf)exitbuf for _exit routine .seg "text" .align 8 .global _end .global _edata .global __setjmp .global __longjmp .global _main .global __exit .global __exitto .global _start _start: #ifdef BOOTBLOCK .global _begin, _bootb, _bbsize, _bbchecksum b,a _begin _bootb: ! should be NBLKENTRIES (64), see installboot.c .skip 64*4 ! room for boot_tab _bbsize: .word 0 _bbchecksum: .word 0 _begin: #endif BOOTBLOCK ! Each standalone program is responsible for its own stack. Our strategy ! is that each program which uses this runtime code creates a stack just ! below its relocation address. Previous windows may (and probably do) ! have frames allocated on the prior stack; leave them alone. Starting with ! this window, allocate our own stack frames for our windows. (Overflows ! or a window flush would then pass seamlessly from our stack to the old.) ! RESTRICTION: A program running at some relocation address must not exec ! another which will run at the very same address: the stacks would collide. ! This is currently not a problem, as all standalone programs (boot, copy, ! kadb, unix, et al.) run at different, carefully chosen addresses...which ! is, of course, a crock. ! ! Careful: don't touch %o0 until the save, since it holds the romp ! for Forth PROMs. ! set _start, %o1 save %o1, -SA(MINFRAME), %sp acall: call 1f ! get the current pc into o7 ! (where _start is currently located) sethi %hi(acall), %o3 ! relocated address of call 1: sub %o7,acall-_start,%o0 ! address where _start is in memory or %o3, %lo(acall), %o3 ! relocated address of call cmp %o3, %o7 be jmpstart .empty ! next instruction ok in delay slot set _edata+4, %o2 ! end of program, inclusive, except bss set _start, %o1 ! beginning of program sub %o2, %o1, %o2 ! size of program 2: ldd [%o0], %o4 ! relocate program inc 8, %o0 ! bcopy std %o4, [%o1] deccc 8, %o2 bg 2b inc 8, %o1 set jmpstart, %l0 ! now that it is relocated, jump to it jmp %l0 nop jmpstart: set _romp, %o0 ! Stash the romp we've been saving st %i0, [%o0] /* * We need to read idprom to figure out what we are. * Put machine-dependent variables in the following registers: * %l0 Cpudelay * %l1 nwindows * %l2 npmgrps * %l3 vac * %l4 vac_size * %l5 vac_linesize */ fiximp: set idp, %o0 call _getidprom mov 2, %o1 cmp %o0, IDFORM_1 mov VACLINESIZE_DEFAULT, %l5 sethi %hi(VACSIZE_DEFAULT), %l4 mov VAC_DEFAULT, %l3 mov NPMGRPS_DEFAULT, %l2 mov NWINDOWS_DEFAULT, %l1 bne id_badformat mov CPUDELAY_DEFAULT, %l0 set idp, %o1 ldub [%o1+1], %o0 #ifdef sun4 cmp %o0, IDM_SUN4 be id_sunrise ! Sunrise? cmp %o0, IDM_SUN4_COBRA be id_cobra ! Cobra? cmp %o0, IDM_SUN4_STINGRAY be id_stingray ! Stingray? cmp %o0, IDM_SUN4_SUNRAY be id_sunray ! Sunray? nop id_cobra: set _segmask, %o1 set 0xff, %o2 st %o2, [%o1] ! set segmask to 0xff mov 7, %l0 ! set Cpudelay to 7 mov NPMGRPS_110, %l2 ! set npmgrps mov %g0, %l3 ! set vac to zero ba set_delay .empty ! use delay slot to set nwindows /* * All of the Cpudelay values used are for cache off. */ id_sunrise: mov 7, %l1 ! set nwindows to 7 mov NPMGRPS_260, %l2 ! set npmgrps ba set_delay mov 1, %l0 ! set Cpudelay to 1 id_stingray: mov 7, %l1 ! set nwindows to 7 mov NPMGRPS_330, %l2 ! set npmgrps ba set_delay mov 1, %l0 ! set Cpudelay to 1 id_sunray: mov NPMGRPS_460, %l2 ! set npmgrps mov VAC_LINESIZE_SUNRAY, %l5 mov 1, %l0 ! set Cpudelay to 1 #else sun4 /* * XXX - This should all come from the open prom properties. */ mov 1, %l0 ! set Cpudelay to 1 cmp %o0, IDM_SUN4C_60 be id_campus1 ! Campus-1? cmp %o0, IDM_SUN4C_40 be id_campus1 ! Office-1? cmp %o0, IDM_SUN4C_65 be,a id_campus1 ! Campus-B? mov 1, %l0 ! set Cpudelay to 1 cmp %o0, IDM_SUN4C_20 be id_campus1 ! Off-campus? cmp %o0, IDM_SUN4C_70 be,a id_calvin ! Calvin? mov 1, %l0 ! set Cpudelay to 1 id_campus1: mov 7, %l1 ! set nwindows to 7 mov NPMGRPS_60, %l2 ! set npmgrps sethi %hi(VAC_SIZE_60), %l4 mov VAC_LINESIZE_60, %l5 ba set_delay mov %g0, %l3 ! set vac to zero id_calvin: mov 8, %l1 ! set nwindows to 8 mov 256, %l2 ! set npmgrps sethi %hi(VAC_SIZE_60*2), %l4 mov VAC_LINESIZE_60*2, %l5 mov %g0, %l3 ! set vac to zero #endif sun4 id_badformat: set_delay: sethi %hi(_Cpudelay), %o0 st %l0, [%o0 + %lo(_Cpudelay)] ! set Cpudelay sethi %hi(_nwindows), %o0 st %l1, [%o0 + %lo(_nwindows)] ! set nwindows sethi %hi(_npmgrps), %o0 st %l2, [%o0 + %lo(_npmgrps)] ! set npmgrps sethi %hi(_vac), %o0 st %l3, [%o0 + %lo(_vac)] ! set vac sethi %hi(_vac_size), %o0 st %l3, [%o0 + %lo(_vac_size)] sethi %hi(_vac_linesize), %o0 #ifdef VAC call init_cache #endif st %l3, [%o0 + %lo(_vac_linesize)] set _edata, %o0 ! beginning of bss set _end+4, %o1 ! end of bss call _bzero ! zero the bss sub %o1, %o0, %o1 ! size of bss ! ! Set the psr into a known state, until we are sure it is: ! supervisor mode, interrupt level >= 13, traps enabled ! mov %psr, %o0 andn %o0, PSR_PIL, %o0 set PSR_S|PSR_PIL_INIT|PSR_ET, %o1 or %o0, %o1, %o0 mov %o0, %psr nop; nop; nop #ifdef sun4c call _l14enable ! turn on level 14 interrupts nop #endif !sun4c ! ! Mark this spot. ! sethi %hi(exitbuf), %o0 call __setjmp or %o0, %lo(exitbuf), %o0 tst %o0 ! returned 1: we exit now. bnz out nop call _main mov 0, %o0 ! delay slot ! Fall through... ! ! __exit means exit NOW. We may be arbitrarily deep in the windows, so longjmp. ! #ifndef VAC __exit: set exitbuf, %o0 call __longjmp mov 1, %o1 out: ret ! ret to prom restore __exitto: save %sp, -SA(MINFRAME), %sp set _romp, %o0 ! pass the romp to the callee jmpl %i0, %o7 ! call thru register ld [%o0], %o0 ret restore #else !VAC __exit: save %sp, -SA(MINFRAME), %sp set _vac, %o0 ! check vac flag ld [%o0], %o0 tst %o0 bz 1f call _turnoff_cache nop 1: set exitbuf, %o0 call __longjmp mov 1, %o1 out: ret restore __exitto: save %sp, -SA(MINFRAME), %sp ! ! turn off the cache if it's currently on ! set _vac, %o0 ! check vac flag ld [%o0], %o0 tst %o0 bz no_cache nop call _turnoff_cache nop no_cache: set _romp, %o0 ! pass the romp to the callee jmpl %i0, %o7 ! call thru register ld [%o0], %o0 set _vac, %o0 ! check vac flag ld [%o0], %o0 tst %o0 bz leave_cache_off nop call _turnon_cache nop leave_cache_off: ret restore init_cache: save %sp, -SA(MINFRAME), %sp set _vac, %o0 ! check vac flag ld [%o0], %o0 tst %o0 bz 1f .empty set _start, %o0 ! this doesn't get the stack sethi %hi(_end), %o1 call _cache_prog ! clear the NC bits for prog's pages or %o1, %lo(_end), %o1 call _turnon_cache nop 1: ret restore #endif VAC