* * C initial startup procedure under AmigaDOS * Adapted by Jorrit Tyberghein * * Use the following command line to make the cli/workbench startup * asm -iINCLUDE: Arg.asm * * Use the following command line to make the resident startup * asm -dRESIDENT -iINCLUDE: -oArgR.o Arg.asm * * Use the following command line to make the cli startup * asm -dCLI -iINCLUDE: Arg.asm * 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/execbase.i" INCLUDE "libraries/dos.i" INCLUDE "libraries/dosextens.i" INCLUDE "workbench/startup.i" INCLUDE "exec/funcdef.i" INCLUDE "exec/exec_lib.i" INCLUDE "libraries/dos_lib.i" MEMFLAGS EQU MEMF_CLEAR+MEMF_PUBLIC AbsExecBase EQU 4 * some usefull macros: callsys macro CALLLIB _LVO\1 endm xdef _XCEXIT * exit(code) is standard way to leave C. xdef _@XCEXIT xref _LinkerDB * linker defined base value xref __BSSBAS * linker defined base of BSS xref __BSSLEN * linker defined length of BSS IFD RESIDENT xref _RESLEN xref _RESBASE xref _NEWDATAL xref __stack ENDC * library references section text,code xref _argmain * Name of C program to start with. start: movem.l d1-d6/a0-a6,-(a7) move.l a0,a2 * save command pointer move.l d0,d2 * and command length lea _LinkerDB,a4 * load base register move.l AbsExecBase.W,a6 IFND RESIDENT ;We do not have to clear BSS because AmigaDOS 2.0 does this for us. ; 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 stack ptr move.l a6,_SysBase(A4) ENDC IFD RESIDENT movem.l d2,-(a7) movem.l a0-a2,-(a7) *------ get the size of the stack, if CLI use cli_DefaultStack *------ if WB use a7 - TC_SPLOWER move.l ThisTask(a6),A3 move.l pr_CLI(A3),d1 IFND CLI beq.s fromwb ENDC lsl.l #2,d1 move.l d1,a0 move.l cli_DefaultStack(a0),d1 lsl.l #2,d1 * # longwords -> # bytes IFND CLI bra.s dostack fromwb: move.l a7,d1 sub.l TC_SPLOWER(a3),d1 ENDC dostack: moveq #0,d2 * use d2 as flag for newstack or not move.l #_RESLEN,d0 cmp.l __stack(a4),d1 * This a4 is in the original * set of data bcc.s nochange move.l __stack(a4),d1 add.l d1,d0 * increase size of mem for new stack moveq #1,d2 * set flag nochange: move.l d1,a3 * save stacksize to set up stack checking move.l #MEMFLAGS,d1 callsys AllocMem tst.l d0 bne.s ok1 movem.l (a7)+,d2/a0-a2 rts ok1: move.l d0,a0 move.l d0,a2 ;a2 now has difference move.l d0,a1 move.l #_NEWDATAL,d0 sub.l #_RESBASE,a4 ;copy data over cpy: move.l (a4)+,(a0)+ subq.l #1,d0 bne.s cpy ;a4 now points at number of relocs move.l (a4)+,d0 reloc: beq.s nreloc move.l a1,a0 add.l (a4)+,a0 * a0 now has add of reloc add.l (a0),a2 move.l a2,(a0) move.l a1,a2 * restore offset subq.l #1,d0 bra.s reloc nreloc: move.l a1,a4 * set up new base register add.l #_RESBASE,a4 move.l #_RESLEN,realdatasize(a4) movem.l (a7)+,a0-a2 move.l a6,_SysBase(A4) tst.b d2 movem.l (a7)+,d2 * restore d2 movem.l a7,__StackPtr(A4) * Save stack ptr (movem doesn't * change flags) beq.s nochg2 *------ set up new stack move.l a4,d0 sub.l #_RESBASE,d0 add.l #_RESLEN,d0 add.l __stack(a4),d0 * here a4 will be pointing at the * new data, but _stack will be the * same if all goes well sub.l #128,d0 * 128 down for good measure move.l d0,a7 move.l __stack(a4),d0 move.l d0,4(a7) * fill in size of new stack add.l d0,realdatasize(a4)* need to know how much to free later nochg2: ENDC clrwb: IFND CLI clr.l _WBenchMsg(A4) ENDC *----- clear any pending signals moveq #0,d0 move.l #$00003000,d1 callsys SetSignal *------ attempt to open DOS library: lea DOSName(PC),A1 moveq.l #0,D0 callsys OpenLibrary move.l D0,_DOSBase(A4) bne.s ok2 moveq.l #100,d0 bra.w exit2 ok2: *------ are we running as a son of Workbench? move.l ThisTask(a6),A3 IFND CLI tst.l pr_CLI(A3) beq.s fromWorkbench ENDC *======================================================================= *====== CLI Startup Code =============================================== *======================================================================= * * Entry: D2 = command length * A2 = Command pointer fromCLI: *------ find command name: move.l pr_CLI(a3),a0 add.l a0,a0 * bcpl pointer conversion add.l a0,a0 move.l cli_CommandName(a0),a1 add.l a1,a1 * bcpl pointer conversion add.l a1,a1 *------ collect parameters: move.l d2,d0 * get command line length moveq.l #0,d1 move.b (a1)+,d1 move.l a1,_ProgramName(A4) add.l d1,d0 * add length of command name addq.l #1,d0 * allow for space after command clr.w -(A7) * set null terminator for command line addq.l #3,D0 * force to longword alligned number of bytes andi.w #$fffc,D0 * (round up) addq.l #2,d0 * one extra word sub.l D0,A7 * make room on stack for command line subq.l #6,D0 clr.l 0(A7,D0) *------ copy command line onto stack move.l d2,d0 * get command line length subq.l #1,d0 add.l d1,d2 copy_line: move.b 0(A2,D0.W),0(A7,D2.W) * copy command line to stack subq.l #1,d2 dbf d0,copy_line move.b #' ',0(a7,d2.w) * add space between command and parms subq.l #1,d2 copy_cmd: move.b 0(a1,d2.w),0(a7,d2.w) * copy command name to stack dbf d2,copy_cmd move.l A7,A1 move.l A1,-(A7) * push command line address IFND CLI bra.s main * call C entrypoint *======================================================================= *====== Workbench Startup Code ========================================= *======================================================================= fromWorkbench: *------ we are now set up. wait for a message from our starter lea pr_MsgPort(A3),a0 * our process base callsys WaitPort lea pr_MsgPort(A3),a0 * our process base callsys GetMsg move.l d0,_WBenchMsg(a4) move.l d0,-(SP) * move.l d0,a2 * get first argument move.l sm_ArgList(a2),d0 beq.s do_cons move.l _DOSBase(a4),a6 move.l d0,a0 move.l wa_Lock(a0),d1 callsys CurrentDir do_cons: move.l sm_ToolWindow(a2),d1 * get the window argument beq.s do_main move.l #MODE_OLDFILE,d2 callsys Open move.l d0,stdin(a4) beq.s do_main lsl.l #2,d0 move.l d0,a0 move.l fh_Type(a0),pr_ConsoleTask(A3) do_main: move.l _WBenchMsg(A4),a0 * get address of workbench message move.l a0,-(a7) * push argv moveq #0,d0 move.l d0,-(a7) * push argc move.l sm_ArgList(a0),a0 * get address of arguments move.l wa_Name(a0),_ProgramName(A4) * get name of program ENDC *============================================= *------ common code -------- *============================================= main jsr _argmain(PC) * call C entrypoint moveq.l #0,d0 * set successful status bra.s exit2 * _XCEXIT: move.l 4(SP),d0 * extract return code _@XCEXIT: exit2: move.l d0,-(a7) move.l AbsExecBase.W,a6 move.l _DOSBase(A4),a1 callsys CloseLibrary * close Dos library done_1c: *------ if we ran from CLI, skip workbench cleanup: IFND CLI tst.l _WBenchMsg(A4) beq.s exitToDOS move.l stdin(a4),d1 beq.s done_4 callsys Close done_4: *------ return the startup message to our parent * we forbid so workbench can't UnLoadSeg() us * before we are done: move.l AbsExecBase.W,A6 callsys Forbid move.l _WBenchMsg(a4),a1 callsys ReplyMsg ENDC *------ this rts sends us back to DOS: exitToDOS: IFD RESIDENT move.l realdatasize(a4),d0 move.l a4,a1 sub.l #_RESBASE,a1 move.l AbsExecBase.W,a6 move.l (A7)+,d6 movea.l __StackPtr(a4),a5 callsys FreeMem move.l d6,d0 movea.l a5,sp ELSE move.l (A7)+,D0 movea.l __StackPtr(a4),SP * restore stack ptr ENDC movem.l (a7)+,d1-d6/a0-a6 rts DOSName dc.b 'dos.library',0 section __MERGED,BSS * xdef _SysBase,_WBenchMsg xdef _ProgramName,__StackPtr,_DOSBase * ifd RESIDENT realdatasize ds.b 4 * size of memory allocated for data + * possible stack endc _SysBase ds.b 4 _WBenchMsg ds.b 4 __StackPtr ds.b 4 stdin ds.b 4 _DOSBase ds.b 4 _ProgramName ds.b 4 END