#if defined(ALPHA) /*++ Copyright (c) 1993 Digital Equipment Corporation Module Name: jnfsstub.s Abstract: A streamlined copy of jenassem.s, for the FailSafe Booter. Author: John DeRosa 21-October-1992 Environment: Executes in kernel mode. Revision History: --*/ #include "ksalpha.h" #include "selfmap.h" #include "jnsndef.h" /***************************************************************** Simple functions to perform PALcode calls and memory barriers. ******************************************************************/ LEAF_ENTRY(AlphaInstIMB) callpal imb ret zero, (ra) .end AlphaInstIMB LEAF_ENTRY(AlphaInstMB) mb ret zero, (ra) .end AlphaInstMB LEAF_ENTRY(AlphaInstHalt) callpal halt ret zero, (ra) # should never return, but... .end AlphaInstHalt #if 0 LEAF_ENTRY(DisableInterrupts) callpal di ret zero, (ra) .end DisableInterrupts #endif LEAF_ENTRY(RegisterExceptionHandler) lda a0, FailSafeEntry # Restart main code on unexpected exceptions callpal wrentry ret zero, (ra) .end RegisterExceptionHandler NESTED_ENTRY(FwExecute, 0x60, ra) /* Routine Description: This is the entry point for the Execute service. It behaves in two different ways depending on where it is called from: 1) If called from the Firmware, it saves the stack pointer in a fixed location and then saves all the saved registers in the stack. This is the stack that will be used to restore the saved state when returning to the firmware. 2) If called from a loaded program, the program to be loaded and executed can overwrite the current program and its stack. Therefore a temporary stack is set. Arguments: a0 IN PCHAR Path, a1 IN ULONG Argc, a2 IN PCHAR Argv[], a3 IN PCHAR Envp[] Return Value: ARC_STATUS returned by FwPrivateExecute. Always returns to the Firmware. */ lda t0, FwSavedSp subq sp, 0x60 # make room in the stack stl sp, (t0) # save new stack pointer stq ra, (sp) # return address on top of stack stq s0, 0x8(sp) # save s registers stq s1, 0x10(sp) stq s2, 0x18(sp) stq s3, 0x20(sp) stq s4, 0x28(sp) stq s5, 0x30(sp) stq fp, 0x38(sp) stq gp, 0x40(sp) jsr ra, FwPrivateExecute # go do the work. RestoreFwState: ldq ra, (sp) # restore return address ldq s0, 0x8(sp) # restore s registers ldq s1, 0x10(sp) ldq s2, 0x18(sp) ldq s3, 0x20(sp) ldq s4, 0x28(sp) ldq s5, 0x30(sp) ldq fp, 0x48(sp) ldq gp, 0x40(sp) addq sp, 0x60 # restore stack pointer ret zero, (ra) # return to firmware control .end FwExecute NESTED_ENTRY(FwInvoke, 0x40, ra) /*++ ARC_STATUS FwInvoke( IN ULONG ExecAddr, IN ULONG StackAddr, IN ULONG Argc, IN PCHAR Argv[], IN PCHAR Envp[] ) Routine Description: This routine invokes a loaded program. Arguments: ExecAddr - Supplies the address of the routine to call. StackAddr - Supplies the address to which the stack pointer is set. Argc, Argv, Envp - Supply the arguments and environment to pass to Loaded program. The stack pointer is saved in register s0 so that when the loaded program returns, the old stack pointer can be restored. Return Value: ESUCCESS is returned if the address is valid. EFAULT indicates an invalid address. --*/ subq sp, 0x40 # make room on the stack stq ra, (sp) # save ra on top of stack stq s0, 0x8(sp) # save s0 and a0, 3, t1 # return EFAULT if unaligned address ldiq v0, 0x6 bne zero, 1f # branch if address alignment error mov a0, t12 # save program address in t12 mov sp, s0 # save stack pointer mov a1, sp # ..and load new one for program mov a2, a0 # argc becomes first argument mov a3, a1 # argv becomes second argument mov a4, a2 # envp becomes third argument jsr ra, (t12) # call program // here if loaded program returns. mov s0, sp # restore stack pointer mov zero, v0 # return ESUCCESS value ldq s0, 0x8(sp) # restore things ldq ra, (sp) 1: addq sp, 0x40 ret zero, (ra) .end FwInvoke #if 0 // // This function was used to zero out memory in the jnfs.c module. // We do not need to do this anymore. // /**** VOID WildZeroMemory( IN ULONG StartAddress, IN ULONG Size ) Routine Description: This routine zeroes the specified range of memory. At some point this may be changed to a more clever algorithm, For now, it simply does store quads. Arguments: a0 - supplies the base physical address of the range of memory to zero. It must be a multiple of the data cache line size. a1 - supplies length of memory to zero, in bytes. This must be a multiple of the data cache line size. Return Value: None. --*/ LEAF_ENTRY(WildZeroMemory) mov a0, t0 # start address mov a1, t1 # number of bytes to move 1: subqv t1, 0x20 # zero a D-cache block = 32 bytes stq zero, (t0) stq zero, 0x8(t0) stq zero, 0x10(t0) stq zero, 0x18(t0) addqv t0, 0x20 # move to next cache block bgt t1, 1b # t1 = 0 when done. ret zero, (ra) .end WildZeroMemory #endif /************************************************************ These are stubs. When the real code appears in the Alpha build tree, these should be deleted. Consult the "hacked" file. *************************************************************/ LEAF_ENTRY(DebugPrompt) callpal halt # surprise! ret zero, (ra) # should never return, but... .end DebugPrompt /* ---- VOID FwStallExecution ( ULONG Microseconds ); This routine utilizes the Alpha cycle counter to delay a requested number of microseconds. ---- */ LEAF_ENTRY( FwStallExecution) beq a0, 20f // exit if zero delay requested // lda t0, 20000(zero) // force small delays to 20 milliseconds // subl a0, 5, t1 // cmoveq t1, t0, a0 10: bsr t3, 100f // call 1 microsecond delay subroutine subl a0, 1, a0 // decrement requested microseconds zap a0, 0xf0, a0 // unsigned long a0 bgt a0, 10b 20: ret zero, (ra) // // 1 microsecond delay subroutine // 100: ldl t0, CyclesPerMicrosecond // init 1 microsecond delay rpcc t1 // get entry time rpcc value zap t1, 0xf0, t1 // clear <63:32> 200: rpcc t2 // get current rpcc value zap t2, 0xf0, t2 // clear <63:32> subl t2, t1, t2 // compute unsigned 32b difference zap t2, 0xf0, t2 subl t0, t2, t2 // (requested delay - delay so far) > 0? bgt t2, 200b ret zero, (t3) .end FwStallExecution #endif // ALPHA