home *** CD-ROM | disk | FTP | other *** search
- *
- * C initial startup procedure under AmigaDOS
- *
-
- 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
-
- TINY EQU 0
- callsys macro
- CALLLIB _LVO\1
- endm
-
- xdef __startup
- 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
-
- xref __main ; Name of C program to start with.
- xref __fpinit * initialize floating point
- xref __fpterm * terminate floating point
-
- * library references
-
- csect _NOMERGE,0,0,0,4
- xref __savecli
- xref __freecli
- xref FindTask
-
- __startup:
- start:
- movem.l d1-d6/a0-a6,-(a7)
- REGSIZE EQU (6+7)*4
- lea REGSIZE(a7),A5 * determine old stack pointer
- 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
- move.l a6,SysBase(A4)
-
- *------ Clear out our BSS section
- 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
-
- *------ get the address of our task
- move.l ThisTask(a6),A3
-
- *----- clear any pending signals
- moveq #0,d0
- move.l #$00003000,d1
- callsys SetSignal
-
- *------ are we running as a son of Workbench?
- move.l pr_CurrentDir(A3),__curdir(A4)
- tst.l pr_CLI(A3)
- beq fromWorkbench
-
- *=======================================================================
- *====== CLI Startup Code ===============================================
- *=======================================================================
-
- fromCLI:
- *------ attempt to open DOS library:
- bsr.w openDOS
-
- *------ Duplicate the current directory for the called process
- move.l __curdir(A4),D1
- move.l DOSBase(A4),A6
- callsys DupLock
- move.l D0,__curdir(A4)
-
- *------ Save the current CLI info including path for child to use
- pea cli
- jsr __savecli(pc)
- addq.l #4,a7
-
- *------ 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,D4 ;save our pointer
- move.l d1,d3
- add.l d1,d1 ; double length since we copy it twice
- add.l d1,d0 ; add length of command name
- addq.l #5,d0 ; allow for space after command
- addq.l #4,d0 ; As well as for the roundup
- * ; changed from 5 to 9 for quotes
- *
- *------ We have the length of the command string to be copied.
- *------ Allocate space for it.
- *------ Round up to the nearest 4 bytes
- lsl.l #2,d0
- add.l memsize(A4),d0
- move.l d0,memsize(A4)
-
- ************************************************************************
- ************************************************************************
- ******** Allocate and copy over the code to do the magic stuff *********
- ************************************************************************
- ************************************************************************
-
- lea memlist(A4),A0
- move.l AbsExecBase.W,a6
- callsys AllocEntry ;get a place to put the code
- * btst.l #31,d0 ;did we get the memory we asked for?
- * beq cliexit ;no, can't do anything then
- move.l D0,A1
- move.l D0,-(A7) ;remember the chunk we allocated
-
- *------ Now we copy the code over
- movea.l ML_SIZE+ME_ADDR(A1),A1 ;locate our allocated block
-
- *------ Copy over the command line to the allocated area
- lea commandbuf-copybeg(A1),A3
-
- *------ At this point, we have:
- * A0 - Work pointer
- * A1 - Pointer to Allocated memory block
- * A2 - Pointer to program name
- * A3 - Pointer to target buffer
- * A3 - Pointer to our process structure
- * D0 - Work register
- * D1 - Work register
- * D2 - length of command name
- * D3 - length of program name
- * D4 - Pointer to program name
-
- move.l d2,argslen ; save length of args
- move.l d3,proglen ; save length of prog
-
- movea.l D4,A0 ; Load program name
- move.l D3,D0 ; and length
- move.b #'"',(a3)+
- bra.s cpy1
- cpycmd: move.b (A0)+,(A3)+ ; copy over the command name
- cpy1: dbf d0,cpycmd
- move.b #'"',(a3)+
- move.b #' ',(A3)+ ; add the space delimiter
-
- move.l A2,A0 ; Load command text
- move.l D2,D0 ; and length
- bra.s cpy2
- cpylin: move.b (A0)+,(A3)+
- cpy2: dbf d0,cpylin
- clr.b (A3)+
-
- *------ Now copy over the program name
- move.l A3,_ProgramName(A4)
- move.l D4,A0
- move.l D3,D0
- bra.s cpy3
- cpypgm: move.b (A0)+,(A3)+
- cpy3: dbf D0,cpypgm
- clr.b (A3) ;don't forget trailing null on name
-
- *------ First we want to put it into our seglist
- lea segexit-copybeg(A1),A2
- move.l A2,_XCEXIT+2(A4) ;patch the jump instruction
- lea start-4(PC),A2
-
- * Now we have: A1 to our new fake segment
- * A2 to the start of the real seglist
- move.l #(copyend-copybeg)/4,(A1)+
- move.l A1,D3
- lsr.l #2,D3 ;convert it to a bptr to the list
- move.l (A2),(A1)+ ;save our next segment pointer
- clr.l (A2) ;and kill it from the chain
- *------ We have the seglist
-
- lea AutoLoader(PC),A2
- move.l #(copyend-AutoLoader)-1,D0
- copyit move.b (A2)+,(A1)+
- dbf d0,copyit
-
- *------ See if they want to do some I/O
- tst.l _BackGroundIO(A4)
- beq noio
- lea current_window(A4),A0
- move.l A0,D1
- move.l #1005,D2
- move.l DOSBase(A4),A6
- callsys Open
- move.l d0,_Backstdout(A4)
- noio:
-
- *------ If under 2.0 Flush cache and get ProgramDir
-
- moveq #36,d0
- cmp.w $14(a6),d0
- bgt.b nov36
-
- move.l DOSBase(A4),A6
- jsr -$258(a6) ;GetProgramDir
- move.l d0,d1
- callsys DupLock
- move.l d0,ProgramDir(a4)
-
- move.l AbsExecBase.w,A6
- moveq #-1,d0
- callsys CacheClearU
-
- nov36:
-
- move.l AbsExecBase.w,A6
-
- callsys Forbid
-
- *------ Attach the task to do the dirty work
- move.l __procname(A4),D1 ; Name of task to start
- move.l __priority(A4),D2 ; Priority of background task
- move.l __stack(A4),D4 ; Stack size of created task
-
- move.l DOSBase(A4),A6
- callsys CreateProc
- move.l A6,A3 ; restore dosbase to close it
- tst.l D0
- bne ok
-
- *------ Serious problems. For some reason the CreateProc failed.
- *------ We need to free the AlocEntry memory and go home
- move.l (A7)+,A2
- movea.l ML_SIZE+ME_ADDR(A2),A1 ;locate our allocated block
- *------ Also must get rid of current directory
- move.l __curdir(A4),D1
- callsys UnLock
-
- move.l A2,A0
- move.l AbsExecBase.w,A6
- callsys FreeEntry
- move.l #104,D0
- bra cliexit
-
- ok:
- *------ The task started ok, attach the memory we allocated to
- *------ its task control block
- move.l D0,A2
-
- move.l (a7)+,A1 ;locate the memory we allocated
- lea -pr_MsgPort(A2),A2
- lea TC_MEMENTRY(A2),A0
-
-
- * ADDTAIL
- LEA LH_TAIL(A0),A0
- MOVE.L LN_PRED(A0),D0
- MOVE.L A1,LN_PRED(A0)
- MOVE.L A0,(A1)
- MOVE.L D0,LN_PRED(A1)
- MOVE.L D0,A0
- MOVE.L A1,(A0)
-
- move.l #0,D0
-
- cliexit:
- move.l AbsExecBase.w,A6
- callsys Permit
- move.l A3,A1
- move.l AbsExecBase.w,A6
- callsys CloseLibrary
- movem.l (a7)+,d1-d6/a0-a6
- rts
-
- *=======================================================================
- *====== Workbench Startup Code =========================================
- *=======================================================================
-
- fromWorkbench:
- move.l a7,d0
- sub.l TC_SPLOWER(a3),d0
-
- *------ Set __base for stack checking
- move.l a7,d1
- sub.l d0,d1 * get top of stack
- add.l #128,D1 * allow for parms overflow
- move.l D1,__base(A4) * save for stack checking
-
- cmp.l __stack(a4),d0
- bcc.s nochange
-
- *-- current stack is not as big as __stack says it needs
- *-- to be. Allocate a new one.
- move.l __stack(a4),d0
- add.l #128,d0 * extra room
- move.l d0,newstacksize(a4)
-
- move.l #MEMFLAGS,d1
- callsys AllocMem
- tst.l d0
- beq.w return
-
- move.l d0,newstack(a4)
- add.l #128,d0 * extra room
- move.l d0,__base(a4)
-
- add.l __stack(a4),d0
- move.l d0,d1
-
- *-- If we're running under 2.0, call StackSwap to set up
- *-- the new stack. Otherwise, just jam the new value into
- *-- A7.
- cmpi.w #36,$14(a6)
- blt.s no20
-
- move.l d0,mystk_Pointer(a4)
- move.l d1,mystk_Upper(a4)
- sub.l newstacksize(a4),d1
- lea mystk_Lower(a4),a0
- move.l d1,(a0)
- callsys StackSwap
- bra.s nochange
-
- no20: move.l d0,a7
-
- nochange:
-
- *------ Save the current stack. We'll reset it to here to
- *------ Run the autoterminators.
- move.l a7,newst_Pointer(a4)
- move.l a7,newst_Upper(a4)
- lea newst_Lower(a4),a0
- move.l __base(a4),(a0)
- cmpi.w #36,$14(a6)
- blt.s no20b
- callsys StackSwap
-
- no20b:
-
-
- *------ open the DOS library:
- bsr.w openDOS
-
-
- *------ we are now set up. wait for a message from our starter
- bsr.w waitmsg
- 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 DupLock
- move.l d0,__curdir(A4)
- move.l d0,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
- pea NULL(A4) ; push argc
- move.l sm_ArgList(a0),a0 ; get address of arguments
- move.l wa_Name(a0),_ProgramName(A4) ; get name of program
-
- lea xcexit(PC),A2
- move.l A2,_XCEXIT+2(A4) ;patch the jump instruction
-
- moveq #36,d0
- cmp.w $14(a6),d0
- bgt.b nov36b
-
- move.l AbsExecBase.w,A6
- moveq #-1,d0
- callsys CacheClearU
- nov36b:
-
- *------ For startup from workbench, there is no reason to go through
- *------ The fancy stuff to make the startup work. Just run the
- *------ Code directly
- jsr __fpinit(PC)
- tst.l d0
- bne.w exit2
- jsr __main
- moveq.l #0,d0
- bra.w exit2
-
-
- ************************************************************************
- ************************************************************************
- ************* *************
- ************* Start of code that is copied to fake segment *************
- ************* *************
- ************************************************************************
- ************************************************************************
-
- copybeg:
- DC.L (copyend-copybeg)/4
- next: DC.L 0
- AutoLoader:
- move.l a7,d0
- movem.l d1-d6/a0-a6,-(a7)
- move.l d0,a5
- move.l AbsExecBase.w,a6
- lea LinkerDB,A4 ; load base register
- move.l a7,_StackPtr(A4)
-
- bsr.w openDOS
- suba.l a1,a1
-
- suba.l a1,a1
- callsys FindTask
- move.l d0,A3
-
- move.l TC_SPLOWER(A3),__base(A4) ; set base of stack
- add.l #128,__base(A4) ;allow for parms overflow
-
- move.l pr_SegList(A3),a0 ;locate the segment list
- add.l A0,A0
- add.l A0,A0 ;and convert to an APTR
- move.l 12(A0),A1 ;so we can access the segments
- add.l A1,A1
- add.l A1,A1
-
- move.l (A1),seglist(A4) ;save the remainder for later
- move.l (A1),12(A0) ;cut off our segment
-
- move.l __curdir(A4),D1
- move.l DOSBase(A4),a6
- callsys CurrentDir
-
- move.l ProgramDir(a4),d1
- beq.s noprogramdir
- jsr -$252(a6) ;SetProgramDir
-
- noprogramdir:
-
- *------ Open Nil: and set up it's input buffer so
- *------ ReadArgs will work.
- lea nil(pc),a0
- move.l a0,d1
- move.l #MODE_OLDFILE,d2
- callsys Open
- move.l d0,pr_CIS(a3)
- add.l d0,d0
- add.l d0,d0
- move.l d0,a2
- move.l argslen(pc),d2
- move.l d2,fh_End(a2)
- move.l #0,fh_Pos(a2)
-
- move.l AbsExecBase.w,a6
- move.l d2,d0
- moveq.l #0,d1
- callsys AllocMem
- tst.l d0
- beq.b segexit
-
- move.l d0,a0
- lea commandbuf(pc),a1
- adda.l proglen(pc),a1
- addq.l #3,a1 * 3 - is for quotes and trailing space
- subq.l #1,d2
- blt.b donecpy
- cpy:
- move.b (a1)+,(a0)+
- dbf d2,cpy
-
- donecpy:
- lsr.l #2,d0
- move.l d0,fh_Buf(a2)
-
- *------ Use the cli that our creator set up for us.
- move.l cli(pc),pr_CLI(a3)
-
- jsr __fpinit
- tst.l d0
- bne.s segexit
- pea commandbuf(PC)
- jsr __main ; call C entrypoint
- addq #4,A7
-
-
- *------ Unlock the directory we set up for them
- segexit:
- move.l DOSBase(A4),a6
- move.l __curdir(A4),D1
- callsys UnLock
-
- moveq.l #0,d0 ; set successful status
- xcexit:
- exit2:
-
- tst.l _WBenchMsg(A4)
- beq.s swapdone
-
- *-- Set the stack to the first NEW stack we allocated
- *-- So C++ destructors can run with a large stack if required
- move.l newst_Lower(a4),__base(a4)
- move.l AbsExecBase.W,A6
- cmpi.w #36,$14(a6)
- blt.s noswap1
- lea newst_Lower(a4),a0
- callsys StackSwap
- bra.b swapdone
- noswap1:
- move.l newst_Pointer(a4),a7
- swapdone:
- move.l _ONEXIT(A4),d0 ; exit trap function?
- beq.s exit3
- move.l d0,a0
- jsr (a0)
-
- exit3:
-
- *------ These must not be PC relative calls since this code is copied
- jsr __fpterm
-
- done_1c:
-
- *-- Swap back to original stack
- *-- If we're running under 2.0, call StackSwap
- *-- Otherwise, just jam the new value into a7
- move.l AbsExecBase.W,A6
- cmpi.w #36,$14(a6)
- blt.s noswap
- tst.l mystk_Lower(a4)
- beq.s noswap
-
- lea mystk_Lower(a4),a0
- subq.l #4,mystk_Pointer(a4) * make room for the ret code
- callsys StackSwap
-
- noswap:
-
- move.l _StackPtr(a4),a7 * restore stack ptr
-
-
- *------ if we ran from CLI, skip workbench cleanup:
- tst.l _WBenchMsg(A4)
- beq.s exitToDOS
- move.l newstacksize(a4),d0
- beq.s exit4
- move.l newstack(a4),a1
- move.l AbsExecBase.W,A6
- callsys FreeMem
- exit4:
- move.l DOSBase(A4),a6
- move.l stdin(A4),d1
- beq.s done_4
- callsys Close
-
- done_4:
- tst.l ProgramDir(a4)
- beq.s noprogdir
- moveq.l #0,d1
- jsr -$252(a6) ;SetProgramDir
- move.l ProgramDir(a4),d1
- callsys UnLock
-
-
- noprogdir:
-
- *------ return the startup message to our parent
- * we forbid so workbench can't UnLoadSeg() us
- * before we are done:
- move.l __curdir(a4),d1
- beq.s done_5
- callsys UnLock
-
- done_5:
- move.l AbsExecBase.w,A6
- callsys Forbid
- move.l _WBenchMsg(A4),a1
- callsys ReplyMsg
- move.l DOSBase(a4),a1
- bra.b noCIS
-
- *------ this rts sends us back to DOS:
- exitToDOS:
- jsr __freecli
-
- move.l AbsExecBase.W,a6
- sub.l a1,a1
- callsys FindTask
- move.l d0,a0
-
- move.l pr_CIS(a0),d1 * test for our input file handle
- beq.b noCIS
-
- clr.l pr_CIS(a0)
- move.l d1,d2
- add.l d1,d1
- add.l d1,d1
- move.l d1,a2
-
- *------ First free the buffer we allocated
- move.l fh_Buf(a2),d1
- add.l d1,d1
- add.l d1,d1
- move.l d1,a1
- move.l argslen(pc),d0
- callsys FreeMem
-
- *------ Restore fields to 0
- clr.l fh_Buf(a2)
- clr.l fh_End(a2)
-
- *------ Close Nil:
- move.l d2,d1
- move.l DOSBase(A4),a6
- callsys Close
-
- *------ They are done so unload them
- move.l seglist(A4),D1
- move.l DOSBase(A4),a6
- callsys UnLoadSeg
-
- move.l a6,a1
-
- noCIS:
- move.l AbsExecBase.w,a6
- callsys CloseLibrary ; close Dos library
-
- return:
- movem.l (a7)+,d1-d6/a0-a6
- rts
-
- *-----------------------------------------------------------------------
- * Open the DOS library:
-
- openDOS
- lea DOSName(A4),A1
- moveq.l #0,D0
- callsys OpenLibrary
- move.l D0,DOSBase(A4)
- beq noDOS
- rts
- *-----------------------------------------------------------------------
- noDOS:
- moveq.l #100,d0
- bra exit2
-
- cli: dc.l 0
- argslen: dc.l 0
- proglen: dc.l 0
- nil: dc.b 'NIL:',0,0
-
- copyend:
- commandbuf:
-
- ************************************************************************
- ************************************************************************
- ************** **************
- ************** End of code that is copied to fake segment **************
- ************** **************
- ************************************************************************
- ************************************************************************
-
- *-----------------------------------------------------------------------
- * This routine gets the message that workbench will send to us
- * called with task id in A3
-
- waitmsg:
- lea pr_MsgPort(A3),a0 ; our process base
- callsys WaitPort
- lea pr_MsgPort(A3),a0 ; our process base
- callsys GetMsg
- rts
-
- csect __MERGED,1,0,0,4
-
- *------ These externals control the task that is started
- xref _BackGroundIO ; flag to indicate background task
- * ; wants to do I/O
- xref __stack ; stack space for created task
- xref __procname ; name of process to be created
- xref __priority ; priority to create process at
-
- xref MathBase
- xref MathTransBase
- *
- xdef NULL,SysBase,DOSBase,_Backstdout
-
- xref _FPERR
- xref _WBenchMsg
- xref __curdir
- xref _OSERR,_SIGFPE,_ONERR,_ONEXIT,_ONBREAK
- xref _SIGINT
- xref _ProgramName,_StackPtr,__base
- *
- memlist ds.b LN_SIZE
- dc.w 1
- dc.l MEMF_PUBLIC
- memsize dc.l copyend-copybeg
-
- _XCEXIT
- @_XCEXIT dc.w $4ef9
- dc.l 0
- seglist dc.l 0
- NULL dc.l 0 ;
- DOSBase dc.l 0
- SysBase dc.l 0
- dosCmdLen dc.l 0
- dosCmdBuf dc.l 0
- stdin dc.l 0
- _Backstdout dc.l 0 ;filehandle for I/O
- ProgramDir dc.l 0
- DOSName dc.b 'dos.library',0
- current_window dc.b '*',0
- mystk_Lower dc.l 0
- mystk_Upper dc.l 0
- mystk_Pointer dc.l 0
- newst_Lower dc.l 0
- newst_Upper dc.l 0
- newst_Pointer dc.l 0
- newstack dc.l 0 * pointer to new stack (if needed)
- newstacksize dc.l 0 * size of new stack
- END
-