; 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. ; ; > s.Wimp08 ; ***** WARNING ***** ; ; This file contains old code, which is retained only for compiling Wimps to ; run on old kernels (before RO 3.70). The code contains some known bugs ; (eg. Wimp_TransferBlock). ; ; s.Wimp08s contains the current code, which is much more efficient and ; cleaner for task memory management. This works with all ARMs supported by ; the current kernel. It is *not* just for StrongARM, despite previous comments ; made here. ; ; UseAMBControl should be {TRUE} (to use current code), except when compiling ; to run on old kernels. ; ; Any bug fixes *must* be made in s.Wimp08s (and are probably not worth ; replicating here). ; ; mjs ; [ :LNOT: KernelLocksFreePool ; These magic addresses are no longer in the PublicWS header - indeed, they are ; no longer fixed addresses since Tungsten. Fortunately, the relevant code was ; moved to the kernel in Ursula, so for all OSes that need them, the addresses ; can be considered to be constant. ^ &01F033FC SvcTable # &400 ^ &01F037FC BranchToSWIExit # 4 ; from SWI despatcher ] GBLS LoadWimp08s [ UseAMBControl LoadWimp08s SETS "GET s.Wimp08s" | LoadWimp08s SETS "" ! 0, "" ! 0, "********* Building old variant of Wimp (UseAMBControl {FALSE})" ! 0, "*WARNING* This is only sensible for Wimps running on old kernels" ! 0, "********* (before RISC OS 3.70). Old variant is slow and buggy." ! 0, "" ] $LoadWimp08s ;;---------------------------------------------------------------------------- ;; Switcher routines ;;---------------------------------------------------------------------------- ; THIS FILE IS SUPERSEDED BY s.Wimp08s ; Wimp_SlotSize ; Wimp_ClaimFreeMemory ; Wimp_TransferBlock ; ; findpages look for application memory & set up free pool ; testapplication see if the application space is in use ; restorepages put the rest of the pages back after the current slot ; allocateslot transfer pages from free pool to a slot array ; deallocateslot transfer pages from a slot array to free pool ; mapslotin map pages in a slot into application space ; mapslotout map pages in a slot out of the way ; ; initdynamic intercept SWI table entry ; resetdynamic unintercept SWI table entry ; My_ChangeDynamic stack the applications to fill up application space ; servicememory accept/refuse to allow memory to be moved ; servicememorymoved unstack the applications and recover! ;----------------------------------------------------------------------------- ; Data structures: ; task table -> task block (or task_unused if task dead) ; task block -> slot block for task ; freepool -> slot block for free pool (with room for all pages) ; slot block = { page, addr, protection }* -1 -1 ; (suitable for OS_ReadMemMapEntries and OS_FindMemMapEntries) ; freepoolbase, orig_applicationspacesize delimit the free pool ;----------------------------------------------------------------------------- ; Set/Read current Wimp slot size ; Entry: R0 = new 'current' slot size in bytes (-1 ==> no change) ; R1 = new 'next' slot size in bytes (-1 ==> no change) ; Exit: R0 = actual 'current' slot size ; R1 = actual 'next' slot size ; R2 = total amount of free memory 'owned' by the Wimp ; if R2 < R1, the next slot will not be allocated in full ; when no tasks are running, R2 will be 0 ; if R0>=0 on entry, pages may be remapped and MemoryLimit changed [ :LNOT: UseAMBControl SWIWimp_SlotSize ROUT MyEntry "SlotSize" ; MOV R4,R0 ; R4 = new current slot size ; MOV R2,R1 ; R2 = proposed slot size SWI XOS_ReadMemMapInfo CMP R2,#-1 ; if -ve, just read current value LDREQ R3,slotsize BEQ %FT01 ADD R2,R2,R0 ; R2 = (R2+size-1) DIV size * size SUB R2,R2,#1 DivRem R3,R2,R0, R14 STR R3,slotsize ; [slotsize] = no of pages 01 LDR R2,orig_applicationspacesize LDR R14,freepoolbase SUB R2,R2,R14 ; R2 = total free memory [ Medusa Push "R0-R1" [ ShrinkableAreas Push r3 ; get round r3 corruption for now MOV r0, #5 MOV r1, #-1 SWI XOS_DynamicArea Pull r3 | MOV R0,#6 SWI XOS_ReadDynamicArea ; memory in free pool MOV R2,R1 ] Pull "R0-r1" ] MUL R1,R3,R0 ; R1 = next slot size [ false ; MED-00946 CMP R1,R2 MOVGT R1,R2 ; can't be more memory in next than freepool ] STMIA sp,{R1,R2} ; ensure calling task gets new values ; ; transfer pages between current slot and free pool ; on exit R0 = actual current slot size (whether or not memory could be moved) ; CMP R4,#-1 ; R4 = proposed new current slot size ; under Medusa [freepool] has no meaning BEQ returnmemsize [ :LNOT:Medusa LDR R14,freepool CMP R14,#0 BLT returnmemsize ] ; MOV R0,#ApplicationSpaceSize MOV R1,#0 SWI XOS_ChangeEnvironment MOV R3,R1 ; R3 --> end of current slot MOV R0,#MemoryLimit MOV R1,#0 SWI XOS_ChangeEnvironment TEQ R1,R3 BNE returnmemsize ; fixed - memory cannot be paged ; LDR R0,pagesize ; R0 = page size SUB R14,R0,#1 ADD R4,R4,R14 BIC R4,R4,R14 ; round up to nearest page boundary SUB R4,R3,R4 SUB R4,R4,#ApplicationStart ; R4 = amount to transfer into pool ; LDR R5,taskhandle ; obtain R5 --> task block LDR R5,[wsptr,R5] TST R5,#task_unused LDRNE R5,pendingtask TST R5,#task_unused BNE returnmemsize ; no current task (?) ; LDR R2,[R5,#task_slotptr] ; R2 --> slot (if any) CMP R2,#nullptr BLEQ getnullslot STRVC R2,[R5,#task_slotptr] BVS ExitWimp ; exit if unable to claim block ; LDR R0,pagesize ; R0 = page size MOV R1,#0 01 LDR R14,[R2],#12 CMP R14,#0 ADDGE R1,R1,R0 ; R1 = total amount of memory in slot BGE %BT01 SUB R2,R2,#12 ; R2 --> terminator of slot block ; CMP R4,#0 BEQ returnmemsize ; don't bother with message if same size [ Medusa Push "R0-R3" ; there may be more memory in the slot than memory limit, app space suggest. ADD R1,R1,#ApplicationStart MOV R0,#0 Push "R1" SWI XOS_ChangeEnvironment Pull "R1" MOV R0,#14 SWI XOS_ChangeEnvironment ; if running under Medusa then the CAO needs to be moved to the module area, otherwise ; the CDA call will fail. MOV R0,#15 MOV R1,#&08000000 SWI XOS_ChangeEnvironment BVS %FT03 ; can't change cao, try and shift memory anyway. MOV R2,R1 MOV R0,#6 ; freepool MOV R1,R4 ; number of bytes to alter free pool by SWI XOS_ChangeDynamicArea Push "R1" MOV R1,R2 MOV R0,#15 SWI XOS_ChangeEnvironment ; put cao back where it was. Pull "R1" CMP R1,#0 Pull "R0-R3",EQ BEQ returnmemsize ; no change CMP R4,#0 ; sets conditionals for below MOV R4,R1 Pull "R0-R3" B %FT04 03 MOV R0,#6 ; freepool MOV R1,R4 ; number of bytes to alter free pool by SWI OS_ChangeDynamicArea CMP R1,#0 Pull "R0-R3",EQ BEQ returnmemsize ; no change CMP R4,#0 ; sets conditionals for below MOV R4,R1 Pull "R0-R3" 04 | RSBLT R4,R4,#0 ; R4 now positive, flags reflect actual change ] BLT growapp ; ; shrink application space by R4 bytes (already a whole number of pages) ; shrinkapp CMP R4,R1 ; always move as much as possible MOVGT R4,R1 ; MOV R3,R2 ; R3 --> terminator ; CMP R4,#0 01 SUBGT R2,R2,#12 SUBGT R1,R1,R0 ; used later for OS_ChangeEnvironment SUBGTS R4,R4,R0 BGT %BT01 ; [ :LNOT:Medusa BL maptofreepool ] MOV R14,#-1 STR R14,[R2] ; terminator ; LDR R14,[R5,#task_slotptr] CMP R2,R14 BHS %FT01 ; MOV R2,R14 ; if null block, delete it! MOV R0,#ModHandReason_Free BL XROS_Module MOV R2,#nullptr B %FT02 01 SUB R3,R2,R3 ; R3 = amount to change block by (-ve) MOV R0,#ModHandReason_ExtendBlock LDR R2,[R5,#task_slotptr] BL XROS_Module 02 STRVC R2,[R5,#task_slotptr] [ Medusa MOV R5,R1 ; used in the switcher message B sendmemmessage ; SafeChangeDynamic ; if running under Medusa then the CAO needs to be moved high, otherwise ; the CDA call will fail. ; Entry : R4 number of bytes to move (signed), R0-R3 possibly corrupt ; Exit : R1 number of bytes actually moved (unsigned) SafeChangeDynamic Push "lr" MOV R0,#15 MOV R1,#&08000000 SWI XOS_ChangeEnvironment BVS %FT03 ; can't change cao, try and shift memory anyway. MOV R2,R1 MOV R0,#6 ; freepool MOV R1,R4 ; number of bytes to alter free pool by SWI XOS_ChangeDynamicArea Push "R1" MOV R1,R2 MOV R0,#15 SWI XOS_ChangeEnvironment ; put cao back where it was. Pull "R1,PC" 03 MOV R0,#6 ; freepool MOV R1,R4 ; number of bytes to alter free pool by SWI OS_ChangeDynamicArea 04 Pull "PC" ; ; grow an app under the medusa kernel ; R4 is byte change, R2 is slot terminator, R0 page size, R5 task pointer, R1 is slot size ; growapp TEQ R4,#0 BEQ returnmemsize ; this takes account of the case where the ; slot cannot grow due to memory constraints. Push "R0,R1,R4" MOV R3,#0 01 ADD R3,R3,#12 SUBS R4,R4,R0 BNE %BT01 ; need to extend slot ptr by R3 LDR R2,[R5,#task_slotptr] MOV R0,#ModHandReason_ExtendBlock BL XROS_Module BVC %FT03 ; oh, dear we need to shrink the app by one page size and try again MOV R0,#6 LDR R1,[SP] Push "R0-R4" MOV R4,R1 BL SafeChangeDynamic Pull "R0-R4" ; SWI XOS_ChangeDynamicArea ; alert alert, something quite awful has happened ; you know, i used to wonder what sort of bozzos put comments in like these, now ; i understand... ADDVS SP,SP,#12 ; skip rubbish BVS ExitWimp Pull "R0,R1,R4" SUB R4,R4,R0 B growapp ; try again with smaller slot. 03 STR R2,[R5,#task_slotptr] Pull "R0,R1,R4" MOV R3,#ApplicationStart Push "R4" MOV R4,R1 LDR R0,pagesize MOV R1,#0 ; first R1 bytes (original slot) probably have the correct page number CMP R4,#0 BEQ %FT06 05 ADD R2,R2,#4 STR R3,[R2],#8 ; address ADD R3,R3,R0 SUBS R4,R4,R0 BNE %BT05 06 ; next R4 bytes are new and so we have no idea what page number they are, set them to zero. Pull "R4" CMP R4,#0 BEQ %FT09 07 Push "R2" 08 STR R1,[R2],#4 ; page no. STR R3,[R2],#4 ; address STR R1,[R2],#4 ; protection ADD R3,R3,R0 SUBS R4,R4,R0 BNE %BT08 MOV R0,#-1 STR R0,[R2] Pull "R0" SWI XOS_FindMemMapEntries ; only find entries for new pages 09 SUB R5,R3,#ApplicationStart ; used in message to switcher | ; Medusa B setcurslot ; ; grow application space by R4 bytes (already a whole number of pages) ; growapp LDR R3,orig_applicationspacesize LDR R14,freepoolbase SUB R3,R3,R14 ; R3 = amount of memory available CMP R4,R3 ; MOVGT R4,R3 ; max amount moveable ; ; Push "R1,R2,R4" ; MOV R3,#0 01 SUBS R4,R4,R0 ADDGE R3,R3,#12 BGT %BT01 ; LDR R2,[R5,#task_slotptr] MOV R1,R2 MOV R0,#ModHandReason_ExtendBlock BL XROS_Module STRVC R2,[R5,#task_slotptr] SUBVC R14,R2,R1 ; amount block has moved by MOVVC R6,R2 ; R6 --> new block ; Pull "R1,R2,R4" BVS ExitWimp ; nothing updated yet, so just exit ; ADD R2,R2,R14 ; R2 --> end of block (moved!) ; LDR R3,orig_applicationspacesize ; DO IT AGAIN!!! LDR R14,freepoolbase ; - may have changed !!! SUB R3,R3,R14 ; R3 = amount of memory available CMP R4,R3 MOVGT R4,R3 ; max amount moveable ; LDR R0,pagesize DivRem R5,R4,R0, R14 ; R5 = number of pages to move MOV R3,R1 ; R3 = size of slot so far BL mapfromfreepool ; on exit R1 = memory transferred ; MOV R0,R6 ; R0 --> new slot block BL mapin ; map in whole slot (corrupts R2) ; ADD R1,R1,R3 ; R1 = total memory in new slot setcurslot MOV R5,R1 ; R5 = current slot size (for later) ADD R1,R1,#ApplicationStart BL setmemsize ; R1 = end of memory for slot ] ; Medusa ; ; send round a broadcast, to be picked up by the Switcher ; NB this can only be done if the task is alive (otherwise it has no handle) ; sendmemmessage LDR R14,taskhandle LDR R14,[wsptr,R14] TST R14,#task_unused ; ASSERT ms_data=20 MOVEQ R0,#28 ; 28 byte block MOVEQ R3,#0 ; your ref LDREQ R4,=Message_SlotSize LDREQ R6,[sp,#0*4] ; next slot size (already on stack) Push "R0-R6" MOVEQ R0,#User_Message ; don't bother getting reply MOVEQ R1,sp MOVEQ R2,#0 ; broadcast BLEQ int_sendmessage ; fills in sender, myref ADD sp,sp,#28 returnmemsize MOV R0,#MemoryLimit ; may not actually be full slot size MOV R1,#0 ; (eg. if Twin is running above) SWI XOS_ChangeEnvironment SUBVC R0,R1,#ApplicationStart ; R0 = actual slot size B ExitWimp LTORG getnullslot Push "LR" MOV R3,#4 ; we need 2 terminators BL claimblock MOVVC R14,#-1 ; terminator STRVC R14,[R2] Pull "PC" ; ; Claim free memory pages ; Entry: R0 = 0 for release, 1 for claim ; R1 = length required ; Exit: R1 = length available ; R2 = start address ; R2 = 0 means memory could not be claimed (no need to release) ; Can't: if not enough free memory ; if claimed already ; if in the middle of a remapping operation ; mem_remapped * 2_0001 mem_claimed * 2_0010 wimparea DCB "Wimp" [ :LNOT: FreePoolWCF wimpareastring DCB "WDA",0 ; SMC: add WDA:Wimp Dynamic Area to Wimp.Messages file. ] ALIGN SWIWimp_ClaimFreeMemory ROUT MyEntry "ClaimFreeMemory" ; [ Medusa [ :LNOT: FreePoolWCF MOV R5,R1 LDR R1,wimparea ] CMP R0,#0 BNE %FT01 ; free [ FreePoolWCF MOV R0,#0 ADRL R14,freepoolinuse STRB R0,[R14] B ExitWimp | MOV R0,#1 STRB R0,memoryOK MOV R0,R1 MOV R1,#-&8000000 ; shrink area SWI XOS_ChangeDynamicArea MOV R0,#0 STRB R0,memoryOK CLRV B ExitWimp ] 01 ; claim [ FreePoolWCF ADRL R4,freepoolinuse LDRB R0,[R4] TEQ R0,#0 | MOV R0,R1 SWI XOS_ReadDynamicArea TEQ R1,#0 ] MOVNE R0,#0 STRNE R0,[SP] STRNE R0,[SP,#4] BNE ExitWimp ; already 'claimed' [ FreePoolWCF MOV R5,R1 ; preserve the amount asked for MOV R0,#6 SWI XOS_ReadDynamicArea MOVVS R0,#0 ; Shouldn't happen MOVVS R1,#0 CMP R5,R1 ; set HI if R5 <0 or R5>R1 MOVHI R0,#0 MOVLS R2,#1 STRLSB R2,[R4] ; mark free pool in use STR R0,[SP,#4] ; return values STR R1,[SP] B ExitWimp [ false CMP R5,#0 ; asked for -ve amount CMPGE R1,R5 ; not enough ? MOVLT R3,R1 MOVLT R4,#0 ; no address as claim 'failed' BLT %FT01 05 CLRV MOV R1,#1 STRB R1,[R4] ; mark free pool as in use MOV R0,#6 SWI XOS_ReadDynamicArea MOVVS R4,#0 ; shouldn't happen MOVVC R3,R1 MOVVC R4,R0 ; start address of free pool B %FT01 ] | MOV R1,#1 STRB R1,memoryOK MOV R1,R5 CMP R1,#0 SETV LT LDRVC R0,wimparea SWIVC XOS_ChangeDynamicArea MOV R4,#0 STRB R4,memoryOK MOVVS R0,#6 ; freepool, just size!!! LDRVC R0,wimparea ; our area MOV R2,#0 CLRV SWI XOS_ReadDynamicArea TEQ R2,#0 MOV R3,R1 MOVNE R4,R0 ; no start if claim failed CLRV B %FT01 ] 02 ] TEQ R0,#0 LDRB R5,memoryOK ; always load R5 BICEQ R5,R5,#mem_claimed STREQB R5,memoryOK BEQ ExitWimp ; MOV R3,#0 ; R3=0 no memory available MOV R4,#0 ; R4=0 can't claim ; TEQ R5,#0 BNE %FT01 ; can't claim (nasty business going on) ; LDR R14,freepool CMP R14,#nullptr2 BHS %FT01 ; can't claim (no free pool) ; LDR R3,orig_applicationspacesize LDR R4,freepoolbase SUB R3,R3,R4 ; R3 = length available ; ADD R14,R3,#1 CMP R1,R14 ; C=1 ==> too long! MOVCS R4,#0 ; address = 0 if carry set ORRCC R5,R5,#mem_claimed STRCCB R5,memoryOK 01 STMIA sp,{R3,R4} ; R1,R2 on return = length,addr B ExitWimp [ Medusa wimp_area_handler CLRV TST R0,#1 MOVNE PC,lr ; not insterested in postshrink/grow SETV ; must be a pre shrink/grow, allow this if it was caused by the claim above Push R0 LDRB R0,memoryOK TEQ R0,#0 Pull R0 CLRV NE MOVVC PC,lr CMP R0,#2 MOVEQ R3,#0 MOV R0,#0 SETV MOV PC,lr ] ; ; Transfer memory from one application to another ; Entry: R0 = task handle of source ; R1 --> source buffer ; R2 = task handle of destination ; R3 --> destination buffer ; R4 = buffer length ; buffer addresses and length are byte-aligned (not nec. word-aligned) ; the buffer addresses are validated to ensure they are in range ; Errors: "Invalid task handle" ; "Wimp transfer out of range" ; SWIWimp_TransferBlock ROUT MyEntry "TransferBlock" ; Push "R0-R4" MOV R0,#MemoryLimit ; force this field to be up-to-date MOV R1,#0 SWI XOS_ChangeEnvironment LDR R14,taskhandle LDR R14,[wsptr,R14] CMP R14,#0 STRGT R1,[R14,#task_environment+12*MemoryLimit] [ Medusa LDMIA SP,{R0-R4} ; leave them on the stack | Pull "R0-R4" ] ; BL validtask_alive MOVVC R7,R6 ; R7 --> dest task block MOVVC R2,R0 [ Medusa Push "R5" ] BLVC validtask_alive ; R6 --> source task block BVC %FT05 medusa_exit_trb [ Medusa ADD SP,SP,#4 ; the push above was non-conditional ] medusa_exit_trb2 [ Medusa ADD SP,SP,#20 SETV ; want an error ] B ExitWimp ; 05 SUBS R10,R4,#0 ; length must be >= 0 BNE %FT07 ; ignore zero length now! [ Medusa ADD SP,SP,#24 ; no error so don't set V ] B ExitWimp 07 BLT err_badtransfer CMP R1,#ApplicationStart ; buffer start >= &8000 CMPHS R3,#ApplicationStart BLO err_badtransfer SUB R8,R1,#ApplicationStart ; assuming app space... SUB R9,R3,#ApplicationStart ; ... R8,R9 = offsets into domain ; [ Medusa :LAND: sixteenmeg MOV R11,#16*1024*1024 | LDR R11,orig_applicationspacesize ] ; CMP R1,R11 ; not in application space? ADDHS R8,R8,#ApplicationStart ; make absolute again BHS %FT11 LDR R14,[R6,#task_environment+12*MemoryLimit] ADD R0,R1,R4 CMP R0,R14 BHI err_badtransfer 11 CMP R3,R11 ; not in application space? ADDHS R9,R9,#ApplicationStart ; make absolute again BHS %FT01 LDR R14,[R7,#task_environment+12*MemoryLimit] ADD R2,R3,R4 CMP R2,R14 BHI err_badtransfer 01 ; ; map all slots into memory space, copy the data, then unmap them ; NOTE: make sure the slots are mapped out before exitting!!! ; MOV R0,#ApplicationSpaceSize MOV R1,#0 SWI XOS_ChangeEnvironment ; R1 --> end of current slot ; [ Medusa ; orignal calling values are still on the stack TEQ R6,R7 ; are the tasks the same? BEQ %FT02 CMP R10,#7*1024*1024 BLT %FT02 ; ok we're doing a BIG transfer, so split it up MOV R10,#7*1024*1024 ; 7 meg, leave a bit of breathing space Push "R1" ; save end-of-current-slot ADD R0,SP,#8 LDMIA R0,{R0-R4} ADD R1,R1,#7*1024*1024 ; we'll carry on but only do 7 megs worth ADD R3,R3,#7*1024*1024 ; then recall the routine, but starting 7 meg SUB R4,R4,#7*1024*1024 ; further on. SWI XWimp_TransferBlock Pull "R1" ; restore end-of-current-slot ; this will cycle through as many times as required 02 ; now if the ammount to copy+ R1 > app space, or 2* copy if neither task is the current task ; then part or all of current task must be paged out. MOV R0,R1 LDR R1,taskhandle LDR R2,pagesize LDR R4,[SP] ; task handle TEQ R1,R4 BEQ onetask_currentr4 ; one of the tasks is the current task TEQ R1,R5 BEQ onetask_currentr5 CMP R8,R11 ADDLO R0,R0,R10 ADDLO R0,R0,R2 ; just in case copy is over a page CMP R9,R11 ADDLO R0,R0,R10 ADDLO R0,R0,R10 [ sixteenmeg CMP R0,#16*1024*1024 | LDR R14,orig_applicationspacesize CMP R0,R14 ] BLO %FT03 ; since the copy must take place in application space (on ARM 3 its the only place! and on ; ARM 600 a level 2 page table would be required- 24K) we have to make some room by paging ; out part of the current task. For simplicity, we page the whole of the task out on the ; assumption that it is only rare circumstances that will bring us here. It's also ; potentially dangerous paging out bits of the current task, eg. if an exception occurs ; the Environment may point to somewhere that we've paged a different bit of memory to. ; Another complication with selective paging of the current task is that the bit we choose ; to page out may be required in the copy, obviously we need to do more work to make sure ; we don't fall over in these situations. makespacefromct Push "R1" ; save task handle BL mapslotout ; map out CT MOV R0,#0 STR R0,taskhandle ADD R0,SP,#8 LDMIA R0,{R0-R4} SWI XWimp_TransferBlock ; do it again, only this time there is no current task Pull "R1" STR R1,taskhandle ; return to how it all was BL mapslotin ADD SP,SP,#24 B ExitWimp ; this is potentially dodgy as the bit we want to map out of the way may actually be in ; the transfer range onetask_currentr5 TEQ R5,R4 BEQ %FT03 CMP R8,R11 ; we only need to woryy about space if the copy ; is actually in the tasks app space BLO onetaskcurrent B %FT03 onetask_currentr4 TEQ R5,R4 BEQ %FT03 CMP R9,R11 onetaskcurrent ADDLO R0,R0,R10 ADDLO R0,R0,R2 ; just in case copy is over a page [ sixteenmeg CMP R0,#16*1024*1024 | LDR R14,orig_applicationspacesize CMP R0,R14 ] BLO %FT03 B makespacefromct 03 MOV R0,#ApplicationSpaceSize MOV R1,#0 SWI XOS_ChangeEnvironment ; R1 --> end of current slot Pull "R4" ADD SP,SP,#20 ; will always be original values on stack MOV R2,R1 LDR R3,taskhandle CMP R8,R11 ; do we need it paged in ? BHS %FT04 CMP R3,R5 ADDEQ R8,R8,#ApplicationStart BEQ %FT04 LDR R0,[R6,#task_slotptr] MOV R1,R8 MOV R8,R2 BL mapenoughslot ADD R8,R8,R0 04 CMP R9,R11 BHS %FT06 CMP R3,R4 ADDEQ R9,R9,#ApplicationStart BEQ %FT06 LDR R0,[R7,#task_slotptr] MOV R1,R9 MOV R9,R2 BL mapenoughslot ; page in only whats required for the copy ADD R9,R9,R0 06 | BL rackupslots ; In: R1= bit; Out: trashes R0-R4 ; CMP R8,R11 LDRLO R14,[R6,#task_slotptr] ; must be a slot here if address valid LDRLO R14,[R14,#4] ; get address of first page ADDLO R8,R8,R14 ; R8 --> source buffer ; CMP R9,R11 LDRLO R14,[R7,#task_slotptr] ; must be a slot here if address valid LDRLO R14,[R14,#4] ; get address of first page ADDLO R9,R9,R14 ; R9 --> destination buffer ] ; ; copy data in the correct order, in case source task = destination ; TST R8,#3 TSTEQ R9,#3 TSTEQ R10,#3 BEQ wordcopy ; word aligned, yipee!!! CMP R8,R9 BHS %FT02 ADD R8,R8,R10 ADD R9,R9,R10 01 LDRB R14,[R8,#-1]! ; descending copy if source < dest STRB R14,[R9,#-1]! SUBS R10,R10,#1 BNE %BT01 B %FT03 02 LDRB R14,[R8],#1 ; ascending copy if source >= dest STRB R14,[R9],#1 SUBS R10,R10,#1 BNE %BT02 03 [ Medusa LDR R2,taskhandle ; page out the bits we paged in, unless CT CMP R2,R5 BEQ %FT05 LDR R0,[R6,#task_slotptr] CMP R0,#-1 BLNE mapout 05 CMP R2,R4 BEQ %FT10 LDR R0,[R7,#task_slotptr] CMP R0,#-1 BLNE mapout 10 | BL unrackslots ] B ExitWimp wordcopy CMP R8,R9 BHS %FT02 ADD R8,R8,R10 ADD R9,R9,R10 01 LDR R14,[R8,#-4]! ; descending copy if source < dest STR R14,[R9,#-4]! SUBS R10,R10,#4 BNE %BT01 B %BT03 02 LDR R14,[R8],#4 ; ascending copy if source >= dest STR R14,[R9],#4 SUBS R10,R10,#4 BNE %BT02 B %BT03 [ Medusa mapenoughslot ; maps only the pages that are required for the copy to address R2, slot R0, length R10 ; domain offset R1 Push "R0-R1,R3-R5,lr" LDR R3,pagesize SUB R3,R3,#1 BIC R1,R1,R3 ADD R3,R3,#1 ; find start of block 01 CMP R1,#0 BEQ %FT05 02 LDR R14,[R0],#12 CMP R14,#0 BLT err_badtransfer2 SUBS R1,R1,R3 BNE %BT02 ; R0 now points to start of slot that is involved in the copy 05 MOV R4,R0 LDR R1,[SP,#4] ; domain offset again SUB R5,R3,#1 AND R1,R1,R5 ; offset from page STR R1,[SP] ; R0 on return ADD R1,R1,R10 ADD R1,R1,R5 BIC R1,R1,R5 ; no. of pages required x pagesize 09 LDR R14,[R4],#12 CMP R14,#0 BLT err_badtransfer2 SUBS R1,R1,R3 BNE %BT09 LDR R5,[R4] ; temporarily shorten the slot block MOV R14,#-1 ; this way we don't need to make a new block STR R14,[R4] ; which may require memory we don't have. BL mapslot STR R5,[R4] ; put it back as it was Pull "R0-R1,R3-R5,PC" err_badtransfer2 MyXError WimpBadSlot B medusa_exit_trb2 ; task handle no longer on stack MakeErrorBlock WimpBadSlot ] err_badtransfer MyXError WimpBadTransfer B medusa_exit_trb MakeErrorBlock WimpBadTransfer ; ; free pool set up on entry (unless application memory is already in use) ; order of pages in the free pool is unimportant ; ; Read in table of all OS pages ; work out which ones are in application space ; put them into free pool list ; ; Data structures: ; slot table: list of 3-word entries (as passed to OS_ReadMemMapEntries) ; free pool: list of 3-word entries (enough room for all pages in machine) ; pages are used as in a LIFO stack, with lower addresses last ; ; Exit: if application space used, [freepool] = -1 ; else [freepool] --> free pool block ; findpages ROUT Push "R1-R11,LR" ; MOV R14,#nullptr STR R14,freepool ; lock application memory LDR R14,taskhandle STR R14,inithandle ; this task slot "owns" the memory ; SWI XOS_ReadMemMapInfo ; R0 = page size, R1 = no of pages Pull "R1-R11,PC",VS STR R0,pagesize STR R1,npages ; used later ; ; under the Medusa kernel, try and shrink app space by as much as possible [ Medusa MOV R0,#6 ; free pool MOV R1,#&10000000 ; try and shrink app space SWI XOS_ChangeDynamicArea ; this sets up memory limit/ app space size as well [ :LNOT: sixteenmeg MOV R0,#-1 SWI XOS_ReadDynamicArea ADDVC R5,R0,R2 STRVC R5,orig_applicationspacesize [ :LNOT: FreePoolWCF ; create dynamic area for Wimp_ClaimFreeMemory ADRL R0,wimpareastring ; Look up name for Wimp dynamic area. ADR R2,errorbuffer ; Use safe place for temporary string (copied by OS_DynamicArea). MOV R3,#256 BL LookupToken1 MOVVC R8,R2 ADRVSL R8,wimpareastring ; If look up fails then create something anyway. MOV R0,#0 LDR R1,wimparea MOV R2,#0 MOV R3,#-1 MOV R4,#128 ; not dragable MOV R5,#-1 ADRL R6,wimp_area_handler MOV R7,R12 SWI XOS_DynamicArea ; ignore errors ] ] CLRV Pull "R1-R11,PC" 01 | ; ; if application space in use, we can't construct a free pool ; but we must still read orig_memorylimit and orig_applicationspacesize ; MOV R0,#ApplicationSpaceSize MOV R1,#0 SWI XOS_ChangeEnvironment MOVVC R3,R1 ; R3 --> real end of memory STRVC R3,orig_applicationspacesize ; MOVVC R0,#MemoryLimit MOVVC R1,#0 SWIVC XOS_ChangeEnvironment STRVC R1,orig_memorylimit ; ; TEQ R1,R3 ; preserves V Pull "R1-R11,PC",NE ; these must be equal on entry ; BLVC testapplication ; CC ==> space is in use Pull "R1-R11,PC",VS Pull "R1-R11,PC",CC ; we'll get back to this later if used ; ; allocate a "free pool" block, with 12 bytes per page ; LDR R3,npages MOV R3,R3,LSL #2 ; multiply by 12 ADD R3,R3,R3,LSL #1 ADD R3,R3,#4 ; leave room for terminator BL claimblock STRVC R2,freepool ; ; construct free pool array by calling OS_FindMemMapEntries ; MOVVC R1,#ApplicationStart STRVC R1,freepoolbase ; base address of free pages LDRVC R1,orig_applicationspacesize BLVC findfreepool MOVVC R1,#2 ; protect against USR mode access BLVC setslotaccess ; ; I don't know what this is doing here! ; MOVVC R14,#0 STRVCB R14,memoryOK ; it's had it by now anyway! ; ; now protect all these pages, keeping them just below orig_memlimit ; and set MemoryLimit small ; MOVVC R1,#ApplicationStart BLVC setmemsize ; sets ACTUAL handlers (current task) ; LDRVC R0,freepool SWIVC XOS_SetMemMapEntries Pull "R1-R11,PC" ] ; In R1 = application space size (one after end of free pool) ; R2 -> free pool page table ; [freepoolbase] = start of free pool ; Out free pool table filled in (lowest address last in list) ; [freepoolbase] updated if less than application space size ; [freepoolpages] set up findfreepool ROUT Push "R1-R5,LR" LDR R3,freepoolbase CMP R3,R1 MOVHI R3,R1 STRHI R3,freepoolbase MOV R4,#0 ; R4 = no of pages so far MOV R0,#0 ; R0 = probable page no (don't know) LDR R5,pagesize 01 SUB R1,R1,R5 ; R1 = address of next page CMP R1,R3 STMHSIA R2!,{R0,R1,R14} ; page no, address, access (undefined) ADDHS R4,R4,#1 BHS %BT01 STR R4,freepoolpages MOV R14,#-1 STR R14,[R2] ; terminator LDR R0,[sp,#1*4] SWI XOS_FindMemMapEntries ; find relevent pages Pull "R1-R5,PC" ; In R1 = page protection level required ; R2 -> slot block ; Out page protection level set, array updated ; R0 corrupted setslotaccess ROUT Push "R2,LR" 01 LDR R14,[R2],#12 ; unless terminator, CMP R14,#0 STRGE R1,[R2,#-4] ; fill in access field BGE %BT01 LDR R0,[sp] SWI XOS_SetMemMapEntries Pull "R2,PC" ; ; testapplication ; works out whether application space is in use ; Entry: [orig_memorylimit] = upper bound of memory used by application ; if &8000, then application space is not in use ; Exit: CC ==> memory in use ; ; Method: ; 1. If CAO pointer < MemoryLimit, then application memory is in use. ; 2. Issue Service_Memory: R0 = large - if anyone objects, memory is in use ; ApplicationStart * &8000 IsAnybodyThere * -64*&100000 ; large negative number ; NB: this number is checked for by ShellCLI testapplication ROUT Push "R1-R3,LR" ; [ Medusa :LAND: sixteenmeg MOV R1,#16*1024*1024 ; boo hiss | LDR R1,orig_applicationspacesize ; watch out for Twin etc! ] BL readCAOpointer ; use OS_ChangeEnvironment CMP R2,R1 ; below memorylimit? Pull "R1-R3,PC",CC ; MOV R1,#Service_Memory MOV R0,#IsAnybodyThere ; 64 megabytes should be enough! SWI XOS_ServiceCall CMPVC R1,#1 ; CC ==> service was claimed ; Pull "R1-R3,PC" ; Out R2 = CAO pointer (read using OS_ChangeEnvironment) readCAOpointer ROUT Push "R0-R3,LR" MOV R0,#CAOPointer MOV R1,#0 SWI XOS_ChangeEnvironment STR R1,[sp,#2*4] Pull "R0-R3,PC" ; assume no errors ; ; restorepages ; put back the free pool when the last task dies - do not disturb current stuff ; Entry: all tasks dead ; use OS_ChangeEnvironment to set/read end of application memory ; free pool block indicates remaining spare pages ; Exit: all pages replaced in application space ; memorylimit increased if appropriate ; free pool block released ; restorepages ROUT Push "R1-R7,LR" ; BL deletependingtask ; not interested in this task [ Medusa MOV R4,#-&10000000 ; shrink freepool as much as we can BL SafeChangeDynamic Pull "R1-R7,PC" ] ; ; just add to the pages present LDR R6,freepool CMP R6,#nullptr2 BHS go_restorememlimit ; NB: orig_ values MUST BE CORRECT! ; MOV R0,#MemoryLimit MOV R1,#0 SWI XOS_ChangeEnvironment ; R1 = current memory limit ; ; free pool is already in the right place - just set access bits to 0 ; LDR R2,freepool MOV R1,#0 ; 0 => USR mode read/write access BL setslotaccess ; R2 -> free pool still MOV R14,#nullptr2 ; application space NOT in use by Wimp STR R14,freepool ; NB only applies if not used on entry MOV R0,#ModHandReason_Free BL XROS_Module ; ignore errors from here go_restorememlimit BL restorememlimit ; Pull "R1-R7,PC" restorememlimit ROUT EntryS MOV R0,#MemoryLimit LDR R1,orig_memorylimit SWI XOS_ChangeEnvironment MOV R0,#ApplicationSpaceSize LDR R1,orig_applicationspacesize SWI XOS_ChangeEnvironment EXITS ; must preserve flags ; ; allocateslot ; take pages from the free pool, and construct a page array block ; Entry: [taskhandle] = current task ; [slotsize] = max no of pages to use in new slot ; Exit: taskhandle->task_slotptr --> block (suitable for OS_SetMemMapEntries) ; pages transferred from the free pool to the slot ; [freepoolbase] updated ; slot size = 0 if no free pool (ie. all used up) ; MemoryLimit updated to reflect the amount of memory available ; allocateslot ROUT [ Medusa 01 Push "R0-R4,lr" MOV R0,#14 MOV R1,#ApplicationStart SWI XOS_ChangeEnvironment MOV R0,#0 MOV R1,#ApplicationStart SWI XOS_ChangeEnvironment LDR R0,slotsize LDR R3,pagesize MUL R1,R3,R0 ; usually R0 < R3 MOV R0,#6 RSB R1,R1,#0 ; shrinking free pool SWI XOS_ChangeDynamicArea [ false MOVVS R4,#0 STRVS R4,slotsize ] ; ADDVS SP,SP,#4 ; Pull "R1-R4,PC",VS sadly this may 'succeed' but return an error CLRV CMP R1,#0 ; SETV EQ ;hmmm no error block... ; Pull "R0-R4,PC",VS ; couldn't allocate any memory BNE %FT01 nomemoryinslot [ false MOV R0,#0 MOV R1,#0 SWI XOS_ChangeEnvironment MOV R0,#14 MOV R1,#0 SWI XOS_ChangeEnvironment ; reset env ] BL setdefaulthandlers Pull "R0-R4,PC" nomemoryinslot2 MOV R0,#15 Pull R1 SWI XOS_ChangeEnvironment ; reset env Pull "R0-R4,PC" 01 Push R1 MOV R0,#15 MOV R1,#ApplicationStart SWI XOS_ChangeEnvironment ; lower the cao so that claiming RMA doesn't lose pages Pull R14 Push R1 MOV R1,R14 ; R1 is actual allocation DivRem R4,R1,R3,R14 ADD R4,R4,R4, LSL #1 ; x3 MOV R4,R4, LSL #2 ; x4 ADD R3,R4,#4 02 TEQ R3,#0 BEQ nomemoryinslot2 MOV R0,#ModHandReason_Claim BL XROS_Module ; R2 is block or error BVC %FT03 [ false LDR lr,pagesize MOV R0,#6 MOV R1,lr SWI XOS_ChangeDynamicArea ; grow free pool by a page | Push "R0-R4" LDR R4,pagesize BL SafeChangeDynamic Pull "R0-R4" ] SUB R3,R3,#12 B %BT02 03 MOV R0,#15 Pull R1 Push "R2-R3" SWI XOS_ChangeEnvironment ; reset cao Pull "R2-R3" LDR lr,pagesize ; SWI will have corrupted this ADD R4,R2,R3 ; end of block SUB R4,R4,#4 Push "r2" MOV R3,#ApplicationStart MOV R0,#0 04 STR R0,[R2],#4 STR R3,[R2],#4 STR R0,[R2],#4 ; set protection level. ADD R3,R3,lr CMP R2,R4 BLO %BT04 MOV R0,#-1 STR R0,[R2] Pull "R0" SWI XOS_FindMemMapEntries LDRVC R1,taskhandle LDRVC R1,[wsptr,R1] STRVC R0,[R1,#task_slotptr] STR R0,[SP] ; just in case anything uses this Pull "R0-R4,PC" 99 ] Push "R1-R7,LR" ; LDRB R14,memoryOK ; if free space in use, can't allocate TEQ R14,#0 MOVNE R7,#0 LDREQ R7,freepoolpages ; number of pages in free pool ; LDR R5,slotsize ; max no of pages CMP R5,R7 MOVGT R5,R7 ; now R5 = actual no of pages to use CMP R5,#0 MOVLE R1,#ApplicationStart BLE gosetmemsize ; no pages allocated ; ; allocate a heap block of the correct size ; ADD R3,R5,R5,LSL #1 ; R3 = 3 * no of pages MOV R3,R3,LSL #2 ; R3 = 12 * no of pages ADD R3,R3,#4 ; leave room for terminator BL claimblock Pull "R1-R7,PC",VS ; ; NB: pages may have been remapped because of that call - check here! ; LDR R7,freepoolpages ; R7 = number of free pages CMP R5,R7 MOVGT R5,R7 ; now R5 = actual no of pages to use ; ; construct block by transferring pages from the free pool ; R2 --> new block, R5 = no of pages, R6-->free pool, R7 = free pool sp ; LDR R14,taskhandle ; must be a live task! LDR R1,[wsptr,R14] ; R1 --> task block STR R2,[R1,#task_slotptr] ; BL mapfromfreepool ; R5 = number of pages to grab ADD R1,R1,#ApplicationStart ; R1 --> end of application memory ; MOV R0,R2 BL mapin ; map pages in (corrupts R2) gosetmemsize LDR R14,freepool ;; Wimp 1.89o onwards CMP R14,#nullptr ;; LDREQ R0,taskhandle ;; if this is the "owner" slot, LDREQ R14,inithandle ;; it can have the application memory CMPEQ R0,R14 ;; BLEQ restorememlimit ;; (preserves flags) BLNE setmemsize ;; otherwise it gets none. ; Pull "R1-R7,PC" ; ; Entry: R2 --> slot block ; R5 = number of pages required ; Exit: R1 = amount of memory transferred ; slot block, [freepoolbase], free pool sp updated ; pages are not actually mapped in yet, and addresses are un-initialised ; mapfromfreepool ROUT Push "R2-R7,LR" ; LDR R7,freepoolpages ; R7 = number of pages in free pool SUB R14,R7,R5 STR R14,freepoolpages ; update [freepoolpages] ADD R7,R7,R7,LSL #1 LDR R14,freepool ADD R7,R14,R7,LSL #2 ; R7 -> terminator of free pool MOV R4,#0 ; R4 = page protection level (always 0) 01 SUBS R5,R5,#1 LDRPL R0,[R7,#-12]! ; R0 = page no STMPLIA R2!,{R0,R3,R4} ; page no, address (uninit), access BPL %BT01 MOV R14,#-1 STR R14,[R2] ; slot block terminator STR R14,[R7] ; free pool terminator ; ; update [freepoolbase] and R1 ; LDR R0,pagesize ; R0 = page size LDR R5,[sp,#3*4] MUL R1,R0,R5 ; R1 = amount of memory transferred LDR R14,freepoolbase ADD R14,R14,R1 ; update [freepoolbase] STR R14,freepoolbase ; Pull "R2-R7,PC" ; ; setmemsize ; sets up MemoryLimit and ApplicationSpaceSize for (polltaskhandle) task ; NB: these values apply to the CALLING task (so OS_ChangeEnvironment is used) ; Entry: R1 = new memorylimit / applicationspacesize ; Exit: OS_ChangeEnvironment used to change OS versions of these variables ; if task is alive, its copies are also updated ; R1 = old memorylimit ; setmemsize ROUT Push "LR" MOV R0,#ApplicationSpaceSize Push "R1" SWI XOS_ChangeEnvironment MOVVC R0,#MemoryLimit Pull "R1" SWIVC XOS_ChangeEnvironment Pull "PC" ; ; deallocateslot ; returns pages from a used slot to the free pool ; Entry: [taskhandle] = current task ; Exit: slot block deallocated (if any) ; taskhandle->task_slotptr = null ; pages put back into free pool (NB block never needs extension) ; deallocateslot ROUT Push "R1-R2,LR" ; LDR R14,taskhandle LDR R1,[wsptr,R14] ; R1 --> task block LDR R2,[R1,#task_slotptr] CMP R2,#nullptr MOVNE R14,#nullptr STRNE R14,[R1,#task_slotptr] [ Medusa BEQ %FT03 01 ; first find out how much memory is really in the slot Push "R2-R3" MOV R0,#0 LDR R1,pagesize 02 LDR R14,[R2],#12 CMP R14,#-1 ADDNE R0,R0,R1 BNE %BT02 ; R0 bytes in slot, update environment ADD R1,R0,#ApplicationStart MOV R0,#0 Push "R1" SWI XOS_ChangeEnvironment LDR R1,[SP] MOV R0,#14 SWI XOS_ChangeEnvironment Pull "R1" Push "R4" SUB R4,R1,#ApplicationStart BL SafeChangeDynamic Pull "R4" Pull "R2-R3" CLRV MOV R0,#ModHandReason_Free BL XROS_Module ; free the slot 03 | BLNE deallocate ; R2 --> block to deallocate from ] ; CLRV Pull "R1-R2,PC" ; ; Entry: R2 --> slot block ; Exit: pages mapped into free pool etc. (maptofreepool called) ; slot block deallocated ; deallocate ROUT Push "LR" [ Medusa CMP R2,#nullptr Pull "PC",EQ ; return if invalid slot pointer Push "R0-R4" BL mapslotout ; map current task out of the way LDR R0,pagesize MOV R1,#0 MOV R3,R2 01 LDR R14,[R3],#12 CMP R14,#-1 ADDNE R1,R1,R0 BNE %BT01 ; R1 is now size of block in bytes ADD R1,R1,#ApplicationStart MOV R0,#0 Push "R1" SWI XOS_ChangeEnvironment ; set up suitable environment MOV R3,R1 Pull "R1" MOV R0,#14 SWI XOS_ChangeEnvironment MOV R4,R1 MOV R0,R2 Push "R2-R4" BL mapin ; map in area to be free'd MOV R4,#&10000000 BL SafeChangeDynamic Pull "R2-R4" CLRV MOV R0,#ModHandReason_Free BL XROS_Module ; free the slot 45 MOV R1,R4 MOV R0,#14 SWI XOS_ChangeEnvironment ; return environment to how it was MOV R1,R3 MOV R0,#0 SWI XOS_ChangeEnvironment BL mapslotin ; put current task back Pull "R0-R4,PC" 50 | BL maptofreepool CMP R2,#nullptr MOVNE R0,#ModHandReason_Free BLNE XROS_Module Pull "PC" ] ; ; Entry: R2 --> slot block ; Exit: pages mapped to base of free pool ; page numbers put into free pool (lowest page last) ; [freepoolbase] updated ; maptofreepool ROUT Push "R1-R7,LR" ; CMP R2,#nullptr Pull "R1-R7,PC",EQ ; no block! ; LDR R6,freepool LDR R7,freepoolpages ; R7 = number of pages in free pool ADD R6,R6,R7,LSL #2 ADD R6,R6,R7,LSL #3 ; R6 -> terminators of free pool MOV R0,R6 ; R0 -> block for OS_SetMemMapEntries LDR R1,pagesize LDR R4,freepoolbase ; R4 -> next address MOV R5,#2 ; R5 = protection level 01 LDR R3,[R2],#12 ; R3 = page number CMP R3,#nullptr SUBNE R4,R4,R1 STMNEIA R6!,{R3,R4,R5} ; page number, address, protection level ADDNE R7,R7,#1 BNE %BT01 STR R4,freepoolbase STR R7,freepoolpages MOV R14,#-1 STR R14,[R6] ; terminator SWI XOS_SetMemMapEntries Pull "R1-R7,PC" ; don't alter memorylimit ; ; mapslotin ; all pages in a slot are put into the application space (&8000) ; Entry: [taskhandle] = current task ; Exit: pages mapped in ; handlers (eg. MemoryLimit) are also set up from task data ; mapslotin ROUT Push "R1-R4,LR" ; LDR R14,taskhandle LDR R1,[wsptr,R14] ; R1 --> task block CMP R1,#0 Pull "R1-R4,PC",LE ; task is dead (shouldn't happen) ; LDR R0,[R1,#task_slotptr] CMP R0,#nullptr ; no slot allocated BLNE mapin ; (corrupts R2) ; LDR R14,taskhandle LDR R4,[wsptr,R14] ; NB task cannot be dead ADD R4,R4,#task_environment ; MOV R0,#0 ; handler number 01 LDMIA R4!,{R1-R3} ; restore task handler data SWI XOS_ChangeEnvironment ADD R0,R0,#1 CMP R0,#MaxEnvNumber BCC %BT01 ; Pull "R1-R4,PC" ; ; Entry: R0 --> block suitable for passing to OS_SetMemMapEntries ; Exit: the pages in the block are mapped into the application area ; mapin ROUT MOV R2,#ApplicationStart ; Entry: R0 --> page map block ; R2 --> start address of place to map pages to ; Exit: R2 --> after the memory mapslot ROUT Push "R1,R3,LR" ; LDR R3,pagesize MOV R1,R0 01 LDR R14,[R1],#4 CMP R14,#0 STRGE R2,[R1],#8 ; next page ADDGE R2,R2,R3 BGE %BT01 ; SWI XOS_SetMemMapEntries ; Pull "R1,R3,PC" ; ; mapslotout ; all pages in a slot are put out of the way ; Entry: [taskhandle] = current task ; Exit: pages mapped out ; mapslotout ROUT Push "R1-R6,LR" ; LDR R14,taskhandle LDR R6,[wsptr,R14] ; R6 --> task block CMP R6,#0 Pull "R1-R6,PC",LE ; task is dead already ; ADD R5,R6,#task_environment MOV R0,#0 01 TEQ R0,#EscapeHandler ; we must replace these now, TEQNE R0,#EventHandler ; since they are dangerous! TEQNE R0,#UpCallHandler MOVNE R1,#0 MOVNE R2,#0 MOVNE R3,#0 SWIEQ XOS_ReadDefaultHandler ; replace with 'kosher' handlers SWI XOS_ChangeEnvironment ; set, and read original settings STMIA R5!,{R1-R3} ; old data ADD R0,R0,#1 CMP R0,#MaxEnvNumber BCC %BT01 ; LDR R0,[R6,#task_slotptr] CMP R0,#nullptr ; R0 --> slot block BLNE mapout ; NB do this afterwards! ; Pull "R1-R6,PC" ; ; Entry: R0 --> block suitable for passing to OS_SetMemMapEntries ; Exit: all pages referenced in the block are mapped out of the way ; mapout ROUT Push "R1-R3,LR" ; MOV R2,#-1 ; map out of the way LDR R3,pagesize MOV R1,R0 01 LDR R14,[R1],#4 CMP R14,#0 STRGE R2,[R1],#8 ; next page BGE %BT01 ; SWI XOS_SetMemMapEntries ; Pull "R1-R3,PC" ;;---------------------------------------------------------------------------- ;; *WimpSlot command (for changing amount of application space) ;;---------------------------------------------------------------------------- ^ 0 vec_min # 4 ; fields in output vector vec_max # 4 vec_next # 4 ss_outputvec * &100 Keydef DCB "min,max,next", 0 ; -min no longer compulsory ALIGN WimpSlot_Code ROUT Push "R11,R12,LR" LDR wsptr,[R12] MOV R11,sp ; remember stack for later ; SUB sp,sp,#ss_outputvec ; local workspace ; ; scan the comand line by calling OS_ReadArgs ; MOV R1,R0 ; R1 = input string ADR R0,Keydef ; R0 = key definition string MOV R2,sp ; R2 = output vector MOV R3,#ss_outputvec ; R3 = max output vector length SWI XOS_ReadArgs BVS %FT99 ; ; scan the resulting vector for known fields ; MOV R0,#MemoryLimit MOV R1,#0 SWI XOS_ChangeEnvironment SUB R3,R1,#ApplicationStart ; R3 = current amount of memory ; LDR R1,[sp,#vec_min] CMP R1,#0 BEQ %FT01 BL getminmax ; R0 = min memory BVS %FT99 CMP R0,R3 BLS %FT01 ; Push "R0" ; R0 = new current slot size MOV R1,#-1 ; leave next slot alone SWI XWimp_SlotSize Pull "R1" BVS %FT99 CMP R0,R1 ; R0=actual size, R1=required size BLO err_notenoughmemory MOV R3,R0 ; R3 = new amount of memory 01 LDR R1,[sp,#vec_max] CMP R1,#0 BEQ %FT02 BL getminmax ; R0 = max memory BVS %FT99 CMP R0,R3 MOVLO R1,#-1 ; leave next slot alone SWILO XWimp_SlotSize 02 LDR R1,[sp,#vec_next] CMP R1,#0 BEQ %FT99 BL getminmax ; R0 = new next slot size MOVVC R1,R0 MOVVC R0,#-1 ; leave current slot alone SWIVC XWimp_SlotSize 99 MOV sp,R11 Pull "R11,R12,PC" err_notenoughmemory MOV R0,R1,ASR #10 ; R0 = size in K ; SUB SP,SP,#32 ; allocate buffer big enough ; MOV R1,SP MOV R2,#20 SWI XOS_BinaryToDecimal ; convert to a string ADDVS SP,SP,#32 BVS %BT99 ; (exit if it errored) ; MOV R0,#0 STRB R0,[R1,R2] ; terminate the string ; Push "R4,R5" ; MOV R4,R1 ; -> string to use MOV R5,#0 MOV R3,#errordynamicsize-4 ADRL R2,errordynamic+4 ; -> buffer to fill in ADR R0,errmem BL LookupToken ; Pull "R4,R5" ADD SP,SP,#32 ; balance the stack ; ADRL R0,errordynamic LDR R1,=ErrorNumber_ChDynamNotAllMoved STR R1,[R0] ; SETV B %BT99 ; exit having setup the error block [ STB errmem DCB "ErrMemS",0 ; simple message | errmem DCB "ErrMem",0 ; original one ] ALIGN ; ; Entry: R1 --> string ; Exit: R0 = parameter value (number) ; Errors: "Bad number" ; getminmax ROUT Push "R1-R3,LR" ; MOV R0,#10 SWI XOS_ReadUnsigned Pull "R1-R3,PC",VS ; LDRB R3,[R1] ASCII_UpperCase R3, R14 TEQ R3,#"K" ; if terminator is "K" or "k", ADDEQ R1,R1,#1 MOVEQ R2,R2,LSL #10 ; multiply by 1024 TEQ R3,#"M" ; if terminator is "M" or "m", ADDEQ R1,R1,#1 MOVEQ R2,R2,LSL #20 ; multiply by 1048576 TEQ R3,#"G" ; if terminator is "G" or "g", ADDEQ R1,R1,#1 MOVEQ R2,R2,LSL #30 ; multiply by 1073741824 ; LDRB R14,[R1] ; check terminator RSBS R14,R14,#" "+1 ; ensure GT set if OK MyXError BadNumb,LE ; MOVVC R0,R2 ; R0 = answer Pull "R1-R3,PC" MakeInternatErrorBlock BadNumb,,BadParm ;;---------------------------------------------------------------------------- ;; Stuff to deal with OS_ChangeDynamicArea ;;---------------------------------------------------------------------------- ; ; intercept OS_ChangeDynamicArea ; initdynamic ROUT [ :LNOT: FreePoolWCF [ Medusa [ true Push "R0-R2,lr" MOV R0,#6 SWI XOS_ReadDynamicArea ; is there a kernel free pool Pull "R0-R2,lr" MOVVC PC,lr CLRV | MOV PC,lr ] ] ] Push "R1-R4,LR" ; ADR R0,RAM_SWIEntry LDR R1,copyofRAMcode+0 LDR R2,copyofRAMcode+4 ADR R3,My_ChangeDynamic LDR R14,=SvcTable + 4 * OS_ChangeDynamicArea LDR R4,[R14] ; R4 = old SWI entry TEQ R4,R0 ; if already in, forget it! STMNEIA R0,{R1-R4} STRNE R0,[R14] ; R0 = RAM_SWIEntry ; synchronise with respect to modified code at RAM_SWIEntry MOVNE R1,R0 ; start address ADDNE R2,R1,#4 ; end address (inclusive) for 2 words (other 2 are addresses) MOVNE R0,#1 ; means R1,R2 specify range SWINE XOS_SynchroniseCodeAreas ; do the necessary Pull "R1-R4,PC" copyofRAMcode SUB R12,PC,#:INDEX:RAM_SWIEntry+8 LDR PC,[PC,#-4] ASSERT (.-copyofRAMcode = 8) ASSERT (OScopy_ChangeDynamic-RAM_SWIEntry = 12) resetdynamic ROUT [ :LNOT: FreePoolWCF [ Medusa MOV PC,lr ] ] Push "R1,LR" ; ; happy note for StrongARM - this is not a code modification (vector address change only) ; LDR R1,=SvcTable + 4 * OS_ChangeDynamicArea LDR R14,OScopy_ChangeDynamic STR R14,[R1] ; Pull "R1,PC" LTORG ;---------------------------------------------------------------------------- ; OS_ChangeDynamicArea ; Entry: R0 = area to move (0=system heap, 1=RMA, 2=screen) ; R1 = amount to move (+ve ==> take away from application space) ; Exit: R1 = amount actually moved ; Errors: not all bytes moved (0 moved if R1 was +ve) ; ; if freepool < 0 or CAO pointer <> Wimp, ; then just pass it on ; else if not enough free pool memory, grab some from current slot ; map all pages into the application space ; reset ApplicationSpaceSize/MemoryLimit to their original values ; branch to the OS code ;----------------------------------------------------------------------------- LTORG My_ChangeDynamic ROUT Push "R0-R5,LR" [ Medusa :LAND: FreePoolWCF ADRL R14,freepoolinuse LDRB R2,[R14] TEQ R2,#0 BEQ goto_osentry ; free pool is in use by WCF, must trap with 'memory cannot be moved' MOV R1,#0 ADD SP,SP,#8 MyXError ChDynamNotAllMoved Pull "R2-R5,lr" ORR lr,lr,#V_bit LDR PC,=BranchToSWIExit MakeInternatErrorBlock ChDynamNotAllMoved,,ErrNoMv LTORG 05 ] ; ; if freepool>0, the Wimp MUST be in control ; LDR R14,freepool CMP R14,#nullptr2 BHS goto_osentry ; LDR R14,ptr_IRQsema ; if in IRQ, forget it! LDR R14,[R14] TEQ R14,#0 BNE goto_osentry ; LDRB R14,memoryOK ; check for re-entrancy TST R14, #mem_remapped BNE goto_osentry ; shouldn't ever happen TST R14, #mem_claimed ; if free memory claimed BNE noslot ; then continue, but trap it in Service_Memory ; ; work out if the current free pool is sufficient to meet the demand ; if not, see whether the current application would like to give some up ; LDR R14,freepoolpages ; R14 = number of free pages LDR R0,pagesize MUL R14,R0,R14 ; R14 = free memory LDR R1,[sp,#4] SUBS R14,R14,R1 ; R14 = extra needed (if -ve) BGE noslot SUB R0,R0,#1 ; round to next lower page boundary BIC R0,R14,R0 ; assume pagesize = 2^n ; BL readCAOpointer ; OS_ChangeEnvironment -> R2 LDR R14,orig_applicationspacesize CMP R2,R14 BCC noslot ; can't do it ADRL R14,Module_BaseAddr TEQ R2,R14 BEQ %FT02 ; OK if Wimp active - don't even ask! ; MOV R1,#Service_Memory ; R0 = amount to change area by SWI XOS_ServiceCall CMP R1,#0 ; clear V! BEQ noslot ; can't do it 02 Push "R0" ; amount to move (-ve) MOV R0,#ApplicationSpaceSize MOV R1,#0 SWI XOS_ChangeEnvironment ; R1 = size of current slot Pull "R0" SUB R1,R1,#ApplicationStart ; convert from end address to SIZE ADDS R0,R1,R0 ; R0 = new slot size (if -ve, ignore) MOVGE R1,#-1 SWIGE XWimp_SlotSize ; I hope this works! noslot ; ; map all slots into application space ; MOV R0,#CAOPointer ; Wimp active during OS_ChangeDynamic ADRL R1,Module_BaseAddr SWI XOS_ChangeEnvironment STR R1,oldCAOpointer ;; MUST RESTORE CAOPOINTER !!! ; ; swap total memory limits with local ones ; MOV R0,#MemoryLimit LDR R1,orig_memorylimit SWI XOS_ChangeEnvironment STR R1,orig_memorylimit ; swap these over ; MOV R0,#ApplicationSpaceSize LDR R1,orig_applicationspacesize STR R1,oldapplimit ; used later SWI XOS_ChangeEnvironment STR R1,orig_applicationspacesize ; swap these over ; ; map all slots into the area above the current one ; BL rackupslots ; R1 --> address to start from ; current task is left alone ; ; free pool is already present at the top end of the memory ; check that we now have a contiguous block of memory ; LDRB R14,memoryOK ORR R14,R14,#mem_remapped ; set flag for Service_Memory STRB R14,memoryOK goto_osentry Pull "R0-R5,LR" LDR PC,OScopy_ChangeDynamic ; ; Entry: R1 --> address to start putting slots at ; Exit: all slots mapped into application space, not overlapping ; R2 --> end address of slots ; R0,R1,R3,R4 trashed ; rackupslots ROUT Push "LR" ; MOV R2,R1 ; start mapping from here ADRL R1,taskpointers LDR R3,taskhandle ; this one's been done already ADD R3,wsptr,R3 MOV R4,#maxtasks 01 TEQ R1,R3 ; is this the current task? LDR R14,[R1],#4 ; NB always increment R1 TEQNE R14,#task_unused LDRNE R0,[R14,#task_slotptr] MOVEQ R0,#nullptr CMP R0,#nullptr BLNE mapslot ; updates [R0..], R2 SUBS R4,R4,#1 BNE %BT01 ; Pull "PC" ; ; Entry: all slots mapped into application space, consecutively ; Exit: all slots except the current one are mapped out ; R0-R4 trashed ; unrackslots ROUT Push "LR" ; ADRL R1,taskpointers LDR R3,taskhandle ; leave this one alone ADD R3,wsptr,R3 MOV R4,#maxtasks 01 TEQ R1,R3 ; is this the current task? LDR R14,[R1],#4 ; NB always increment R1 TEQNE R14,#task_unused LDRNE R0,[R14,#task_slotptr] MOVEQ R0,#nullptr CMP R0,#nullptr BLNE mapout SUBS R4,R4,#1 BNE %BT01 ; Pull "PC" [ Medusa ;----------------------------------------------------------------------------- ; Service_PagesSafe interception ; Entry: R2 No. of pages to move ; R3 page list before move ; R4 page list after move ;----------------------------------------------------------------------------- DCB "PagesSafe" ALIGN servicepagessafe Push "R0-r8,lr" ; SWI &107 ; beep when this happens MOV R0,#0 ADD R5,R2,#1 MOV R8,R4 MOV R4,R3 01 SUBS R5,R5,#1 BEQ %FT09 LDR R6,[R4],#12 CMP R6,#-1 BEQ %FT09 LDR R7,[R8],#12 ; 3-word entries MOV R0,#-1 ADRL R3,taskpointers 03 ADD R0,R0,#1 CMP R0,#maxtasks BEQ %FT11 LDR R2,[R3,R0, LSL #2] TEQ R2,#task_unused BEQ %BT03 LDR R2,[R2,#task_slotptr] CMP R2,#-1 BEQ %BT03 05 LDR R1,[R2],#12 CMP R1,#-1 BEQ %BT03 CMP R1,R6 BNE %BT05 STR R7,[R2,#-12] B %BT01 09 Pull "R0-R8,PC" 11 ; just in case 1-tasking & task isn't in the list LDR R0,taskhandle LDR R2,singletaskhandle CMP R0,R2 BNE %BT01 LDR R0,pendingtask CMP R0,#1 BLT %BT01 LDR R2,[R0,#task_slotptr] CMP R2,#-1 BEQ %BT01 13 LDR R1,[R2],#12 CMP R1,#-1 BEQ %BT01 CMP R1,R6 BNE %BT13 STR R7,[R2,#-12] B %BT01 ] ;----------------------------------------------------------------------------- ; Service_Memory interception ; Entry: R0 = amount application space would be altered by ; R2 = CAO pointer ;----------------------------------------------------------------------------- servicememory ROUT [ Medusa [ true Push "R0-R2,lr" MOV R0,#6 SWI XOS_ReadDynamicArea ; is there a kernel free pool Pull "R0-R2,lr" ; BVC medusaaboutto MOVVC PC,lr CLRV | MOV PC,lr ] ] Push "R0-R3,LR" ; Debug dy,"Service_Memory: CAO pointer, amount to move =",R2,R0 ; LDR R14,freepool ;; Wimp 1.89o onwards CMP R14,#nullptr ;; BNE %FT01 ;; only allow paging if LDR R14,taskhandle ;; the "owner" slot is active LDR R1,inithandle ;; TEQ R1, R14 ;; TMD: actually do the comparison! BNE serviceclaim ;; 01 LDRB R14, memoryOK ; if free memory has been claimed TST R14, #mem_claimed ; then refuse to move memory BNE serviceclaim ADRL R14,Module_BaseAddr TEQ R2,R14 ; are we in control? Pull "R0-R3,PC",NE TEQ R0,#IsAnybodyThere ; if this is the Wimp, allow it Pull "R0-R3,PC",EQ ; LDR R14,freepool ; is there a free pool? CMP R14,#nullptr2 Pull "R0-R3,PC",EQ ; freepool=-2 ==> OK (not running) CMP R14,#nullptr LDRNEB R14,memoryOK ; if not remapped already, stop this! TSTNE R14,#mem_remapped ; (usually because memory claimed) BEQ serviceclaim ; LDR R1,oldapplimit ; orig_applicationspacesize is wrong LDR R0,[sp] ; (has been swapped with local one) ADD R0,R1,R0 ; proposed new end-of-memory LDR R14,freepoolbase CMP R0,R14 Pull "R0-R3,PC",CS serviceclaim MOV R14,#0 STR R14,[sp,#1*4] ; claim service if not enough memory Pull "R0-R3,PC" [ Medusa [ {FALSE} medusaaboutto Push "R0,lr" ADRL R0,Module_BaseAddr TEQ R0,R2 Pull "R0,PC",NE LDR R0,inithandle LDR R14,taskhandle TEQ R0,R14 MOVNE R1,#0 Pull "R0,PC" ] medusaservicemem ; page may have been taken out of application space ; the slot block must be updated. Push "R0-R3,lr" ; first check pending task LDR R14,pendingtask MOVS R0,R14,ASR #31 LDREQ R0,[R14,#task_slotptr] CMP R0,#nullptr SWINE XOS_FindMemMapEntries BNE %FT05 LDR R14,taskhandle CMP R14,#0 Pull "R0-R3,PC",EQ LDR R14,[wsptr,R14] MOVS R0,R14,ASR #31 LDREQ R0,[R14,#task_slotptr] CMP R0,#nullptr SWINE XOS_FindMemMapEntries 05 Pull "R0-R3,PC" ] ;----------------------------------------------------------------------------- ; Service_MemoryMoved interception ; Put pages back into their proper positions ;----------------------------------------------------------------------------- servicememorymoved ROUT [ Medusa [ true Push "R0-R2,lr" MOV R0,#6 SWI XOS_ReadDynamicArea ; is there a kernel free pool Pull "R0-R2,lr" BVC medusaservicemem CLRV | MOV PC,lr ] ] Push "R0-R7,R10-R11,LR" ; LDR R14,ptr_IRQsema ; if in IRQ, forget it! LDR R14,[R14] TEQ R14,#0 Pull "R0-R7,R10-R11,PC",NE ; TEQP PC,#SVC_mode ; enable interrupts (bug in MOS) ; LDR R14,freepool ; no messing about if no free pool CMP R14,#nullptr2 Pull "R0-R7,R10-R11,PC",EQ ; Wimp not involved at all BLO %FT01 ; Wimp has a free pool to maintain ; LDR R0,taskhandle ;; Wimp 1.89o onwards LDR R14,inithandle ;; TEQ R0,R14 ;; update these if "owner" slot Pull "R0-R7,R10-R11,PC",NE ;; is being altered ; ;; MOV R0,#ApplicationSpaceSize ;; restorepages uses these later MOV R1,#0 ;; SWI XOS_ChangeEnvironment ;; STRVC R1,orig_applicationspacesize ;; MOV R0,#MemoryLimit ;; MOV R1,#0 ;; SWI XOS_ChangeEnvironment ;; STRVC R1,orig_memorylimit ;; ;; Pull "R0-R7,R10-R11,PC" ;; 01 LDRB R14,memoryOK ; if not remapped, forget it TST R14,#mem_remapped Pull "R0-R7,R10-R11,PC",EQ ; ; restore correct CAO pointer (forced to be Wimp during OS_ChangeDynamic) ; MOV R0,#CAOPointer LDR R1,oldCAOpointer SWI XOS_ChangeEnvironment ; ignore errors ; ; scan all slots to see if the memory has moved ; ADRL R5,taskpointers MOV R4,#maxtasks 01 LDR R14,[R5],#4 MOVS R0,R14,ASR #31 ; R0 = 0 (OK) or -1 (no slot) LDREQ R0,[R14,#task_slotptr] CMP R0,#nullptr SWINE XOS_FindMemMapEntries ; R10 --> new map, R0 --> slot SUBS R4,R4,#1 ; clears V BNE %BT01 ; ; don't forget the 'pending' slot ; LDR R14,pendingtask ;; this was missing in Risc OS 2.00 MOVS R0,R14,ASR #31 ;; LDREQ R0,[R14,#task_slotptr] ;; essential for screen remapping CMP R0,#nullptr ;; SWINE XOS_FindMemMapEntries ;; ; ; restore the current orig_applicationspacesize/memorylimit for this slot ; BL restorememlimit LDR R3,oldapplimit STR R1,orig_memorylimit ; these must be equal STR R1,orig_applicationspacesize ; ; reconstruct the free slot by entering the expected addresses ; note that sometimes more than just the free pool will have been removed ; LDR R2,freepool ; R1 -> end of memory, R2 -> free slot BL findfreepool ; fills in free pool MOV R1,#2 ; no USR mode read/write BL setslotaccess ; ; map out all applications except the current one ; NB: this is important so that pages cannot coincide later ; BL unrackslots ; LDRB R14,memoryOK BIC R14,R14,#mem_remapped ; should be alright again now! STRB R14,memoryOK ; Pull "R0-R7,R10-R11,PC" ] ;;---------------------------------------------------------------------------- ;; Resource files ;;---------------------------------------------------------------------------- romsprites DCD 16,0,16,16 ; null area just in case resourcefsfiles [ standalone:LOR:RegisterMessages ResourceFile $MergedMsgs, Resources.Wimp.Messages ] [ standalone:LOR:RegisterTemplates [ NewErrorSystem ResourceFile Resources...Template3D, Resources.Wimp.Templates ; AMcC 18-Oct-94 was Template3D | ResourceFile Resources...Templates, Resources.Wimp.Templates ] ] [ standalone:LOR:RegisterTools3D ResourceFile Resources...Tools3d, Resources.Wimp.Tools ] [ standalone:LOR:RegisterTools2D ResourceFile Resources...Tools, Resources.Wimp.Tools ] [ RegisterSprites ResourceFile Resources...Sprites, Resources.Wimp.Sprites ] [ RegisterSprites22 ResourceFile Resources...Sprites22, Resources.Wimp.Sprites22 ] [ RegisterWIMPSymbolFont ResourceFile Resources.!WIMPSym.WIMPSymbol.Encoding, Fonts.WIMPSymbol.Encoding ResourceFile Resources.!WIMPSym.WIMPSymbol.f240x120, Fonts.WIMPSymbol.f240x120 ResourceFile Resources.!WIMPSym.WIMPSymbol.IntMetrics, Fonts.WIMPSymbol.IntMetrics ResourceFile Resources.!WIMPSym.WIMPSymbol.Outlines, Fonts.WIMPSymbol.Outlines ] [ :LNOT: NoDarwin [ RealDarwin ResourceFile Resources.!Darwin.Darwin.f240x120, Fonts.Darwin.Medium.f240x120 ResourceFile Resources.!Darwin.Darwin.IntMetrics, Fonts.Darwin.Medium.IntMetrics | ResourceFile Resources.!Homerton.homerton.IntMetric0, Fonts.Darwin.Medium.IntMetric0 ResourceFile Resources.!Homerton.homerton.Outlines0, Fonts.Darwin.Medium.Outlines0 ] ] [ standalone :LAND: false ResourceFile Resources.desktop, Resources.Desktop.Messages ] DCD 0 END