; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; TTL => Kernel : SWI Despatch, simple SWIs SUBT Arthur Variables OPT 4 ; ----------------------------------------------------------------------------- ; ; mjs Oct 2000 kernel/HAL split ; ; macros that can be switched between doing real HAL calls and pseudo ; HAL calls with r9-> mjs pseudo HAL workspace ; ; these have been handy for interim HALising of kernel code in-situ ; (particularly used for video stuff), but can probably disappear later ; [ HAL MACRO mjsAddressHAL $zero AddressHAL $zero MEND MACRO mjsCallHAL $rout CallHAL $rout MEND MACRO DebugTX $str [ DebugHALTX BL DebugHALPrint = "$str", 0 ALIGN ] MEND | MACRO mjsAddressHAL LDR r9, =mjs_tempHALworkspace LDR r9, [r9] ; sb -> pseudo HAL workspace MEND MACRO mjsCallHAL $rout BL $rout MEND ] ;HAL ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; handy macros: ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ MACRO $l CheckSpaceOnStack $space, $faildest, $tmp [ True ; SKS $l MOV $tmp, sp, LSR #15 ; Stack base on 32K boundary SUB $tmp, sp, $tmp, LSL #15 ; Amount of stack left CMP $tmp, #$space ; Must have at least this much left BMI $faildest | $l MOV $tmp, #32*1024 ; assume stack ends at next 32K boundary SUB $tmp, $tmp, #1 AND $tmp, $tmp, stack CMP $tmp, #$space BLT $faildest ] MEND MACRO assert $condition [ :LNOT: ($condition) ! 1,"Assert failed: $condition" ] MEND ; ************************************** ; *** BYTEWS - Point to OsbyteVars *** ; ************************************** MACRO $label BYTEWS $reg $label LDR $reg,=ZeroPage+OsbyteVars MEND ; *************************************** ; *** LDROSB - Load Osbyte variable *** ; *************************************** MACRO $label LDROSB $reg, $var, $cond $label LDR$cond $reg, =ZeroPage LDR$cond.B $reg, [$reg, #OsbyteVars+$var-OSBYTEFirstVar] MEND ; **************************************** ; *** STROSB - Store Osbyte variable *** ; **************************************** MACRO $label STROSB $reg, $var, $temp, $cond $label LDR$cond $temp, =ZeroPage STR$cond.B $reg, [$temp, #OsbyteVars+$var-OSBYTEFirstVar] MEND ; **************************************************** ; *** VDWS - Point to our new VduDriverWorkSpace *** ; **************************************************** MACRO $label VDWS $reg $label LDR $reg, =ZeroPage+VduDriverWorkSpace MEND ; one that builds a module command table entry: ; set Module_BaseAddr to module base before use. GBLA Module_BaseAddr Module_BaseAddr SETA 0 ; Command $cmd, $max, $min - declared in hdr.macros. ; debug macro: set the border colour MACRO $l SetBorder $reg1, $reg2, $red, $green, $blue, $delay ! 0, "Setborder used" $l LDR $reg1, =VIDC ; Note $reg, $green and $blue are 4 bit values LDR $reg2, =&40000000+(($red)*&11)+(($green)*&1100)+(($blue)*&110000) STR $reg2, [$reg1] [ "$delay"<>"" MOV $reg1, #$delay 10 SUBS $reg1, $reg1, #1 BNE %BT10 ] MEND ; Fake a 26-bit pc, given a PSR currently in lr (or reg), and the 32-bit address on ; the stack. The stacked address is pulled, and the result is left in lr. MACRO FakeLR $temp, $dontpull, $reg [ "$reg" = "" AND $temp,lr,#&F0000003 | AND $temp,$reg,#&F0000003 ] AND lr,lr,#I32_bit+F32_bit ORR $temp,$temp,lr,LSL #IF32_26Shift [ "$dontpull" = "dontpull" LDR lr,[sp] | LDR lr,[sp],#4 ] BIC lr,lr,#ARM_CC_Mask ORR lr,lr,$temp MEND ; [ AddTubeBashers [ TubeType = Tube_Normal DebugTUBE * &03340000+3*&4000 ; tube in podule #3 ; Tube register offsets ^ 0 R1STAT # 4 R1DATA # 4 | DebugTUBE * &03000000 ; simulator tube address R1DATA * 0 ] ] ; routine to stuff a char down the Tube ; should be inside above conditional, but AAsm winges pitifully. MACRO $l TubeChar $reg1, $reg2, $charset, $stackthere ! 0, "TubeChar used." $l [ "$stackthere"="" Push "$reg1, $reg2" ] LDR $reg1, =DebugTUBE [ TubeType = Tube_Normal ; normal tubes have status register, simulator one doesn't 01 LDRB $reg2, [$reg1, #R1STAT] TST $reg2, #&40 BEQ %BT01 ] $charset STRB $reg2, [$reg1, #R1DATA] [ "$stackthere"="" Pull "$reg1, $reg2" ] MEND MACRO $l TubeString $reg1, $reg2, $reg3, $string, $cc LDR $reg1, =DebugTUBE ADR $reg2, %FT20 10 [ TubeType = Tube_Normal LDRB $reg3, [$reg1, #R1STAT] TST $reg3, #&40 BEQ %BT10 ] LDRB $reg3, [$reg2], #1 TEQ $reg3, #0 STRNEB $reg3, [$reg1, #R1DATA] BNE %BT10 B %FT30 20 = "$string" [ "$cc" = "" = 10, 13 ] = 0 ALIGN 30 MEND MACRO $l TubeDumpNoStack $dump, $t1, $t2, $t3 $l MOV $t1, #7 01 ADRL $t2, HexTable TubeChar $t3, $t2, "LDRB $t2, [$t2, $dump, LSR #28]", NoStack MOV $dump, $dump, ROR #28 SUBS $t1, $t1, #1 BPL %BT01 TubeChar $t3, $t2, "MOV $t2, #"" """, NoStack MEND MACRO $l TubeNewlNoStack $t1, $t2 $l TubeChar $t1, $t2, "MOV $t2, #10", NoStack TubeChar $t1, $t2, "MOV $t2, #13", NoStack MEND a1 RN 0 a2 RN 1 a3 RN 2 a4 RN 3 v1 RN 4 v2 RN 5 v3 RN 6 v4 RN 7 v5 RN 8 v6 RN 9 sb RN 9 v7 RN 10 v8 RN 11 ; Set sb up ready for CallHAL. MACRO AddressHAL $zero [ "$zero" <> "" LDR sb, [$zero, #HAL_Workspace] | LDR sb, =ZeroPage LDR sb, [sb, #HAL_Workspace] ] MEND ; Calls the HAL. $rout is the routine. sb must have been set up by AddressHAL MACRO CallHAL $rout, $cond MOV$cond lr, pc LDR$cond pc, [sb, #-(EntryNo_$rout+1) * 4] MEND ; Checks whether a HAL routine exists. If it does, a1 points to it (probably ; not useful), and Z is clear. lr corrupted. MACRO CheckHAL $rout LDR a1, [sb, #-(EntryNo_$rout+1) * 4] ADRL lr, NullHALEntry TEQ a1, lr MEND ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Various constants ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ PageSize * (4*1024) ;MMU page size (normal pages) Log2PageSize * 12 ;for shifts MinAplWork * 40*1024 ; minimum size of AplWork ; Fixed addresses MEMCADR * &03600000 GBLL ROMatTop [ HAL32 :LAND: {TRUE} ROM * &FC000000 ROMatTop SETL {TRUE} | ROM * &03800000 ROMLimit * &04000000 ] OSMD * &11111111 VideoPhysRam * &02000000 ; Amazing - it's in the same place! DRAM0PhysRam * &10000000 ; 4 DRAM banks DRAM1PhysRam * &14000000 DRAM2PhysRam * &18000000 DRAM3PhysRam * &1C000000 DRAMBaseAddressMask * &1C000000 ; used to mask off bits after stealing video RAM PhysSpaceSize * &20000000 ; IOMD physical map is 512M big PhysROM * &00000000 ; and real ROM starts at 0 [ STB PhysExtROM * &01000000 ; 2nd ROM bank starts at 16M ] SAMLength * 512*4 ; SAM length in bytes for 1 bank of VRAM [ :LNOT: HAL EASISpacePhys * &08000000 EASISpace * PhysSpace + EASISpacePhys ] ; Manifests CR * 13 LF * 10 space * " " ; Registers SPIRQ RN R13 ; Callback byte bits: CBack_OldStyle * 1 CBack_Postpone * 2 CBack_VectorReq * 4 ; Set up symbols for the SWIs which aren't really there yet SUBT Arthur Code OPT 4 [ HAL ORG ROM + OSROM_HALSize | ORG ROM ] AREA |!!!!OSBase|,CODE,READONLY ENTRY ; Not really, but we need it to link KernelBase ; ***************************************************************************** ; ; Now ready to start the code: off we go! ; ; ***************************************************************************** [ HAL ; ORG ROM + OSROM_HALSize | ; ORG ROM ] GBLS DoMorrisROMHeader GBLS DoTestThings DoMorrisROMHeader SETS "" DoTestThings SETS "" [ HAL ; BIN HAL.L7200.HAL ; RISC OS image header RISCOS_Header = "OSIm" DCD 0 DCD OSROM_ImageSize*1024 - OSROM_HALSize DCD RISCOS_Entries - RISCOS_Header DCD (RISCOS_Entries_End - RISCOS_Entries) / 4 RISCOS_Entries DCD RISCOS_InitARM - RISCOS_Entries DCD RISCOS_AddRAM - RISCOS_Entries DCD RISCOS_Start - RISCOS_Entries DCD RISCOS_MapInIO - RISCOS_Entries DCD RISCOS_AddDevice - RISCOS_Entries DCD RISCOS_LogToPhys - RISCOS_Entries DCD RISCOS_IICOpV - RISCOS_Entries RISCOS_Entries_End | [ MorrisSupport DoMorrisROMHeader SETS " GET s.Morris" ] ; now include the test code, if there is any [ IncludeTestSrc DoTestThings SETS " GET TestSrc.Begin" ] $DoTestThings [ IncludeTestSrc DoMorrisROMHeader SETS "" ] $DoMorrisROMHeader ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; If there is no test code then we want a branch table at the start of ROM to ; handle reset and any aborts etc. in the reset code. ; If MorrisSupport we've already generated 16/32 ROM entry code, so skip this bit [ :LNOT: IncludeTestSrc :LAND: :LNOT: MorrisSupport :LAND: :LNOT: HAL LDR pc, .+ResetIndirection ; load PC, PC relative B UndInstInReset B SWIInReset B PrefAbInReset B DataAbInReset B AddrExInReset B IRQInReset UndInstInReset SUB pc, pc, #8 SWIInReset SUB pc, pc, #8 PrefAbInReset SUB pc, pc, #8 DataAbInReset SUB pc, pc, #8 AddrExInReset SUB pc, pc, #8 IRQInReset SUB pc, pc, #8 ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This bit (up to EndFiq) is copied to location 0. Processor vectors are ; indirected through 0 page locations so that they can be claimed using ; OS_ClaimProcessorVector. IRQs are initially handled specially so that the ; keyboard can be handled during reset but the load is replaced with the ; standard one later on. MOSROMVecs LDR pc, MOSROMVecs+ProcVec_Branch0 LDR pc, MOSROMVecs+ProcVec_UndInst LDR pc, MOSROMVecs+ProcVec_SWI LDR pc, MOSROMVecs+ProcVec_PrefAb LDR pc, MOSROMVecs+ProcVec_DataAb LDR pc, MOSROMVecs+ProcVec_AddrEx LDR pc, MOSROMVecs+InitIRQHandler EndMOSROMVecs ASSERT InitIRQHandler >= EndMOSROMVecs - MOSROMVecs ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This is the table of default processor vectors which is copied to 0 page. DefaultProcVecs & Branch0_NoTrampoline & UndPreVeneer & SVC & PAbPreVeneer & DAbPreVeneer & AdXPreVeneer & Initial_IRQ_Code ASSERT (.-DefaultProcVecs) = ProcVec_End-ProcVec_Start ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; These are preveneers which must be copied to 0 page locations so that the ; relevant handler can be branched to. This is mainly for non-ARM600 platforms ; although the address exception preveneer (which should not actually be required ; on ARM600) is always copied. DefaultPreVeneers [ No26bitCode UndPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) LDR PC, DefaultPreVeneers-ProcVecPreVeneers+UndHan [ ChocolateAMB DCD 0 | PAbPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) LDR PC, DefaultPreVeneers-ProcVecPreVeneers+PAbHan ] DCD 0 | DCD 0 DCD 0 DCD 0 ] AdXPreVeneer * ProcVecPreVeneers+(.-DefaultPreVeneers) LDR PC, DefaultPreVeneers-ProcVecPreVeneers+AdXHan ASSERT (.-DefaultPreVeneers) = ProcVecPreVeneersSize ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This is the trampoline in the system heap used to handle branch through 0. Branch0_Trampoline STR r1, Branch0_Trampoline + Branch0_Trampoline_SavedR1 STR lr, Branch0_Trampoline + Branch0_Trampoline_SavedR14 ADD lr, pc, #4 LDR pc, .+4 & Branch0_FromTrampoline Branch0_Trampoline_Init * .-Branch0_Trampoline Branch0_Trampoline_SavedR1 * .-Branch0_Trampoline Branch0_Trampoline_SavedR14 * .-Branch0_Trampoline+4 Branch0_Trampoline_Size * .-Branch0_Trampoline+8 [ :LNOT: IncludeTestSrc :LAND: :LNOT: HAL ; We now waste space until the offset into the ROM is the same as the RAM address of ResetIndirection ; This is so that ; a) on a reset, ROM is paged in at the bottom, so we jump to CONT, and ; b) on a break, RAM is paged in at the bottom, so we jump to CONT_Break ASSERT .-ROM <= ResetIndirection % ResetIndirection-(.-ROM) & CONT-ROM+PhysROM ; address of reset code in physical space ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Now some initialised workspace/vectors that go at &100 ; All the stuff from here to after the DirtyBranch instruction is read ; consecutively out of ROM, so don't put anything in between without changing ; the code StartData ASSERT IRQ1V = &100 & DefaultIRQ1V ASSERT ESC_Status = IRQ1V+4 & &00FF0000 ; IOCControl set to FF on reset ASSERT IRQsema = ESC_Status+4 & 0 EndData ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI return handler: checks callback ; no branches or interlocks in the common case: V clear, no callback SVCDespatcher ROUT SWIRelocation * SVCDespatcher-SWIDespatch SLVK_SetV * {PC}-SWIRelocation ORR lr, lr, #V_bit SLVK_TestV * {PC}-SWIRelocation ! 0,"SLVK_TestV at ":CC:(:STR:SLVK_TestV) ORRVS lr, lr, #V_bit SLVK * {PC}-SWIRelocation ! 0,"SLVK at ":CC:(:STR:SLVK) Local_SLVK LDR r12, [sp], #4 [ ZeroPage = 0 MOV r10, #0 | LDR r10, SWIRelocationZeroPage ] [ FixCallBacks MSR CPSR_c, #I32_bit + SVC32_mode ; IRQs off makes CallBackFlag atomic; 32bit so ready for SPSR use ] LDRB r11, [r10, #CallBack_Flag] TST lr, #V_bit BNE %FT50 SWIReturnWithCallBackFlag * {PC}-SWIRelocation ! 0,"SWIReturnWithCallBackFlag at ":CC:(:STR:SWIReturnWithCallBackFlag) 40 TEQ r11, #0 [ :LNOT: FixCallBacks MSREQ CPSR_c, #I32_bit + SVC32_mode ; IRQs off for SPSR use ] MSREQ SPSR_cxsf, lr LDREQ lr, [sp], #4 Pull "r10-r12", EQ MOVEQS pc, lr B callback_checking + SWIRelocation ! 0,"VSetReturn at ":CC:(:STR:({PC}-SWIRelocation)) 50 TST r12, #Auto_Error_SWI_bit [ FixCallBacks BNE callback_checking + SWIRelocation ; we need to do this for X errors even if the callback flags ; are all clear, so that the postpone flag can be set | BNE %BT40 ] B VSet_GenerateError + SWIRelocation [ ZeroPage <> 0 SWIRelocationZeroPage DCD ZeroPage ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; The SWI Despatch routine SVC * {PC}-SWIRelocation Push "r10-r12" [ No26bitCode MRS r12, SPSR ; r12 = saved PSR TST r12, #T32_bit ; depending on processor state (ARM/Thumb) LDREQ r11, [r14, #-4] ; extract SWI number to r11 LDRNEB r11, [r14, #-2] ; (ordering to prevent interlocks) BICEQ r11, r11, #&FF000000 | LDR r11, [r14, #-4] ; extract SWI number to r11 MRS r12, SPSR ; r12 = saved PSR BIC r11, r11, #&FF000000 ; (ordering to prevent interlocks) ] Push "r11,r14" ; push SWI number and return address AND r10, r12, #I32_bit+F32_bit ORR r10, r10, #SVC2632 ; set IFTMMMMM = IF0x0011 MSR CPSR_c, r10 ; restore caller's IRQ state BIC r14, r12, #V_bit ; clear V (some SWIs need original PSR in r12) SVC_CallASWI * {PC}-SWIRelocation ; CallASWI,CallASWIR12 re-entry point BIC r11, r11, #Auto_Error_SWI_bit CMP r11, #OS_WriteI LDRLO pc, [pc, r11, LSL #2] B NotMainMOSSwi + SWIRelocation ASSERT {PC}-SVCDespatcher = SWIDespatch_Size ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; The SWI table JTABLE & SWIWriteC & SWIWriteS & SWIWrite0 & SWINewLine ; next section is one where VectorNumber = SWINumber & VecSwiDespatch ; readc & VecSwiDespatch ; cli & NoIrqVecSwiDespatch ; byte & NoIrqVecSwiDespatch ; word & VecSwiDespatch ; file & VecSwiDespatch ; args & BGetSWI ; bget & BPutSWI ; bput & VecSwiDespatch ; gbpb & VecSwiDespatch ; find [ No26bitCode & ReadLineSWI | & VecSwiDespatch ; readline ] & SCTRL & SWI_GetEnv_Code & SEXIT & SSTENV & SINTON & SINTOFF & SCALLB & SENTERSWI & SBRKPT & SBRKCT & SUNUSED & SSETMEMC & SSETCALL & VecMouse & HeapEntry & ModuleHandler & ClaimVector_SWICode & ReleaseVector_SWICode & ReadUnsigned_Routine & GenEvent & ReadVarValue & SetVarValue & GSINIT & GSREAD & GSTRANS & CvtToDecimal & FSControlSWI & ChangeDynamicSWI & GenErrorSWI & ReadEscapeSWI & ReadExpression & SwiSpriteOp & SWIReadPalette & Issue_Service_SWI & SWIReadVduVariables & SwiReadPoint & DoAnUpCall & CallAVector_SWI & SWIReadModeVariable & SWIRemoveCursors & SWIRestoreCursors & SWINumberToString_Code & SWINumberFromString_Code & ValidateAddress_Code & CallAfter_Code & CallEvery_Code & RemoveTickerEvent_Code & InstallKeyHandler & SWICheckModeValid & ChangeEnvironment & SWIClaimScreenMemory & ReadMetroGnome & XOS_SubstituteArgs_code & XOS_PrettyPrint_code & SWIPlot & SWIWriteN & Add_ToVector_SWICode & WriteEnv_SWICode & RdArgs_SWICode & ReadRAMFSLimits_Code & DeviceVector_Claim & DeviceVector_Release & Application_Delink & Application_Relink & HeapSortRoutine & TerminateAndSodOff & ReadMemMapInfo_Code & ReadMemMapEntries_Code & SetMemMapEntries_Code & AddCallBack_Code & ReadDefaultHandler & SWISetECFOrigin & SerialOp & ReadSysInfo_Code & Confirm_Code & SWIChangedBox & CRC_Code & ReadDynamicArea & SWIPrintChar & ChangeRedirection & RemoveCallBack & FindMemMapEntries_Code & SWISetColour & NoSuchSWI ; Added these to get round OS_ClaimSWI and & NoSuchSWI ; OS_ReleaseSWI (should not have been allocated here). [ AssemblePointerV & PointerSWI | & NoSuchSWI ] & ScreenModeSWI & DynamicAreaSWI & NoSuchSWI ; OS_AbortTrap & MemorySWI [ ProcessorVectors & ClaimProcVecSWI | & NoSuchSWI ] & PerformReset & MMUControlSWI [ STB & NoSuchSWI | & ResyncTimeSWI ] [ StrongARM & PlatFeatSWI & SyncCodeAreasSWI & CallASWI & AMBControlSWI & CallASWIR12 | & NoSuchSWI & NoSuchSWI & NoSuchSWI & NoSuchSWI & NoSuchSWI ] ; The following SWIs are not available in this kernel. & NoSuchSWI ; SpecialControl & NoSuchSWI ; EnterUSR32SWI & NoSuchSWI ; EnterUSR26SWI ; End of unavailable SWIs. ; Should not cause any problems on any machine. STB flag just to be safe though. [ STB :LAND: {FALSE} & VIDCDividerSWI | ! 0, "mjsHAL - VIDCDividerSWI not implemented" & NoSuchSWI ] & NVMemorySWI & NoSuchSWI & NoSuchSWI & NoSuchSWI & HardwareSWI & IICOpSWI & SLEAVESWI & ReadLine32SWI & XOS_SubstituteArgs32_code & HeapSortRoutine32 ASSERT (.-JTABLE)/4 = MaxSwi ASSERT MaxSwi < OS_ConvertStandardDateAndTime ; SWIs for time/date conversion are poked in specially ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; The fudge branch to exit a dirty SWI handler DirtyBranch B SLVK +DirtyBranch-BranchToSWIExit ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ [ StrongARM ;StrongARM needs these ;SWI number passed in r10 CallASWI ROUT LDR r11, [sp, #8] ;pick-up target SWI code (r10 pushed by dispatcher) BIC r11, r11, #&FF000000 ;just in case STR r11, [sp, #0] ;CallASWI now incognito as target SWI B SVC_CallASWI ;re-dispatch ;SWI number passed in r12 (better for C veneers) CallASWIR12 ROUT LDR r11, [sp, #16] ;pick-up target SWI code (r12 pushed by dispatcher) BIC r11, r11, #&FF000000 ;just in case STR r11, [sp, #0] ;CallASWIR12 now incognito as target SWI B SVC_CallASWI ;re-dispatch ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; In return address, r10-r12 stacked, lr has SPSR for return VSet_GenerateError ROUT Push lr [ FixCallBacks BIC lr, lr, #&0F ORR lr, lr, #SVC_mode MSR CPSR_c, lr ; Set caller's interrupt state and 26/32bitness ] MOV r1, #Service_Error BL Issue_Service MOV r10, #ErrorV BL CallVector ; Normally gets to default handler... Pull lr ; which raises error; otherwise just BIC lr, lr, #V_bit ; return with V clear: error claimed! LDR r10, =ZeroPage ; set up r10 and r11 as required [ FixCallBacks MSR CPSR_c, #I32_bit + SVC32_mode ; IRQs off makes CallBackFlag atomic; 32bit so ready for SPSR use ] LDRB r11, [r10, #CallBack_Flag] B SWIReturnWithCallBackFlag LTORG ; ....................... default owner of ErrorV ............................. ; In r0 -> error in current error block ; Out Exits to user's error handler routine as given by ErrHan ; r1-r9 possibly corrupt. Indeed r10-r12 MAY be duff ... eg. REMOTE ErrHandler ROUT BL OscliTidy ; close redirection, restore curr FS LDR r10, =ZeroPage LDR r11, [r10, #ErrBuf] ; Get pointer to error buffer [ No26bitCode LDR sp_svc, =SVCSTK-4*4 ; Just below top of stack Pull r14 STR r14, [r11], #4 ; Return PC for error | LDR sp_svc, =SVCSTK-5*4 ; Just below top of stack Pull r14 ; PSR will be on stack if error at top level FakeLR r12 ; Fake up the PC+PSR STR r14, [r11], #4 ] LDR r14, [r0], #4 ; Copy error number STR r14, [r11], #4 ; Copy error string - truncating at 252 MOV r12, #256-4 10 LDRB r14, [r0], #1 SUBS r12, r12, #1 MOVLS r14, #0 STRB r14, [r11], #1 TEQ r14, #0 BNE %BT10 LDR r14, [r10, #ErrHan] ; And go to error handler [ :LNOT: No26bitCode BIC r14, r14, #ARM_CC_Mask ] STR r14, [r10, #Curr_Active_Object] LDR r0, [r10, #ErrHan_ws] ; r0 is his wp [ :LNOT: FixCallBacks LDRB r11, [r10, #CallBack_Flag] CMP r11, #0 ] MRS r12, CPSR BIC r12, r12, #I32_bit+F32_bit+&0F ; USR26/32 mode, ARM, IRQs enabled [ FixCallBacks MSR CPSR_c, #I32_bit+SVC32_mode ; disable interrupts for SPSR use and CallBackFlag atomicity LDRB r11, [r10, #CallBack_Flag] CMP r11, #0 | MSREQ CPSR_c, #I32_bit+SVC32_mode ; disable interrupts for SPSR use ] MSREQ SPSR_cxsf, r12 Pull "r10-r12", EQ MOVEQS pc, r14 ; USR mode, IRQs enabled Push r14 ; Stack return address MOV r14, r12 ; Put PSR in R14 B Do_CallBack ; Can't need postponement, r0,r14,stack ; such that callback code will normally ; call error handler ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; check for CallBack possible callback_checking TST lr, #I32_bit+&0F ; user 26/32 mode, ints enabled? [ :LNOT: FixCallBacks ; already entered with this CPSR MSRNE CPSR_c, #I32_bit + SVC32_mode ] MSRNE SPSR_cxsf, lr LDRNE lr, [sp], #4 Pull "r10-r12", NE MOVNES pc, lr ; Skip the branch for SVC code speed ; Further checks: postpone callback if returning V set and R0->RAM TST lr, #V_bit ; if no error then do callbacks BEQ Do_CallBack TST r11, #CBack_Postpone [ FixCallBacks TSTNE r11, #CBack_OldStyle :OR: CBack_VectorReq ; can only postpone if not already or if no callbacks pending ] BNE Do_CallBack [ ROMatTop CMP r0, #ROM BHS Do_CallBack | CMP r0, #ROM RSBHIS r12, r0, #ROMLimit BHI Do_CallBack ] [ :LNOT: FixCallBacks MSR CPSR_c, #I32_bit + SVC32_mode ; ints off while flag updated LDRB r11, [r10, #CallBack_Flag] ] ORR r11, r11, #CBack_Postpone ; signal to IRQs STRB r11, [r10, #CallBack_Flag] back_to_user [ :LNOT: FixCallBacks ; already entered with this CPSR MSR CPSR_c, #I32_bit + SVC32_mode ] back_to_user_irqs_already_off MSR SPSR_cxsf, lr LDR lr, [sp], #4 Pull "r10-r12" MOVS pc, lr Do_CallBack ; CallBack allowed: [ FixCallBacks ; Entered in SVC32 mode with IRQs off, r10 = 0 TST r11, #CBack_Postpone BICNE r11, r11, #CBack_Postpone STRNEB r11, [r10, #CallBack_Flag] Do_CallBack_postpone_already_clear ] TST r11, #CBack_VectorReq ; now process any vector entries MOV r12,lr BLNE process_callback_chain MOV lr,r12 [ FixCallBacks LDRB r11, [r10, #CallBack_Flag] ; non-transient callback may have been set during transient callbacks ] TST r11, #CBack_OldStyle BEQ back_to_user [ :LNOT:No26bitCode TST r14, #&10 ; must be returning to 26-bit BNE back_to_user ; on 26-bit systems ] [ {TRUE} ; LRust, Fix RP-0609 ; Check that SVC_sp is empty (apart from r14,r10-r12), i.e. system truly is idle LDR r12, =SVCSTK-4*4 ; What SVC_sp should be if system idle CMP sp, r12 ; Stack empty? BLO back_to_user ; No then no call back ] [ FixCallBacks [ :LNOT: No26bitCode MSR CPSR_c, #I32_bit + SVC2632 ; back to 26-bit mode ] BIC r11, r11, #CBack_OldStyle | MSR CPSR_c, #I32_bit + SVC2632 ; ints off while flag updated LDRB r11, [r10, #CallBack_Flag] BIC r11, r11, #CBack_Postpone+CBack_OldStyle ] STRB r11, [r10, #CallBack_Flag] LDR R12, [R10, #CallBf] [ No26bitCode STR r14, [r12, #4*16] ; user PSR Pull r14 STR r14, [r12, #4*15] ; user PC | FakeLR r10 STR r14, [r12, #4*15] ; user PC/PSR ] MOV r14, r12 Pull "r10-r12" [ SASTMhatbroken STMIA r14!,{r0-r12} STMIA r14,{r13,r14}^ ; user registers NOP ; doesn't matter that r14 is different | STMIA r14, {r0-r14}^ ; user registers ] LDR R12, =ZeroPage+CallAd_ws LDMIA R12, {R12, PC} ; jump to CallBackHandler ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Also called from source.pmf.key, during readc process_callback_chain ROUT Push "r0-r6, r10-r12, lr" ; save some for the callee too. [ FixCallBacks :LAND: No26bitCode MRS r0, CPSR Push "r0" ] LDR r10, =ZeroPage MSR CPSR_c, #I32_bit + SVC2632 ; ints off while flag updated LDRB r11, [r10, #CallBack_Flag] BIC r11, r11, #CBack_VectorReq STRB r11, [r10, #CallBack_Flag] 01 MSR CPSR_c, #I32_bit + SVC2632 ; ints off while flag updated LDR r2, =ZeroPage LDR r2, [r2, #CallBack_Vector] TEQ r2, #0 [ No26bitCode [ FixCallBacks Pull "r0", EQ MSREQ CPSR_c, r0 ; restore original interrupt state and 32bitness | MSREQ CPSR_c, #SVC2632 ; ensure exit with ints on ] Pull "r0-r6, r10-r12, PC",EQ | Pull "r0-r6, r10-r12, PC",EQ,^ ] LDMIA r2, {r10, r11, r12} ; link, addr, r12 MOV r0, #HeapReason_Free [ ZeroPage = 0 STR r10, [r0, #CallBack_Vector-HeapReason_Free] ; Keep head valid | LDR r1, =ZeroPage STR r10, [r1, #CallBack_Vector] ; Keep head valid ] MSR CPSR_c, #SVC2632 ; enable ints for long bits [ ChocolateSysHeap ASSERT ChocolateCBBlocks = ChocolateBlockArrays + 0 [ ZeroPage = 0 MOV r1,#ChocolateBlockArrays LDR r1,[r1,#0] | LDR r1, [r1, #ChocolateBlockArrays] ] BL FreeChocolateBlock LDRVS r1, =SysHeapStart SWIVS XOS_Heap | LDR r1, =SysHeapStart SWI XOS_Heap ] MOV lr, pc MOV pc, r11 ; call im, with given r12 B %BT01 ; loop LTORG ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_WriteC ; In r11 = 0 (look, up there ^) ! SWIWriteC ROUT MSR CPSR_c, #SVC2632 ; enable interrupts Push lr [ ROMatTop [ ZeroPage <> 0 LDR r11, =ZeroPage ] LDR r11, [r11, #VecPtrTab+WrchV*4] ; load top node pointer CMP r11, #ROM [ StrongARM BCC WrchThruVector Push pc, CS ; need to get to ReturnFromVectoredWrch - push PC+12 (old ARM) or PC+8 (StrongARM) BCS PMFWrchDirect MOV R0,R0 ; NOP for PC+8 | Push pc, CS ; push address of ReturnFromVectoredWrch (PC+12) BCS PMFWrchDirect BCC WrchThruVector ] | B WrchThruVector ] ReturnFromVectoredWrch Pull lr B SLVK_TestV WrchThruVector MOV r10, #WrchV BL CallVector B ReturnFromVectoredWrch ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ SWINewLine ROUT MOV r11, lr SWI XOS_WriteI+10 SWIVC XOS_WriteI+13 MOV lr, r11 B SLVK_TestV ; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_WriteI+n SWIWriteI ROUT MOV r10, r0 AND r0, r11, #&FF MOV r11, lr ; NB. Order !!! SWI XOS_WriteC MOVVC r0, r10 MOV lr, r11 B SLVK_TestV ; return setting V ; ............................................................................. ; define module SWI node format ModSWINode_CallAddress * 0 ModSWINode_MListNode * 4 ModSWINode_Link * 8 ModSWINode_Number * 12 ModSWINode_Size * 16 ; not a field - the node size! MACRO $l ModSWIHashvalOffset $swino, $startreg [ "$startreg"="" $l MOV $swino, $swino, LSR #4 | $l MOV $swino, $startreg, LSR #4 ] AND $swino, $swino, #(ModuleSHT_Entries-1)*4 MEND MACRO $l ModSWIHashval $swino, $startreg $l ModSWIHashvalOffset $swino, $startreg ADD $swino, $swino, #ModuleSWI_HashTab [ ZeroPage <> 0 ASSERT ZeroPage = &FFFF0000 ADD $swino, $swino, #&FF000000 ADD $swino, $swino, #&00FF0000 ] MEND NotMainMOSSwi ; Continuation of SWI despatch CMP R11, #&200 BCC SWIWriteI ; ............................................................................. ; Look round RMs to see if they want it ExtensionSWI ROUT [ No26bitCode ASSERT FixR9CorruptionInExtensionSWI Push "lr" | Push "r9, lr" ; first construct the link to pass on. AND r10, lr, #&F0000000 ; copy in user CCodes AND r12, lr, #F32_bit+I32_bit ; (inc. IRQ state) ORR r10, r10, r12, LSL #IF32_26Shift ADR lr, %FT02 + SVC_mode ORR lr, lr, r10 ] BIC r12, r11, #Module_SWIChunkSize-1 ModSWIHashvalOffset r10, r12 [ ZeroPage = 0 LDR r10, [r10, #ModuleSWI_HashTab] | LDR lr, =ZeroPage+ModuleSWI_HashTab LDR r10, [r10, lr] ] loopoverhashchain CMP r10, #0 BEQ VectorUserSWI [ No26bitCode LDR lr, [r10, #ModSWINode_Number] CMP lr, r12 | LDR r9, [r10, #ModSWINode_Number] CMP r9, r12 ] LDRNE r10, [r10, #ModSWINode_Link] BNE loopoverhashchain LDMIA r10, {r10, r12} LDR r12, [r12, #Module_incarnation_list] ; preferred life CMP r12, #0 [ FixR9CorruptionInExtensionSWI:LAND::LNOT:No26bitCode Pull "r9", NE ; restore corrupted r9 before calling SWI handler ;RCM added 'NE' above to fix MED=04655 ] ANDNE r11, r11, #Module_SWIChunkSize-1 ADDNE r12, r12, #Incarnation_Workspace [ No26bitCode ADRNE lr, %FT02 ] MOVNE pc, r10 VectorUserSWI ; Not in a module, so call vec [ FixR9CorruptionInExtensionSWI:LAND::LNOT:No26bitCode Pull "r9" ; restore corrupted r9 before calling UKSWIV ] MOV r10, #UKSWIV ; high SWI number still in R11 [ No26bitCode BL CallVector | B CallVector ; lr still has user CCs (if 26bit) & points at%FT02 ] 02 [ FixR9CorruptionInExtensionSWI Pull "lr" ; r9 already pulled off stack before calling SWI handler or UKSWIV | Pull "r9,lr" ] MRS r10, CPSR BIC lr, lr, #&FF000000 ; Can mangle any/all of punter flags AND r10, r10, #&FF000000 ORR lr, lr, r10 B SLVK ; ....................... default owner of UKSWIV ............................. ; Call UKSWI handler ; Also used to call the upcall handler ; In r12 = HiServ_ws (or UpCallHan_ws) CallUpcallHandler HighSWI ROUT ; no one on vec wants it: give to handler Pull lr ; the link pointing at %BT02 to pass in. LDMIA r12, {r12, pc} ; ........................ default UKSWI handler .............................. NoSuchSWI ROUT Push lr BL NoHighSWIHandler Pull lr B SLVK_SetV ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; .................... default Unused SWI handler ............................. NoHighSWIHandler ROUT LDR r0, =ZeroPage LDR r0, [r0, #IRQsema] CMP r0, #0 ADR r0, ErrorBlock_NoSuchSWI ; Must return static error here [ No26bitCode BEQ %FT01 SETV MOV pc, lr 01 | ORRNES pc, lr, #V_bit ] ; Not in IRQ: can safely build a dynamic error [ International Push "r1-r4, lr" SUB sp, sp,#12 MOV r1, sp MOV r2, #12 MOV r0, r11 SWI XOS_ConvertHex6 ; SWI argument is 00xxxxxx MOV r4, r0 ; now strip leading 0s 02 LDRB r2, [r4], #1 CMP r2, #"0" BEQ %BT02 SUB r4,r4,#1 ADR r0, ErrorBlock_NoSuchSWI1 BL TranslateError_UseR4 ADD sp,sp,#12 Pull "r1-r4, lr" [ No26bitCode SETV MOV pc, lr | ORRS pc, lr, #V_bit ] MakeErrorBlock NoSuchSWI1 | Push "r1-r3, lr" LDR r1, =EnvString LDMIA r0!, {r2, r3} ; number, "SWI " STMIA r1!, {r2, r3} MOV r2, #"&" STRB r2, [r1], #1 MOV r3, r0 MOV r0, r11 MOV r2, #256 SWI XOS_ConvertHex6 ; SWI argument is 00xxxxxx ; now strip leading 0s MOV r1, r0 02 LDRB r2, [r1], #1 CMP r2, #"0" BEQ %BT02 CMP r2, #0 ADDEQ r1, r0, #1 BEQ %FT03 04 STRB r2, [r0], #1 LDRB r2, [r1], #1 CMP r2, #0 BNE %BT04 MOV r1, r0 03 MOV r2, #" " 01 STRB r2, [r1], #1 CMP r2, #0 LDRNEB r2, [r3], #1 BNE %BT01 Pull "r1-r3, lr" LDR r0, =EnvString [ No26bitCode SETV MOV pc, lr | ORRS pc, lr, #V_bit ] ] MakeErrorBlock NoSuchSWI ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Fast SWI handlers for BGet and BPut caches BGetSWI ROUT ; Done separately for highest speed Push lr MOV r10, #BGetV ; Cache hit failed, call victor BL CallVector Pull lr ; Punter lr has VClear BIC lr, lr, #C_bit ; Copy C,V to punter lr ORRCS lr, lr, #C_bit B SLVK_TestV ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ BPutSWI ROUT ; Done separately for highest speed Push "lr" MOV r10, #BPutV ; Cache hit failed, call victor BL CallVector Pull "lr" ; Destack lr(VC) B SLVK_TestV ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI handlers for all the vectored SWIs that have vecnum=swinum ; All defined to affect C & V at most FSControlSWI ROUT MOV r11, #FSCV ; Pretend to be vecnum = swinum swi ; and just drop through to ... VecSwiDespatch ROUT Push lr ; this is user's link (or PSR in 32-bit case) MOV r10, r11 ; SWI number from R11->R10 [ No26bitCode MRS r11, CPSR AND r14, r14, #&F0000000 ; extract caller's CCs BIC r11, r11, #&F0000000 ; mask out ours BIC r11, r11, #I32_bit ; enable IRQs ORR r11, r11, r14 ; add in CCs MSR CPSR_cf, r11 ; and set it all up | ORR r14, lr, #SVC_mode BIC r14, r14, #I_bit ; Enable IRQs TEQP r14, #0 ] BL CallVector ; So the vectored routine can update the pushed link CCodes if wanted ; No update return is therefore LDMIA stack!, {PC}^ (sort of) ; Update return pulls lr, molests it, then MOVS PC, lr ; Note either return enables IRQ, FIQ ; ???? Is the DEFAULT owner allowed to corrupt r10,r11 IFF he claims it ???? Pull lr ; Punter lr has VClear BICCC lr, lr, #C_bit ; Copy C,V to punter lr ORRCS lr, lr, #C_bit B SLVK_TestV NoIrqVecSwiDespatch ROUT Push lr ; this is user's link MOV r10, r11 ; SWI number from R11->R10 [ No26bitCode MRS r11, CPSR AND r14, r14, #&F0000000 ; extract caller's CCs BIC r11, r11, #&F0000000 ; mask out ours ORR r11, r11, #I32_bit ; disable IRQs ORR r11, r11, r14 ; add in CCs MSR CPSR_cf, r11 ; and set it all up | ORR r14, lr, #SVC_mode+I_bit ; Disable IRQ TEQP r14, #0 ] BL CallVector Pull lr ; Punter lr has VClear BICCC lr, lr, #C_bit ; Copy C,V to punter lr ORRCS lr, lr, #C_bit B SLVK_TestV ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_GetEnv SWI_GetEnv_Code ROUT LDR r0, =EnvString LDR r1, =ZeroPage LDR r1, [r1, #MemLimit] LDR r2, =ZeroPage+EnvTime B SLVK ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_Exit SEXIT ROUT BL OscliTidy ; shut redirection, restore FS ; now see if it's an abort Exit LDR r12, ABEX CMP r1, r12 [ No26bitCode TSTEQ r0, #3 | TSTEQ r0, #ARM_CC_Mask ] MOVNE r2, #0 LDR r12, =ZeroPage STR r2, [r12, #ReturnCode] LDR r12, [r12, #RCLimit] CMP r2, r12 SWIHI OS_GenerateError ; really generate an error ADD sp, sp, #8 ; junk SWI no and R14 on stack Pull "r10-r12" LDR r0, =ZeroPage LDR lr, [r0, #SExitA] STR lr, [r0, #Curr_Active_Object] LDR r12, [r0, #SExitA_ws] LDR sp_svc, =SVCSTK [ No26bitCode MRS r0, CPSR MSR CPSR_c, #I32_bit+SVC2632 ; IRQs off (to protect SPSR_svc) BIC r0, r0, #I32_bit+F32_bit+&0F MSR SPSR_cxsf, r0 ; Get ready for USR26/32, IRQs on MOVS pc, lr ; lr->pc, SPSR->CPSR | BICS pc, lr, #ARM_CC_Mask ] ABEX = "ABEX" ; Picked up as word LTORG ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_CallBack: Set/read callback buffer and handler SCALLB MOV r10, #CallBackHandler handlecomm Push "r2, r3, lr" MOV r3, r0 ; buffer MOV r0, r10 BL CallCESWI MOV r0, r3 Pull "r2, r3, lr" B SLVK_TestV ; ............................................................................. ; SWI OS_BreakSet: Set/read breakpoint buffer and handler SBRKCT MOV r10, #BreakPointHandler B handlecomm ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_ReadEscapeState ReadEscapeSWI ROUT LDR r10, =ZeroPage LDRB r10, [r10, #ESC_Status] TST r10, #1 :SHL: 6 BICEQ lr, lr, #C_bit ORRNE lr, lr, #C_bit B SLVK ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_ServiceCall Issue_Service_SWI ROUT Push lr BL Issue_Service Pull lr B SLVK [ StrongARM ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI XOS_PlatformFeatures PlatFeatSWI ROUT Push lr CMP r0, #0 ;Is it a known reason code? BNE %FT50 ;No, so send out a service call ;Ok, it's the 'code_features' reason code. [ ZeroPage <> 0 LDR r0, =ZeroPage ] LDR r0,[r0, #ProcessorFlags] TST r0, #CPUFlag_InterruptDelay ADRNE r1, platfeat_irqinsert ;Yep, so point R1 to the delay routine MOVEQ r1, #0 Pull lr B SLVK ;Return platfeat_irqinsert MOV r0, r0 MOV r0, r0 MOV r0, r0 MOV r0, r0 MOV r0, r0 MOV pc, lr 50 [ {FALSE} Push "r1-r8" MOV r1, #Service_UnknownPlatformFeatures Pull "r2-r9" BL Issue_Service CMP r1, #0 BNE %FT75 Push "r2-r9" Pull "r1-r8" B SLVK ;Return ] 75 ;Get here if the service call isn't claimed. ADR R0, ErrorBlock_BadPlatReas [ International Push "lr" BL TranslateError Pull "lr" ] B SLVK_SetV MakeErrorBlock BadPlatReas ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; SWI OS_GenerateError GenErrorSWI * SLVK_SetV ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ END