4 ; Memory management in a dynamic area
6 ; © 1994-1998 Straylight
8 ;----- Licensing note -------------------------------------------------------
10 ; This file is part of Straylight's Dynamite
12 ; Dynamite is free software; you can redistribute it and/or modify
13 ; it under the terms of the GNU General Public License as published by
14 ; the Free Software Foundation; either version 2, or (at your option)
17 ; Dynamite is distributed in the hope that it will be useful,
18 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ; GNU General Public License for more details.
22 ; You should have received a copy of the GNU General Public License
23 ; along with Dynamite. If not, write to the Free Software Foundation,
24 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 ;----- Standard header ------------------------------------------------------
33 ;----- External dependencies ------------------------------------------------
44 IMPORT |Dynamite$$Commands$$Base|
46 ;----- Module header --------------------------------------------------------
48 AREA |!!!Module$$Header|,CODE,READONLY
50 dyn__base DCD dt_run ;Application code
51 DCD dyn__init ;Initialisation
52 DCD dyn__quit ;Finalisation
53 DCD dt_service ;Service call handling
54 DCD dyn__name ;Module title string
55 DCD version ;Module help string
56 DCD |Dynamite$$Commands$$Base| ;Command table
57 DCD &4A3C0 ;SWI chunk number
58 DCD dyn__swis ;SWI handler code
59 DCD dyn__swiNames ;SWI name table
60 DCD 0 ;SWI name-number code
62 dyn__name DCB "Dynamite",0
64 ;----- Main module code -----------------------------------------------------
66 AREA |Dynamite$$Code|,CODE,READONLY
72 ; On exit: R14 == base address of module
74 ; Use: Finds the base address of the module.
91 ; Use: Claims some memory, and intercepts OS_ChangeDynamicArea.
95 STMFD R13!,{R7,R8,R14} ;Save some registers
97 ; --- Allocate module workspace ---
99 MOV R0,#6 ;Claim RMA workspace
100 LDR R3,=dyn_wSize ;Get my workspace size
101 SWI XOS_Module ;Allocate the workspace
102 LDMVSFD R13!,{R7,R8,PC} ;If it failed, return error
103 STR R2,[R12,#0] ;Save workspace address
104 MOV R12,R2 ;Point to workspace nicely
105 STR R12,dyn__wsAddr ;Store for my patch code
107 MOV R0,#0 ;Initialise some workspace
108 STR R0,dyn_areaSize ;Dynamic area not created yet
109 STR R0,dyn_heapSize ;No data in the heap
110 STR R0,dyn_lockCount ;And clear the lock counter
111 STR R0,dyn_launch ;Make RMRun do clever stuff
112 STR R0,dyn_taskHandle ;And make the task handle 0
113 STR R0,dyn_ancTable ;Clear the free anchor table
114 STR R0,dyn_ancList ;And the anchor block list
115 MOV R0,#hpFlag_tidy ;We are compacted now
116 STR R0,dyn_hpFlags ;So make a note of this
118 ADR R14,dyn_stack ;Point to reloc stack base
119 STR R14,dyn_stackPtr ;Save as the stack pointer
121 ; --- Claim OS_ChangeDynamicArea ---
123 ; We trap this in the kernel branch table, rather than at
124 ; the SWI vector, because it's so much easier.
126 SWI XOS_ReadMemMapInfo ;Read nice things
127 STR R0,dyn_pageSize ;Save the page size
128 SUB R1,R1,#1 ;Chop one off for da_findPage
129 STR R1,dyn_pageCount ;And the number of them
130 MOV R14,#0 ;Log 2 of page size
131 00dyn__init TST R0,#1 ;Is bottom bit set yet?
132 MOVEQ R0,R0,LSR#1 ;No -- shift along a bit
133 ADDEQ R14,R14,#1 ;Add to the log
134 BEQ %00dyn__init ;And keep on going
135 STR R14,dyn_log2PageSize ;And store this away
137 MOV R0,#129 ;The OS_Byte number
139 MOV R2,#255 ;...jubbly!
140 SWI XOS_Byte ;Get OS Version number
141 STR R1,dyn_machine ;Store this away
142 CMP R1,#&A5 ;Is this a RISC PC?
143 BGE %50dyn__init ;Yes -- jump ahead then
144 CMP R1,#&A3 ;Is it RISC OS 2?
145 LDRLT R0,=&ABC ;Yes --- this is sprarea size
146 LDRGE R0,=&ACC ;No -- this is then
147 STR R0,dyn_sprSize ;Save in the workspace
149 MOV R6,PC ;Get the current status
150 TST R6,#IRQ_disable ;Are IRQs enabled?
151 TEQEQP R6,#IRQ_disable ;Yes -- disable them then
153 LDR R0,=&01F033FC ;Find the kernel dispatcher
154 LDR R14,[R0,#OS_ChangeDynamicArea*4]
155 STR R14,dyn_oldChnArea ;Save this in my workspace
156 ADR R14,dyn__patch ;Point to my patch routine
157 STR R14,[R0,#OS_ChangeDynamicArea*4]
159 LDR R14,[R0,#OS_ReadDynamicArea*4]
160 STR R14,dyn_oldReadArea ;Save this in my workspace
161 ADR R14,dyn__readPatch ;Point to my patch routine
162 STR R14,[R0,#OS_ReadDynamicArea*4]
164 LDR R14,[R0,#OS_ValidateAddress*4]
165 STR R14,dyn_oldValidate ;Save this in my workspace
166 ADR R14,dyn__valPatch ;Point to my patch routine
167 STR R14,[R0,#OS_ValidateAddress*4]
168 TEQP R6,#0 ;Restore interrupt status
169 MOV R0,R0 ;Shut the assembler up
171 ; --- Find the TaskManager and WindowManager addresses ---
173 ADR R6,dyn_switchBase ;Point to bit of workspace
174 MOV R0,#18 ;Look up modules by name
175 ADR R1,dyn__switcher ;Point to the Switcher's name
176 SWI XOS_Module ;Try and find its address
177 MOVVS R3,#0 ;If not there, dummy address
178 MOVVS R4,#0 ;For that and the end
179 LDRVC R4,[R3,#-4] ;Otherwise load module length
180 STMIA R6!,{R3,R4} ;Save them in workspace
182 ADR R1,dyn__wimp ;Point to the Wimp's name
183 SWI XOS_Module ;Try and find its address
184 MOVVS R3,#0 ;If not there, dummy address
185 MOVVS R4,#0 ;For that and the end
186 LDRVC R4,[R3,#-4] ;Otherwise load module length
187 STMIA R6!,{R3,R4} ;Save them in workspace
188 LDMFD R13!,{R7,R8,PC}^ ;Return to caller
190 ; --- The machine is a RISC PC -- lucky sod! ---
192 50dyn__init MOV R0,#0 ;Create dynamic area
193 MOV R1,#-1 ;No particular number
194 MOV R2,#0 ;Initial size of area
195 MOV R3,#-1 ;No particular base address
196 MOV R4,#&80 ;The area flags
197 MOV R5,#-1 ;No maximum size please
198 MOV R6,#0 ;No handler needed
199 MOV R7,#0 ;Workspace to pass to handler
200 ADR R8,dyn__areaName ;Dynamic area name
201 SWI XOS_DynamicArea ;Create the area
202 STRVC R1,dyn_areaHandle ;Store the handle
203 STRVC R3,dyn_areaBase ;And the base address
205 LDMFD R13!,{R7,R8,PC} ;Return to caller
207 dyn__switcher DCB "TaskManager",0
208 dyn__wimp DCB "WindowManager",0
209 dyn__areaName DCB "Dynamite",0
213 dyn__wsAddr DCD 0 ;Yuk -- address of workspace
221 ; Use: Tries to close Dynamite down.
225 STMFD R13!,{R12,R14} ;Save a register
226 LDR R12,[R12] ;Find my workspace address
228 ; --- Make sure we're not needed ---
230 BL dh_compact ;Compact the heap first
231 LDR R14,dyn_areaSize ;How much space are we using?
233 BNE %45dyn__quit ;No -- people might want them
234 LDR R14,dyn_stackPtr ;Load the stack pointer
235 ADR R0,dyn_stack ;Point to the stack base
236 CMP R14,R0 ;Are these equal?
237 BNE %45dyn__quit ;No -- we're still used then
239 ; --- Close down the compactor ---
241 LDR R14,dyn_taskHandle ;Get the task handle
242 CMP R14,#0 ;Is it a sensible one?
243 BLGT dt_quit ;Yes -- kill the task then
244 BL danc_quit ;Free all anchor blocks
246 ; --- Get rid of all used pages ---
248 LDR R0,dyn_areaSize ;Get the area size
249 LDR R1,dyn_log2PageSize ;And log 2 of page size
250 MOV R0,R0,LSR R1 ;Number of pages in area
251 BL da_removePages ;Remove pages
253 LDR R0,dyn_machine ;Get the machine type
254 CMP R0,#&A5 ;Is it a RISC PC?
255 BGE %60dyn__quit ;Yes -- jump ahead
257 ; --- First, try to release OS_ChangeDynamicArea ---
259 LDR R0,=&01F033FC ;Find the kernel dispatcher
260 LDR R1,[R0,#OS_ChangeDynamicArea*4]
261 ADR R14,dyn__patch ;Point to my patch routine
262 CMP R1,R14 ;Can I release it safely?
263 BNE %50dyn__quit ;No -- report an error
265 LDR R1,[R0,#OS_ReadDynamicArea*4]
266 ADR R14,dyn__readPatch ;Point to my patch routine
267 CMP R1,R14 ;Can I release it safely?
268 BNE %50dyn__quit ;No -- report an error
270 LDR R1,[R0,#OS_ValidateAddress*4]
271 ADR R14,dyn__valPatch ;Point to my patch routine
272 CMP R1,R14 ;Can I release it safely?
273 BNE %50dyn__quit ;No -- report an error
275 LDR R14,dyn_oldChnArea ;Load the previous value
276 STR R14,[R0,#OS_ChangeDynamicArea*4]
277 LDR R14,dyn_oldReadArea ;Load the previous value
278 STR R14,[R0,#OS_ReadDynamicArea*4]
279 LDR R14,dyn_oldValidate ;Load the previous value
280 STR R14,[R0,#OS_ValidateAddress*4]
282 ; --- Free the workspace I claimed ---
284 40dyn__quit MOV R0,#7 ;Free RMA workspace
285 MOV R2,R12 ;Point to my workspace
286 SWI XOS_Module ;Try to free it nicely
287 LDR R0,[R13],#4 ;Load private word address
288 MOV R14,#0 ;Clear private word value
289 STR R14,[R0,#0] ;To stop OS doing this too...
290 LDMFD R13!,{PC}^ ;Return to caller
292 ; --- We have handles or relocation entries ---
294 45dyn__quit ADRL R0,msg_errInUse ;Point to error message
295 LDMFD R13!,{R12,R14} ;Unstack some registers
296 ORRS PC,R14,#V_flag ;Return to caller with error
298 ; --- We couldn't release OS_ChangeDynamicArea ---
300 50dyn__quit ADRL R0,msg_errRelease ;Point to error message
301 LDMFD R13!,{R12,R14} ;Unstack some registers
302 ORRS PC,R14,#V_flag ;Return to caller with error
304 ; --- We're on a RISC PC ---
306 60dyn__quit MOV R0,#1 ;Remove dynamic area
307 LDR R1,dyn_areaHandle ;Get the area handle
308 SWI XOS_DynamicArea ;Remove it then
309 B %40dyn__quit ;Now free workspace etc.
315 ; On entry: As for ChangeDynamicArea
319 ; Use: Mangles ChangeDynamicArea when being used on the system
324 LDR R12,dyn__wsAddr ;Find my workspace address
325 CMP R0,#3 ;Is it the sprite area?
326 LDRNE PC,dyn_oldChnArea ;No -- continue as normal
328 ; --- Mangle the `remembered' size of the sprite area ---
330 STMFD R13!,{R14} ;Save another register
331 LDR R11,dyn_sprSize ;Find the size word
332 LDR R14,[R11,#0] ;Load total sprite area size
333 ADD R10,R14,R1 ;How much does he want?
334 CMP R10,#4*1024*1024 ;More than 4 megs?
335 BGT %90dyn__patch ;Yes -- that's an error
336 LDR R10,dyn_areaSize ;Load my area's size
337 SUB R14,R14,R10 ;Get the size of the sprites
338 STR R14,[R11,#0] ;Save that for the duration
340 ; --- This is nasty and complicated ---
342 ; Post processing on kernel SWIs is not something normally
343 ; to be enjoyed. The way things will have to be done is as
346 ; * We save R14 and the value &2002A (XOS_ChangeDynamicArea)
347 ; on the stack. The SWI value is so that we regain control
348 ; if something went sadly amiss.
350 ; * We call the previous OS_ChangeDynamicArea routine, having
351 ; set a suitably bogus return address.
353 ; * We mangle the system sprite area in a manner in keeping
354 ; with the aim of the program.
356 ; * Then we examine the status returned to us, and if V was
357 ; set AND the X bit of the R11 saved on the stack before
358 ; we were entered at the top was clear we call
361 MOV R11,#OS_ChangeDynamicArea ;Get the SWI number
362 ORR R11,R11,#&20000 ;Set the X bit nicely
363 STMFD R13!,{R10-R12} ;Save other registers here
364 STMFD R13!,{R11} ;And the obviously bogus R11
365 MOV R14,PC ;Set up a return address
366 LDR PC,dyn_oldChnArea ;And let it rip...
368 ; --- We have now done a ChangeDynamicArea ---
370 ; R14 saved above is on the stack, along with the caller's
371 ; R10-R12 from the OS SWI dispatcher.
373 LDR R11,dyn_sprSize ;Find the size word
374 LDR R14,[R11,#0] ;Load the new area size
375 ADD R14,R14,R10 ;Add the old difference
376 STR R14,[R11,#0] ;And save it back again
378 50dyn__patch LDMFD R13!,{R14} ;Get his return address
379 LDMFD R13!,{R11} ;Get the SWI number too
380 LDMVCFD R13!,{R10-R12} ;Restore his registers
381 BICVCS PC,R14,#V_flag ;And return control to him
383 TST R11,#&20000 ;Was the X bit set?
384 SWIEQ OS_GenerateError ;No -- do error like things
386 LDMFD R13!,{R10-R12} ;Restore his registers
387 ORRS PC,R14,#V_flag ;And return the error
389 ; --- He wanted too much memory ---
391 90dyn__patch ADRL R0,msg_errTooBig ;Point to the error
392 CMP R0,#&80000000 ;Create an overflow
393 B %50dyn__patch ;Make it look like it came
394 ;from ChangeDynamicArea
397 ; --- dyn__readPatch ---
399 ; On entry: R0 == dynamic area to read, and flags etc.
401 ; On exit: R1 == size of dynamic area, R2 == optional maximum size
403 ; Use: Reads the size of a dynamic area. If the caller is
404 ; interested in the sprite area AND they're not either the
405 ; TaskManager or the WindowManager, we mangle the result so
406 ; they think that the sprite area doesn't contain our clever
411 LDR R12,dyn__wsAddr ;Find my workspace address
412 BIC R10,R0,#&80 ;Clear the clever flag bit
413 CMP R10,#3 ;Is it the sprite area?
414 LDRNE PC,dyn_oldReadArea ;No -- continue as normal
416 ; --- Do all the work then ---
418 ; Seeing as we know all there is to know about the sprite
419 ; area, we can do all this here without the yukkiness of
422 STMFD R13!,{R2,R14} ;Save the link register
423 ADR R11,dyn_switchBase ;Find module addresses
424 BIC R10,R14,#&FC000003 ;Find caller's address
425 LDMIA R11!,{R1,R2} ;Load switcher base/size
426 SUB R14,R10,R1 ;Subtract switcher base
427 CMP R14,R2 ;Is it within switcher?
428 LDMHSIA R11!,{R1,R2} ;No -- load wimp base/size
429 SUBHS R14,R10,R1 ;Subtract wimp base
430 CMPHS R14,R2 ;Is it within wimp?
431 LDMFD R13!,{R2,R14} ;Unstack registers again
433 LDR R1,dyn_sprSize ;Find sprite area size word
434 LDR R1,[R1,#0] ;Load current sprite size
435 LDRHS R10,dyn_areaSize ;If caller is pleb, mangle it
436 SUBHS R1,R1,R10 ;By subtracting our heap size
437 TST R0,#&80 ;Does he want max size?
438 MOVNE R2,#4*1024*1024 ;Yes -- that's 4MB
439 MOV R0,#&01400000 ;Point to sprite area start
441 ADD R13,R13,#4 ;Skip past stacked R11
442 LDMFD R13!,{R10-R12} ;Unstack caller's registers
443 BICS PC,R14,#V_flag ;And return to caller
447 ; --- dyn__valPatch ---
449 ; On entry: As for OS_ValidateAddress
451 ; On exit: As for OS_ValidateAddress
453 ; Use: Mangles OS_ValidateAddress so that it gets our somewhat
454 ; rearranged sprite area correct. This is necessary due to
455 ; braindead implementation of OS_ValidateAddress. I'd like to
456 ; be able to do the job properly by hacking the CAM map, but
457 ; the Mysterious Background Address Validator assumes that the
458 ; SWI works in the way Acorn wrote it, so that's put the
459 ; kybosh on that plan.
463 LDR R12,dyn__wsAddr ;Find my workspace address
465 STMFD R13!,{R14} ;Save the link register
466 MOV R10,#&01400000 ;Get base of the sprite area
467 MOV R11,#&01800000 ;Get limit too
468 CMP R0,R10 ;Is it in there?
472 LDMCCFD R13!,{R14} ;No -- restore link
473 LDRCC PC,dyn_oldValidate ;And let OS_VA do it then
475 ; --- Check for weird sprite area thing and Dynamite area ---
477 LDR R11,dyn_sprSize ;Get address of sprite size
478 LDR R11,[R11,#0] ;Load size of sprite area
479 LDR R14,dyn_areaSize ;Load our area size
480 ADD R11,R10,R11 ;Find end of sprite area
481 SUB R10,R11,R14 ;Taking our area into account
482 MOV R11,#&01800000 ;Find top of sprite slot
483 SUB R11,R11,R14 ;Find bottom of our area
484 CMP R11,R0 ;This is deep -- think about
485 CMPHI R1,R10 ;it for a while.
486 LDMFD R13!,{R14} ;If it isn't invalid...
489 ORRHIS PC,R14,#C_flag
490 BICLSS PC,R14,#C_flag
496 ; On entry: R11 == SWI index
498 ; On exit: Depends on the SWI
500 ; Use: Dispatches SWIs to other routines
504 LDR R12,[R12] ;Find my module workspace
509 CMP R11,#(%10-%00)/4 ;Is the SWI in range?
510 ADDLO PC,PC,R11,LSL #2 ;Yes -- dispatch it then
511 B %10dyn__swis ;Otherwise report the error
513 00dyn__swis B dh_alloc ;Dynamite_Claim
514 B dh_free ;Dynamite_Free
515 B dh_freeWithID ;Dynamite_FreeWithID
516 B dh_blockInfo ;Dynamite_BlockInfo
517 B dh_changeID ;Dynamite_ChangeID
518 B dh_extend ;Dynamite_Resize
519 B dh_midExtend ;Dynamite_MidExtend
520 B dh_save ;Dynamite_Save
521 B dh_load ;Dynamite_Load
522 B dh_reduce ;Dynamite_Reduce
523 B dh_compact ;Dynamite_Compact
524 B dh_lock ;Dynamite_Lock
525 B dh_unlock ;Dynamite_Unlock
526 B danc_alloc ;Dynamite_ClaimAnchor
527 B danc_free ;Dynamite_ReleaseAnchor
528 B da_readSize ;Dynamite_ReadSpriteSize
529 B da_describe ;Dynamite_Describe
530 B dh_checkHeap ;Dynamite_IntegrityCheck
531 B dh_changeAnchor ;Dynamite_ChangeAnchor
533 10dyn__swis ADRL R0,msg_errBadSWI ;Point at the error
534 ORRS PC,R14,#V_flag ;And return it back
536 dyn__swiNames DCB "Dynamite",0
551 DCB "ReleaseAnchor",0
552 DCB "ReadSpriteSize",0
554 DCB "IntegrityCheck",0
560 ; --- *Dynamite_Clear ---
564 STMFD R13!,{R14} ;Save a register
565 LDR R12,[R12] ;Load the workspace address
567 ; --- Empty the heap ---
569 LDR R0,dyn_areaSize ;Get the area size
570 LDR R1,dyn_log2PageSize ;And log 2 of page size
571 MOV R0,R0,LSR R1 ;Number of pages in area
572 BL da_removePages ;Remove pages
574 ; --- Free all the anchors ---
576 BL danc_quit ;Free all allocated anchors
578 ; --- Reset the heap variables ---
580 MOV R0,#0 ;Initialise some workspace
581 STR R0,dyn_areaSize ;Dynamic area not created yet
582 STR R0,dyn_heapSize ;No data in the heap
583 STR R0,dyn_lockCount ;And clear the lock counter
584 STR R0,dyn_ancTable ;Clear the free anchor table
585 STR R0,dyn_ancList ;And the anchor block list
586 MOV R0,#hpFlag_tidy ;We are compacted now
587 STR R0,dyn_hpFlags ;So make a note of this
589 LDMFD R13!,{PC}^ ;And return to caller
595 AREA |Dynamite$$Commands|,CODE,READONLY
597 DCB "Dynamite_Clear",0
603 AREA |Dynamite$$Commands_End|,CODE,READONLY
606 ;----- That's all, folks ----------------------------------------------------