;** ;** Startup.asm ;** ;** Copyright (C) 1994,95,96,97 Bernardo Innocenti ;** ;** Amiga/m68k startup code for XModule ;** INCLUDE "exec/types.i" INCLUDE "exec/alerts.i" INCLUDE "exec/nodes.i" INCLUDE "exec/lists.i" INCLUDE "exec/ports.i" INCLUDE "exec/libraries.i" INCLUDE "exec/tasks.i" INCLUDE "exec/memory.i" INCLUDE "exec/macros.i" INCLUDE "exec/execbase.i" INCLUDE "libraries/dos.i" INCLUDE "libraries/dosextens.i" INCLUDE "workbench/startup.i" AbsExecBase EQU 4 ;************************************************************************** ; External symbol definitions and references ;************************************************************************** xdef _Start xdef @_XCEXIT xdef _SysBase,_DOSBase xdef _ThisTask xdef _StdOut xdef _WBenchMsg xdef _SPrintf xdef _VSPrintf xdef _AsmAllocVecPooled xdef _AsmFreeVecPooled xdef _AsmCAllocPooled xref _LinkerDB ; linker defined base value xref __BSSBAS ; linker defined base of BSS xref __BSSLEN ; linker defined length of BSS xref ___main ; Name of C entry point xref _AsmAllocPooled xref _AsmFreePooled IFD DEBUG xref _kprintf ENDC IFND STKSIZE STKSIZE EQU 8192 ENDC ;************************************************************************** ; Macro definitions ;************************************************************************** PUSH MACRO ; push to stack move.\0 \1,-(sp) ; push.(w|l) ENDM POP MACRO ; pop from stack move.\0 (sp)+,\1 ; pop.(w|l) ENDM ;************************************************************************** ; Code entry point ;************************************************************************** SECTION __MERGED,code _Start: NEAR lea _LinkerDB,a4 ; load base register move.l AbsExecBase.w,a6 ; The BSS segment is being cleared by LoadSeg() starting from V37 ; ; lea __BSSBAS,a3 ; get base of BSS ; moveq #0,d1 ; move.l #__BSSLEN,d0 ; get length of BSS in longwords ; bra.s .clr_lp ; and clear for length given ;.clr_bss: ; move.l d1,(a3)+ ;.clr_lp: ; dbf d0,.clr_bss move.l a7,_StackPtr(a4) ; Save StackPtr move.l a6,_SysBase(a4) ; Save SysBase ; Find our Task (Process) structure suba.l a1,a1 JSRLIB FindTask ; FindTask (NULL) move.l d0,a3 move.l d0,_ThisTask(a4) ;************************************************************************** ; CPU checking ;************************************************************************** IFD _MC68020_ btst.b #AFB_68020,AttnFlags+1(a6) beq.s returnfail ENDC ;************************************************************************** ; Open dos.library ;************************************************************************** lea DOSName(PC),a1 moveq.l #37,d0 JSRLIB OpenLibrary move.l d0,_DOSBase(a4) beq.s returnfail ; Find output move.l d0,a6 ; Load DOSBase in A6 JSRLIB Output ; Call Output() move.l d0,_StdOut(a4) ; Save result move.l _SysBase(a4),a6 ; Restore SysBase in A6 ; are we running as a son of Workbench? move.l pr_CurrentDir(a3),__curdir(a4) move.l pr_CLI(a3),d0 bne.s cli_stack ;************************************************************************** ;* Workbench Startup Code: get for startup message ;************************************************************************** lea pr_MsgPort(a3),a0 ; our process message port JSRLIB WaitPort lea pr_MsgPort(a3),a0 ; our process message port JSRLIB GetMsg move.l d0,_WBenchMsg(a4) move.l d0,a2 ; get first argument move.l sm_ArgList(a2),d0 beq.s .wb_stack move.l _DOSBase(a4),a6 ; CurrentDir() move.l d0,a0 move.l wa_Lock(a0),d1 JSRLIB DupLock move.l d0,__curdir(a4) move.l d0,d1 JSRLIB CurrentDir move.l _SysBase(a4),a6 ; Restore SysBase in A6 ; Now calculate the remaining stack size (SP - TC_SPLOWER) .wb_stack: move.l sp,d0 sub.l TC_SPLOWER(a3),d0 bra.s swapstack cli_stack: ; get the size of the stack cli_DefaultStack ; D0 still holds process->pr_CLI lsl.l #2,d0 ; Shift BPTR move.l d0,a0 move.l cli_DefaultStack(a0),d0 lsl.l #2,d0 ; # longwords -> # bytes ;************************************************************************** ;* Stack swapping code ;************************************************************************** swapstack: cmpi.l #STKSIZE,d0 ; D0 = current stack size bcc.s do_main ; current stack is not as big as STKSIZE says it needs ; to be. Allocate a new one. IFD DEBUG lea .msg(pc),a0 PUSH.l a0 ; push format string jsr _kprintf ; call kprintf() addq #4,sp ; fix stack bra.s .end_debug .msg: dc.b 'Startup.asm: Allocating new stack...',$0A, 0 even .end_debug: ENDC move.l #STKSIZE,d0 moveq.l #MEMF_PUBLIC,d1 JSRLIB AllocMem tst.l d0 bne.s .do_swap moveq #RETURN_FAIL,d7 ; Fail bra.s exitdos .do_swap: ; Call StackSwap to set up the new stack lea stackswapstruct(a4),a0 move.l d0,(a0) ; stk_Lower add.l #STKSIZE,d0 ; SP to top of new stack (base + size) move.l d0,stk_Pointer(a0) ; stk_Pointer move.l d0,stk_Upper(a0) ; stk_Upper JSRLIB StackSwap ;************************************************************************** ; Call main() ;************************************************************************** do_main: IFD DEBUG ; Fill all free stack space with a magic number to check ; maximum program stack usage later. move.l #$DEADF00D,d0 move.l TC_SPLOWER(a3),a0 .fillstack: move.l d0,(a0)+ cmp.l a0,sp bgt.s .fillstack ENDC jsr ___main(pc) ; call C entrypoint @XCEXIT: ; XCEXIT() routine @_XCEXIT: ; Save Return Code move.l d0,d7 IFD DEBUG ; Check maximum stack used during execution. ; Search the first longword not containing our magic number. ; ; <- TC_SPUPPER <- top of stack ; |xxxxxxxx| \ ; |xxxxxxxx| |- stack used by startup code ; |xxxxxxxx| / ; |yyyyyyyy|<- sp \ <- current stack position ; |yyyyyyyy| | ; |yyyyyyyy| | ; |yyyyyyyy| |- stack used by C program ; |yyyyyyyy| | ; |yyyyyyyy| | ; |yyyyyyyy|<- Pivot (d0) / <- last used longword ; |DEADF00D| \ ; |DEADF00D| | ; |DEADF00D| |- unused stack ; |DEADF00D| | ; |DEADF00D|<- TC_SPLOWER / <- bottom of stack ; move.l TC_SPLOWER(a3),a0 move.l #$DEADF00D,d0 .cmpstack: move.l (a0)+,d1 ; read one longword and go on next cmp.l d0,d1 ; is the magic number still there? beq.s .cmpstack ; yes: loop again move.l a0,d0 ; make a copy of the Pivot move.l TC_SPLOWER(a3),d1 sub.l d1,d0 ; Pivot - TC_SPLOWER PUSH.l d0 ; push unused stack size (argument 4) move.l TC_SPUPPER(a3),d0 sub.l a0,d0 ; TC_SPUPPER - Pivot PUSH.l d0 ; push used stack size (argument 3) move.l TC_SPUPPER(a3),d0 sub.l d1,d0 ; TC_SPUPPER - TC_SPLOWER PUSH.l d0 ; push total stack size (argument 2) pea .msg(pc) ; push format string (argument 1) jsr _kprintf ; output debug string with kprintf() lea 16(sp),sp ; fix stack (4 arguments) bra.s .end_debug .msg: dc.b 'Startup.asm: Total stack size: %ld, Used: %ld, Unused: %ld.',$0A, 0 even .end_debug: move.l d7,d0 ; restore return code ENDC ; Swap back to original stack move.l _SysBase(a4),a6 lea stackswapstruct(a4),a0 tst.l (a0) beq.s .noswap JSRLIB StackSwap ; free the stack move.l stackswapstruct(a4),a1 ; FreeMem (stk_Lower,STKSIZE) move.l #STKSIZE,d0 JSRLIB FreeMem .noswap: move.l _StackPtr(a4),a2 ; restore original StackPtr ; if we ran from CLI, skip workbench cleanup: tst.l _WBenchMsg(a4) beq.s exitdos move.l _DOSBase(a4),a6 move.l __curdir(a4),d1 beq.s .nounlock JSRLIB UnLock .nounlock: ; return the startup message to our parent. ; We Forbid() so Workbench can't UnLoadSeg() us ; before we are done. move.l _SysBase(a4),a6 JSRLIB Forbid move.l _WBenchMsg(a4),a1 JSRLIB ReplyMsg exitdos: move.l _DOSBase(a4),a1 ; Close dos.library JSRLIB CloseLibrary move.l d7,d0 ; Put return code in D0 rts ; This RTS sends us back to our caller returnfail: moveq.l #RETURN_FAIL,d0 rts ;************************************************************************** ;* Simple (V)SPrintf routines ;************************************************************************** _SPrintf: movem.l a2-a3/a6,-(sp) ; Save registers move.l 4+12(sp),a3 ; Get destination buffer move.l 8+12(sp),a0 ; Get format string lea.l 12+12(sp),a1 ; Get arguments lea.l StuffChar(pc),a2 ; Get formatting routine move.l _SysBase(a4),a6 ; Get ExecBase JSRLIB RawDoFmt ; Format the string movem.l (sp)+,a2-a3/a6 ; Restore registers rts _VSPrintf: movem.l a2/a3/a6,-(sp) move.l 4+12(sp),a3 move.l 8+12(sp),a0 move.l 12+12(sp),a1 lea StuffChar(pc),a2 move.l _SysBase(a4),a6 JSRLIB RawDoFmt movem.l (sp)+,a2/a3/a6 rts StuffChar: move.b d0,(a3)+ rts ;************************************************************************** ;* Memory pools support ;************************************************************************** ; ; AsmAllocVecPooled (Pool, memSize, SysBase) ; a0 d0 a6 ; _AsmAllocVecPooled: addq.l #4,d0 ; Get space for tracking move.l d0,-(sp) ; Save the size IFD OS30_ONLY JSRLIB AllocPooled ELSE jsr _AsmAllocPooled ; Call pool... ENDC move.l (sp)+,d1 ; Get size back... tst.l d0 ; Check for error beq.s .fail ; If NULL, failed! move.l d0,a0 ; Get pointer... move.l d1,(a0)+ ; Store size move.l a0,d0 ; Get result .fail rts ; Return ; ; AsmFreeVecPooled (Pool, Memory, SysBase) ; a0 a1 a6 _AsmFreeVecPooled: move.l a1,d0 ; Test for NULL beq.s .noblock move.l -(a1),d0 ; Get size / ajust pointer IFD OS30_ONLY JMPLIB FreePooled ELSE jmp _AsmFreePooled ENDC .noblock rts ; ; CAllocPooled (Pool, memSize, SysBase) ; a0 d0 a6 _AsmCAllocPooled: move.l d0,-(sp) ; Save the size IFD OS30_ONLY JSRLIB AllocPooled ; Allocate memory from pool... ELSE jsr _AsmAllocPooled ; Allocate memory from pool... ENDC move.l (sp)+,d1 ; Get size back... move.l d0,a0 tst.l d0 ; Check for error beq.s .fail ; If NULL, failed! move.l d0,-(sp) ; Save result moveq #$F,d0 ; Check for odd length (not multiple of 16) and.w d1,d0 beq.s .noneed move.l a0,a1 add.l d1,a1 subq.w #1,d0 ; DBRA loops once too much for us .clear2 move.b #0,-(a1) ; Clear up to 15 bytes dbra d0,.clear2 .noneed lsr.l #4,d1 ; Divide by 16 tst.l d1 ; Check for 0 beq.s .endclear moveq #0,d0 ; D0 will be used to clear our memory buffer subq.l #1,d1 ; DBRA does one cycle more! .clear move.l d0,(a0)+ ; Clear memory block move.l d0,(a0)+ move.l d0,(a0)+ move.l d0,(a0)+ dbra d1,.clear swap d1 ; dbra only works on words subq.w #1,d1 bmi.s .endclear swap d1 bra.s .clear .endclear move.l (sp)+,d0 ; Get result back... .fail rts ; Return DOSName dc.b 'dos.library',0 ;************************************************************************** ;* Data section ;************************************************************************** SECTION __MERGED,BSS _SysBase ds.l 1 _DOSBase ds.l 1 _ThisTask ds.l 1 _StdOut ds.l 1 _StackPtr ds.l 1 _WBenchMsg ds.l 1 __curdir ds.l 1 stackswapstruct ds.b StackSwapStruct_SIZEOF END