OS-9 Level I V1.2 kernal, part 2
The OS-9 kernel is split into two parts. Part 2 is position independent, but usually resides in a two-kilobyte ROM at $F000 together with other modules, such as Clock and SysGo.
nam OS-9 Level I V1.2 kernal, part 2 ttl Module Header ************************************************************ * * * Microware OS-9 Level I V1.2 Kernal, part 2 * * * ************************************************************ * Copyright 1980 by Motorola, Inc., and Microware Systems Corp., * Reproduced Under License * * This source code is the proprietary confidential property of * Microware Systems Corporation, and is provided to licensee * solely for documentation and educational purposes. Reproduction, * publication, or distribution in any form to any party other than * the licensee is strictly prohibited!! * use defsfile ***** * * Module Header * Type set SYSTM+OBJCT Revs set REENT+1 mod OS9End,OS9Nam,Type,Revs,OS9Ent,0 OS9Nam fcs /OS9p2/ ******************** * * Edition History * * Edition 6 - changes to Send routine, fixing timed sleep * 82/09/10 wake up bug LAC * * Edition 7 - changes made to "boot" subroutine, keeping the * integrity of U (a ptr to D.Base) WGP * * Edition 8 - Change made to setime system call enabling it to * call the init routine of the clock module WGP * * Edition 9 - Set boot flag to prevent loop * fcb 9 Edition number ttl Service Routine initialization table page ***** * * System Service Routine Table * SVCTBL equ * fcb $7F fdb IOHOOK-*-2 fcb F$Unlink fdb UNLINK-*-2 fcb F$WAIT fdb WAIT-*-2 fcb F$EXIT fdb EXIT-*-2 fcb F$MEM fdb USRMEM-*-2 fcb F$SEND fdb SEND-*-2 fcb F$Sleep fdb SLEEP-*-2 fcb F$ICPT fdb INTCPT-*-2 fcb F$ID fdb GETID-*-2 fcb F$SPrior fdb SETPRI-*-2 fcb F$SSWI fdb SETSWI-*-2 fcb F$STime fdb SetTime-*-2 fcb F$Find64+$80 fdb F64-*-2 fcb F$ALL64+$80 fdb A64-*-2 fcb F$Ret64+$80 fdb R64-*-2 fcb $80 ttl Cold Start routine page ***** * * Cold Start Routines * * * Initialize Service Routine Dispatch Table * OS9Ent leay SVCTBL,PCR Get ptr to service routine table OS9 F$SSVC Set service table addresses ldx D.PrcDBT Get process ptr OS9 F$ALL64 Get a process bcs COLD stx D.PrcDBT Set process block sty D.PROC tfr S,D copy stack ptr deca get page lower bound ldb #1 set page count std P$ADDR,Y set process descriptor lda #SysState Set system state sta P$State,Y ldu D.Init get configuration ptr bsr SETDIRS set default directories bcc COLD10 branch if successful lbsr BOOT Default failed, boot bsr SETDIRS try again COLD10 bsr SETSTDS open standard i/o bcc COLD20 branch if successful lbsr BOOT open failed, boot bsr SETSTDS try again COLD20 ldd InitStr,U Get initial execution string leax D,U Get string ptr lda #OBJCT set type clrb use declared memory ldy #0 No parameters OS9 F$Chain Start process COLD jmp [$FFFE] Abort start up SETDIRS clrb clear carry ldd SYSSTR,U Get system device name beq SETDIR10 Branch if none leax D,U Get name ptr lda #EXEC.+READ. Set both execution & data OS9 I$ChgDir Set default directory SETDIR10 rts SETSTDS clrb clear carry ldd STDSTR,U get name offset leax D,U get name ptr lda #UPDAT. set mode OS9 I$OPEN open file bcs SETSTD10 branch if error ldx D.PROC get process ptr sta P$PATH,X set standard input OS9 I$DUP count open image sta P$PATH+1,X set standard output OS9 I$DUP count open image sta P$PATH+2,X set standard error SETSTD10 rts ttl SERVICE Routines page ***** * * Subroutine Unlink * * Decrment Link Count. If Count Reaches Zero, * Delete Module From Directory & Return Memory * UNLINK ldd R$U,U Get module address beq UNLK25 Branch if none ldx D.ModDir Get directory ptr UNLK10 cmpd 0,X Is it this module? beq UNLK15 Branch if so leax 4,X Move to next entry cmpx D.ModDir+2 End of directory? bcs UNLK10 bra UNLK25 UNLK15 lda 2,X Get use count beq UNLK16 Branch if not used deca DOWN Link count sta 2,X bne UNLK25 Branch if still used UNLK16 ldy 0,X Get ptr to module cmpy D.BTLO Is it 'system' module? bcc UNLK25 Branch if so ldb M$TYPE,Y Get module type cmpb #FLMGR Is i/o module? bcs UNLK20 Branch if not OS9 F$IODel Delete from i/o system bcc UNLK20 inc 2,X Reset link count bra UNLK30 UNLK20 clra clrb std 0,X Clear directory entry std 0,Y Destroy id code ldd M$SIZE,Y Get module size lbsr DIV256 Divide by 256, rounding up exg D,Y Switch page count & beginning address exg A,B Make address into page number ldx D.FMBM Get bit map ptr OS9 F$DelBit Deallocate memory block UNLK25 clra CLEAR Carry UNLK30 rts page ***** * * Subroutine Wait * * Wait for Child Process to Exit * WAIT ldy D.PROC Get process ptr ldx D.PrcDBT Get process descriptor block ptr lda P$CID,Y Does process have children? bne WAIT10 Branch if so comb Set Carry ldb #E$NoChld Err: no children rts WAIT10 OS9 F$Find64 Get process ptr lda P$State,Y Get child's status bita #DEAD Is child dead? bne WAIT20 Branch if so lda P$SID,Y More children? bne WAIT10 Branch if so clr R$A,U clear child process id ldx D.PROC Get process ptr orcc #IRQMask+FIRQMask Set interrupt masks ldd D.WProcQ Put in waiting queue std P$Queue,X stx D.WProcQ lbra ZZZPRC Put process to sleep WAIT20 ldx D.PROC Get parent process ptr * * Fall Thru to Childs * ***** * * Subroutine Childs * * Return Child's Death Status to Parent * * Input: X - Parent Process ptr * Y - Child Process ptr * U - Parent Process Register ptr * CHILDS lda P$ID,Y Get process id ldb P$Signal,Y Get death status std R$D,U Return to parent pshs A,X,Y,U Save registers leay P$CID-P$SID,X Fake sibling process ptr ldx D.PrcDBT Get process descriptor block ptr bra CHIL20 CHIL10 OS9 F$Find64 Get process ptr CHIL20 lda P$SID,Y Is child next sibling? cmpa 0,S bne CHIL10 Branch if not ldu 3,S Get process ptr ldb P$SID,U Get child's sibling stb P$SID,Y Remove child from sibling list OS9 F$Ret64 Return process descriptor puls A,X,Y,U,PC page ***** * * Subroutine Exit * * Process Termination * EXIT ldx D.PROC Get process ptr ldb R$B,U Get exit status stb P$Signal,X Save status ldb #NumPaths Get number of paths leay P$PATH,X Get path table ptr EXIT10 lda ,Y+ Get next path number beq EXIT15 Branch if not in use pshs B Save path count OS9 I$Close Close the file puls B Retrieve path count EXIT15 decb COUNT Down bne EXIT10 Branch if more lda P$ADDR,X Get memory page number tfr D,U Copy it lda P$PagCnt,X OS9 F$SRtMem ldu P$PModul,X Get primary module ptr OS9 F$Unlink Unlink it ldu D.PROC Get process ptr leay P$CID-P$SID,U Fake sibling process ldx D.PrcDBT Get process descriptor block bra EXIT30 EXIT20 clr P$SID,Y Clear sibling link OS9 F$Find64 Get next process ptr lda P$State,Y Get process status bita #DEAD Is process dead? beq EXIT25 Branch if not lda P$ID,Y Return process to free OS9 F$Ret64 Return process descriptor EXIT25 clr P$PID,Y Clear parent process ptr EXIT30 lda P$SID,Y Get sibling id bne EXIT20 Branch if there is one ldx #D.WProcQ-P$Queue Fake process ptr lda P$PID,U Get parent process id bne EXIT40 Branch if parent alive ldx D.PrcDBT Get process block ptr lda P$ID,U Get process id OS9 F$Ret64 Return process descriptor bra EXIT50 EXIT35 cmpa P$ID,X Is this parent? beq EXIT45 Branch if so EXIT40 leay 0,X Copy this process ptr ldx P$Queue,X Get next process ptr bne EXIT35 Branch if there is one lda P$State,U Get process status ora #DEAD Note process death sta P$State,U Update status bra EXIT50 Wait for parent to notice EXIT45 ldd P$Queue,X Remove parent from wait list std P$Queue,Y OS9 F$AProc Put parent in active process queue leay 0,U Copy child ptr ldu P$SP,X Get parent's stack ldu R$D,U Get actual wait stack lbsr CHILDS Return child status EXIT50 clra REMOVE Process from active system clrb std D.PROC rts page ***** * * Subroutine Usrmem * * Adjust User Memory To Requested Size * USRMEM ldx D.PROC get process ptr ldd R$D,U Get size requested beq USRM35 branch if info request bsr DIV256 Divide by 256, rounding up subb P$PagCnt,X Subtract current size beq USRM35 Branch if already requested size bcs USRM20 Branch if current > requested tfr D,Y Copy pages needed ldx P$ADDR,X Get memory address & size pshs X,Y,U Save registers ldb 0,S Get address beq USRM10 Branch if none addb 1,S Get location of new USRM10 ldx D.FMBM Get free memory ptrs ldu D.FMBM+2 OS9 F$SchBit Look for memory bcs BADMEM Branch if not available stb 2,S Save page number of new ldb 0,S Get beginning of old beq USRM15 Branch if none addb 1,S Add size old cmpb 2,S Is that where new begins? bne BADMEM Branch if not USRM15 ldb 2,S Get page number of new OS9 F$AllBit Allocate memory ldd 2,S Get new address & size suba 1,S Get address of current addb 1,S Get size current puls X,Y,U ldx D.PROC Get process ptr bra USRM30 USRM20 negb GET Excess page count tfr D,Y Copy it negb GET Size requested addb P$PagCnt,X addb P$ADDR,X Get page number of excess cmpb P$SP,X Deallocating stack? bhi USRM25 Branch if not comb SET Carry ldb #E$DelSP rts USRM25 ldx D.FMBM Get free memory ptr OS9 F$DelBit Deallocate memory tfr Y,D Copy excess page count negb ldx D.PROC Get process ptr addb P$PagCnt,X Adjust page count lda P$ADDR,X Get address USRM30 std P$ADDR,X Set new address & size USRM35 lda P$PagCnt,X Get process beginning address clrb CLEAR Lsb std R$D,U Return memory size adda P$ADDR,X Return ptr to memory end std R$Y,U rts BADMEM comb SET Carry ldb #E$MemFul Err: memory full puls X,Y,U,PC ***** * * Subroutine Div256 * * Divide By 256, Rounding Up * DIV256 addd #$FF clrb ROUND Up exg A,B Divide by 256 rts page ***** * * Subroutine Send * * Send a Signal to Process(es) * SEND lda R$A,U Get destination process id bne SENSUB Branch if not all processes * * Loop thru all Process Ids, send Signal to all but Sender * inca Start with process 1 SEND10 ldx D.PROC Get process ptr cmpa P$ID,X Is this sender? beq SEND15 Branch if so bsr SENSUB Signal process SEND15 inca Get next process id bne SEND10 Branch if more clrb Clear Carry rts * * Get destination Process ptr * SENSUB ldx D.PrcDBT Get process descriptor block ptr OS9 F$Find64 Get process ptr bcc SEND20 Branch if good ldb #E$IPrcID Err: illegal process id rts * * Check Signal type * SEND20 orcc #IRQMask+FIRQMask Set interrupt masks pshs A,Y Save process id & ptr ldb R$B,U Is it unconditional abort signal? bne SEND30 Branch if not lda P$State,Y Get process status ora #CONDEM Condem process sta P$State,Y Update status * * Check for Signal collision * SEND30 lda P$Signal,Y Is signal pending? beq SEND40 Branch if not deca Is it wake-up? beq SEND40 Branch if so comb Set Carry ldb #E$USigP Err: unprocessed signal pending puls A,Y,PC SEND40 stb P$Signal,Y Save signal * * Look for Process in Sleeping Queue * ldx #D.SProcQ-P$Queue Fake process ptr bra SEND55 SEND50 cmpx 1,S Is this destination process? * *** Ed. 6 changes follow * bne SEND55 branch if not lda P$State,x get process state bita #TimSleep is process in timed sleep? beq SEND65 branch if not ldu P$SP,x get process stack ptr ldd R$X,u get remaining time beq SEND65 branch if none ldu P$Queue,x get next process in queue beq SEND65 branch if none pshs d save remaining time lda P$State,u get process state bita #TimSleep is it in timed sleep? puls d retrieve remaining time beq SEND65 branch if not ldu P$SP,u get process stack ptr addd R$X,u add remaining time std R$X,u update it bra SEND65 * *** end of Ed. 6 changes * SEND55 leay 0,X Copy process ptr ldx P$Queue,Y More in queue? bne SEND50 Branch if so * * Look for Process in Waiting Queue * ldx #D.WProcQ-P$Queue Fake process ptr SEND60 leay 0,X Copy process ptr ldx P$Queue,Y More in queue? beq SEND75 Branch if not cmpx 1,S Is this destination process? bne SEND60 Branch if not * * Move Process from it's current Queue to Active Queue * SEND65 ldd P$Queue,X Remove from queue std P$Queue,Y lda P$Signal,X Get signal deca Is it wake-up? bne SEND70 Branch if not sta P$Signal,X Clear signal SEND70 OS9 F$AProc Put in active queue SEND75 clrb Clear carry puls A,Y,PC page ***** * * Subroutine Sleep * * Suspend Process * SLEEP ldx D.PROC Get current process orcc #IRQMask+FIRQMask Set interrupt mask lda P$Signal,X Signal waiting? beq SLEP20 Branch if not CKSIGN deca IS It wake-up? bne SLEP10 Branch if not sta P$Signal,X Clear signal SLEP10 OS9 F$AProc Put process in active queue bra ZZZPRC Suspend process SLEP20 ldd R$X,U Get length of sleep beq SLEP50 Branch if indefinite subd #1 count current tick std R$X,U update count beq SLEP10 branch if done pshs X,U Save process & register ptr ldx #D.SProcQ-P$Queue Fake process ptr SLEP30 leay 0,X Copy process ptr ldx P$Queue,X Get next process beq SLEP40 Branch if end of queue pshs D Save sleep time lda P$State,X Get process status bita #TimSleep In timed sleep? puls D Retrieve sleep time beq SLEP40 Branch if not timed sleep ldu P$SP,X Get process stack ptr subd R$X,U Subtract sleep time bcc SLEP30 Branch if not greater addd R$X,U Fix sleep time SLEP40 puls X,U Retrieve process & register ptr std R$X,U Set time to sleep ldd P$Queue,Y Put process in queue stx P$Queue,Y std P$Queue,X lda P$State,X Set timed sleep status ora #TimSleep sta P$State,X ldx P$Queue,X Get next process ptr beq ZZZPRC lda P$State,X Get status bita #TimSleep In timed sleep? beq ZZZPRC Branch if not ldx P$SP,X Get stack ptr ldd R$X,X Get sleep time subd R$X,U Subtract new sleep std R$X,X Update sleep time bra ZZZPRC SLEP50 lda P$State,X Get status anda #$FF-TimSleep Set not timed sleep sta P$State,X ldd #D.SProcQ-P$Queue Fake process ptr SLEP60 tfr D,Y Copy process ptr ldd P$Queue,Y Get next process ptr bne SLEP60 Branch if one exists stx P$Queue,Y Link into queue std P$Queue,X * * Fall Thru To Zzzprc * ***** * * Subroutine Zzzprc * * Deactivate Process, Start Another * ZZZPRC leay <WAKPRC,PCR Get wakeup address pshs Y Make new pc ldy D.PROC Get process ptr ldd P$SP,Y Get process stack ldx R$X,U Get sleep time (if any) pshs CC,D,DP,X,Y,U Make new stack sts P$SP,Y Note location OS9 F$NProc Start another process WAKPRC std P$SP,Y Restore previous stack stx R$X,U Return sleep time clrb CLEAR Carry rts page ***** * * Subroutine Intcpt * * Signal Intercept Handler * INTCPT ldx D.PROC Get process ptr ldd R$X,U Get vector std P$SigVec,X Save it ldd R$U,U Get data address std P$SigDat,X Save it clrb CLEAR Carry rts ***** * * Subroutine Setpri * * Set Process Priority * SETPRI lda R$A,U Get process id ldx D.PrcDBT Get process block ptr OS9 F$Find64 Find process descriptor bcs SETP10 ldx D.PROC Get setting process ptr ldd P$USER,X Get setting user cmpd P$USER,Y Same as set user? bne SETP10 Branch if not lda R$B,U Get priority sta P$Prior,Y Set priority rts SETP10 comb SET Carry ldb #E$IPrcID Err: illegal process id rts ***** * * Subroutine Getid * GETID ldx D.PROC Get process ptr lda P$ID,X Get process id sta R$A,U Return to user ldd P$USER,X Get user index std R$Y,U Return to user clrb rts page ***** * * Subroutine Setswi * * Set Software Interrupt Vectors * SETSWI ldx D.PROC Get process ptr leay P$SWI,X Get ptr to vectors ldb R$A,U Get swi code decb ADJUST Range cmpb #3 Is it in range bcc SSWI10 Branch if not aslb ldx R$X,U stx B,Y rts SSWI10 comb ldb #E$ISWI rts ********** * * Subroutine Settime * ClockNam fcs "Clock" SetTime ldx R$X,U get date ptr ldd 0,X get year & month std D.YEAR ldd 2,X get day & hour std D.DAY ldd 4,X get minute & second std D.MIN lda #SYSTM+OBJCT leax <ClockNam,PCR OS9 F$Link link to clock module bcs SeTime99 jmp 0,Y execute clock's initialization clrb SeTime99 rts page *************** * Findpd * Find Address Of Path Descriptor Or Process Descriptor * * Calling Seq: (A)=Pd Number * (X)=Pd Table Addr * Returns: (Y)=Addr Of Pd * Cc=Set If Pd Is Not Owned By Caller * Destroys: B,Cc * F64 lda R$A,U Get block number ldx R$X,U Get block ptr bsr FINDPD Find block bcs F6410 sty R$Y,U F6410 rts FINDPD pshs D Save registers tsta LEGAL Number? beq FPDERR ..yes; error clrb lsra rorb lsra rorb DIVIDED By 4 pd's per pd block lda A,X Map into high order pd address tfr D,Y (y)=address of path descriptor beq FPDERR Pd block not allocated! tst 0,Y Is pd in use? bne FINDP9 Allocated pd, good! FPDERR coma ERROR - return carry set FINDP9 puls D,PC Return page *************** * Aloc64 * Allocate Path Descriptor (64 Bytes) * * Passed: X=Pdbt, Path Descriptor Block Table Addr * Returns: A=Path Number * Y=Pd Address * Cc=Set If Unable To Allocate * B=Error Code If Unable To Allocate * Destroys: B * A64 ldx R$X,U Get block ptr bne A6410 Branch if set bsr A64ADD Add a page bcs A6420 Branch if error stx 0,X Init block stx R$X,U Return block ptr A6410 bsr ALOC64 Alocate block bcs A6420 sta R$A,U Return block number sty R$Y,U Return block ptr A6420 rts A64ADD pshs U Save register ptr ldd #$100 Get a page OS9 F$SRqMem leax 0,U Copy page ptr puls U Retrieve register ptr bcs A64A20 Branch if no memory clra clrb A64A10 sta D,X Clear page incb bne A64A10 A64A20 rts ALOC64 pshs X,U clra ALCPD1 pshs A Save index of pd block clrb lda A,X beq ALPD12 Empty block (not found) tfr D,Y (y)=address of pd block clra ALPD11 tst D,Y Available pd? beq ALPD13 ..yes addb #PDSIZE Skip to next pd bcc ALPD11 Repeat until end of pd block ALPD12 orcc #CARRY Set carry - not found ALPD13 leay D,Y Get address of path descriptor puls A Restore pd block index bcc ALCPD4 Found a pd, return it inca SKIP To next pd block cmpa #PDSIZE Last one checked? blo ALCPD1 ..no; keep looking clra ALCPD2 tst A,X Search for an unused pdb beq ALCPD3 ..found one inca SKIP To next cmpa #PDSIZE All tried? blo ALCPD2 ..no; keep looking ldb #E$PthFul No available path coma RETURN Carry set - error bra ALCPD9 Return ALCPD3 pshs A,X bsr A64ADD Add a page bcs ALCPDR Allocate error leay 0,X Set up pd address as first pd in block tfr X,D tfr A,B (b)=page address of new pd block puls A,X * (A)=Pdbt Index, (X)=Pdbt stb A,X clrb * * A=Index Into Pdbt Of Pdb Containing Pd * B=Low Order Address Of Pd In Pdb * Y=Address Of Pd * ALCPD4 aslb FORM Path number rola aslb rola ldb #PDSIZE-1 ALCPD5 clr B,Y decb bne ALCPD5 Clear out fresh path descriptor sta PD.PD,Y Set pd# in pd (indicates in use) ALCPD9 puls X,U,PC Return carry clear ALCPDR leas 3,S Return not enough memory error puls X,U,PC Return *************** * Rtrn64 * Return Path Descriptor To Free Status * * Passed: (A)=Path Number * (X)=D.Pdbt Path Descriptor Block Table Addr * Returns: None * Destroys: Cc * R64 lda R$A,U Get block number ldx R$X,U Get block ptr RTRN64 pshs D,X,Y,U Save registers clrb lsra rorb lsra PATH # rorb DIVIDED By 4 pd's per block pshs A Save a lda A,X beq RTRNP9 Impossible path number - return tfr D,Y Get address of pd clr 0,Y Mark it as unused clrb tfr D,U Get address of pdb in which pd lies clra RTRNP1 tst D,U Pd in use? bne RTRNP9 ..yes; return addb #PDSIZE bne RTRNP1 Repeat for each pd in block inca (D)=$0100 OS9 F$SRtMem Return (unused) pdb to system store lda 0,S clr A,X Mark pd unused RTRNP9 clr ,S+ Return scratch with carry clear puls D,X,Y,U,PC Return to caller ttl BOOTSTRAP Routines page ***** * * Subroutine Iohook * * Handles Locating/Loading Remainder Of System * * Input: Y - Service Dispatch Table ptr * IOSTR fcb 'I,'O,'M,'A,'N+$80 IOHOOK pshs D,X,Y,U Save registers ldu D.Init bsr IOLink Link ioman bcc IOHOOK10 bsr BOOT Ioman not found, boot bcs IOHOOK20 bsr IOLink Link ioman again bcs IOHOOK20 IOHOOK10 jsr 0,Y Call ioman init puls D,X,Y,U Retrieve registers ldx -2,Y Get ioman entry jmp 0,X IOHOOK20 puls D,X,Y,U,PC IOLink leax IOSTR,PCR Get ioman name ptr lda #SYSTM+OBJCT Get type OS9 F$LINK rts BOOT pshs U save D.Init ptr comb set carry tst D.Boot bne BOOTXX Don't boot if already tried inc D.Boot ldd BOOTSTR,U Get default device string beq BOOTXX Can't boot without device leax D,U Get name ptr lda #SYSTM+OBJCT get type OS9 F$LINK find bootstrap module bcs BOOTXX Can't boot without module jsr 0,Y Call boot entry bcs BOOTXX Boot failed stx D.MLIM Set memory limit stx D.BTLO Set boot area low limit leau D,X Make boot area high limit stu D.BTHI BOOT10 ldd 0,X get module beginning cmpd #M$ID12 is it module sync code? bne BOOT20 branch if not OS9 F$VModul Validate module bcs BOOT20 ldd M$SIZE,X Get module size leax D,X Skip module bra BOOT30 BOOT20 leax 1,X Try next BOOT30 cmpx D.BTHI End of boot? bcs BOOT10 Branch if not BOOTXX puls U,PC Restore ptr and return emod OS9End equ * ttl Configuration Module page ***** * * Configuration Module * Type set SYSTM mod ConEnd,ConNam,Type,Revs fcb 0 no extended memory fdb $F800 High free memory bound fcb 12 Entries in interrupt polling table fcb 12 Entries in device table fdb ModNam Initial module name fdb DirNam Default directory name fdb TermNam Standard i/o device name fdb BootNam Bootstrap module name ConNam fcs "Init" ModNam fcs "SysGo" DirNam fcs "/D0" TermNam fcs "/Term" BootNam fcs "Boot" emod ConEnd equ * end