Commit cefb4815 authored by Jeffrey Lee's avatar Jeffrey Lee
Browse files

Reimplement AMBControl ontop of the PMP system

  With this set of changes, each AMB node is now the owner of a fake DANode which is linked to a PMP.
  From a user's perspective the behaviour of AMBControl is the same as before, but rewriting it to use PMPs internally offers the following (potential) benefits:
  * Reduction in the amount of code which messes with the CAM & page tables, simplifying future work/maintenance. Some of the AMB ops (grow, shrink) now just call through to OS_ChangeDynamicArea. However all of the old AMB routines were well-optimised, so to avoid a big performance hit for common operations not all of them have been removed (e.g. mapslot / mapsome). Maybe one day these optimal routines will be made available for use by regular PMP DAs.
  * Removal of the slow Service_MemoryMoved / Service_PagesSafe handlers that had to do page list fixup after the core kernel had reclaimed/moved pages. Since everything is a PMP, the kernel will now deal with this on behalf of AMB.
  * Removal of a couple of other slow code paths (e.g. Do_AMB_MakeUnsparse calls from OS_ChangeDynamicArea)
  * Potential for more flexible mapping of application space in future, e.g. sparse allocation of memory to the wimp slot
  * Simpler transition to an ASID-based task swapping scheme on ARMv6+?
  Other changes of note:
  * AMB_LazyMapIn switch has been fixed up to work correctly (i.e. turning it off now disables lazy task swapping and all associated code instead of producing a build error)
  * The DANode for the current app should be accessed via the GetAppSpaceDANode macro. This will either return the current AMB DANode, or AppSpaceDANode (if e.g. pre-Wimp). However be aware that AppSpaceDANode retains the legacy behaviour of having a base + size relative to &0, while the AMB DANodes (identifiable via the PMP flag) are sane and have their base + size relative to &8000.
  * Mostly-useless DebugAborts switch removed
  * AMBPhysBin (page number -> phys addr lookup table) removed. Didn't seem to give any tangible performance benefit, and was imposing hidden restrictions on memory usage (all phys RAM fragments in PhysRamTable must be multiple of 512k). And if it really was a good optimisation, surely it should have been applied to all areas of the kernel, not just AMB!
  Other potential future improvements:
  * Turn the fake DANodes into real dynamic areas, reducing the amount of special code needed in some places, but allow the DAs to be hidden from OS_DynamicArea 3 so that apps/users won't get too confused
  * Add a generic abort trapping system to PMPs/DAs (lazy task swapping abort handler is still a special case)
  File changes:
  - s/ARM600, s/VMSAv6, s/ExtraSWIs - Remove DebugAborts
  - s/ArthurSWIs - Remove AMB service call handler dispatch
  - s/ChangeDyn - AMB_LazyMapIn switch fixes. Add alternate internal entry points for some PMP ops to allow the DANode to be specified (used by AMB)
  - s/Exceptions - Remove DebugAborts, AMB_LazyMapIn switch fixes
  - s/Kernel - Define GetAppSpaceDANode macro, AMB_LazyMapIn switch fix
  - s/MemInfo - AMB_LazyMapIn switch fixes
  - s/AMBControl/AMB - Update GETs
  - s/AMBControl/Memory - Remove block size quantisation, AMB_BlockResize (page list blocks are now allocated by PMP code)
  - s/AMBControl/Options - Remove PhysBin definitions, AMBMIRegWords (moved to Workspace file), AMB_LimpidFreePool switch. Add AMB_Debug switch.
  - s/AMBControl/Workspace - Update AMBNode to contain an embedded DANode. Move AMBMIRegWords here from Options file.
  - s/AMBControl/allocate - Fake DA node initialisation
  - s/AMBControl/deallocate - Add debug output
  - s/AMBControl/growp, growshrink, mapslot, mapsome, shrinkp - Rewrite to use PMP ops where possible, add debug output
  - s/AMBControl/main - Remove PhysBin initialisation. Update the enumerate/mjs_info call.
  - s/AMBControl/memmap - Low-level memory mapping routines updated or rewritten as appropriate.
  - s/AMBControl/readinfo - Update to cope with DANode
  - s/AMBControl/service - Remove old service call handlers
  - s/AMBControl/handler - DA handler for responding to PMP calls from OS_ChangeDynamicArea; just calls through to growpages/shrinkpages as appropriate.
  Tested on pretty much everything currently supported

Version 5.66. Tagged as 'Kernel-5_66'
parent 6c47ed4d
......@@ -11,13 +11,13 @@
GBLS Module_HelpVersion
GBLS Module_ComponentName
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.65"
Module_Version SETA 565
Module_MajorVersion SETS "5.66"
Module_Version SETA 566
Module_MinorVersion SETS ""
Module_Date SETS "04 Dec 2016"
Module_ApplicationDate SETS "04-Dec-16"
Module_Date SETS "13 Dec 2016"
Module_ApplicationDate SETS "13-Dec-16"
Module_ComponentName SETS "Kernel"
Module_ComponentPath SETS "castle/RiscOS/Sources/Kernel"
Module_FullVersion SETS "5.65"
Module_HelpVersion SETS "5.65 (04 Dec 2016)"
Module_FullVersion SETS "5.66"
Module_HelpVersion SETS "5.66 (13 Dec 2016)"
/* (5.65)
/* (5.66)
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
#define Module_MajorVersion_CMHG 5.65
#define Module_MajorVersion_CMHG 5.66
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 04 Dec 2016
#define Module_Date_CMHG 13 Dec 2016
#define Module_MajorVersion "5.65"
#define Module_Version 565
#define Module_MajorVersion "5.66"
#define Module_Version 566
#define Module_MinorVersion ""
#define Module_Date "04 Dec 2016"
#define Module_Date "13 Dec 2016"
#define Module_ApplicationDate "04-Dec-16"
#define Module_ApplicationDate "13-Dec-16"
#define Module_ComponentName "Kernel"
#define Module_ComponentPath "castle/RiscOS/Sources/Kernel"
#define Module_FullVersion "5.65"
#define Module_HelpVersion "5.65 (04 Dec 2016)"
#define Module_LibraryVersionInfo "5:65"
#define Module_FullVersion "5.66"
#define Module_HelpVersion "5.66 (13 Dec 2016)"
#define Module_LibraryVersionInfo "5:66"
......@@ -20,19 +20,17 @@
; Mar 1997 mjs performance enhancements for Ursula OS
; Oct 2000 mjs Ursula code resurrected for 32-bit HALised kernel, hoorah!
GET s.AMBControl.Options
GET s.AMBControl.Workspace
GET s.AMBControl.main
GET s.AMBControl.allocate
GET s.AMBControl.deallocate
GET s.AMBControl.growshrink
GET s.AMBControl.handler
GET s.AMBControl.mapslot
GET s.AMBControl.mapsome
GET s.AMBControl.readinfo
GET s.AMBControl.growp
GET s.AMBControl.shrinkp
GET s.AMBControl.service
GET s.AMBControl.Memory
......@@ -19,18 +19,11 @@
; and claimed blocks from RMA, which is an anachronism since code is in
; the kernel.
; quantise sizes to reduce heap stress
AMBblockQ * 64
;in: r3=size
;out: r2 -> block, r0 corrupted
AMB_BlockClaim ROUT
Push "r1,r3,lr"
ADD r3,r3,#AMBblockQ - 1
BIC r3,r3,#AMBblockQ - 1
BL ClaimSysHeapNode
Pull "r1,r3,pc"
......@@ -42,19 +35,5 @@ AMB_BlockFree ROUT
BL FreeSysHeapNode
Pull "r1,pc"
;in: r2 -> block, r3 = new size
;out: r2 -> new block, r0 corrupted
AMB_BlockResize ROUT
Push "r1,r3,lr"
ADD r3,r3,#AMBblockQ - 1
BIC r3,r3,#AMBblockQ - 1
LDR r1,[r2,#-4] ;pick up OS_Heap's size word (naughty!)
SUB r1,r1,#4 ;heap size will be (at least) 4 more than quantised size
SUBS r3,r3,r1 ;required size change
MOVNE r0, #HeapReason_ExtendBlock
BLNE DoSysHeapOpWithExtension
Pull "r1,r3,pc"
......@@ -18,17 +18,6 @@
AMBMagicNodeID * &4E424D41 ;"AMBN"
AMBInitialMaxNodes * 256
AMBGrowMaxNodes * 64 ;not used now AMBControl is in kernel
;Bin pages by physical address, for quick mapping from page number to
;physical address. Bin entry holds physical address of first page in bin.
;Bin size must be no bigger than minimum physical RAM fragment to be found
;in machine. eg. 512k size gives 128 pages in a bin, so shift of 7 and
;mask of &7F. Max practical bin size is 1M (mask must be immediate constant).
AMBPhysBinShift * 7
AMBPhysBinMask * &7F
ApplicationStart * (32*1024)
......@@ -36,12 +25,6 @@ ApplicationStart * (32*1024)
AbsMaxAppSize * AplWorkMaxSize ;application space limit for RISC OS
AbsMaxAppPages * (AbsMaxAppSize:SHR:Log2PageSize) ;and same limit expressed in Pages
[ ChocolateAMB
AMBMIRegWords * (AbsMaxAppPages+31) :SHR: 5 ;no. of words for AMBMappedInRegister
;convenient to set this at fixed max size
;(only 896 bytes for 28Mb AppSpace)
;whether to check handles given to AMBControl - not very useful when in kernel
GBLL ValidateAMBHandles
......@@ -59,22 +42,16 @@ ValidateAMBHandles SETL {FALSE}
; Probably only worth supporting this on ARMs with simple instruction restart
; after abort (originally StrongARM revT or later for Ursula)
; AMB_LimpidFreePool - if {TRUE}, the cache(s) can be assumed to be clear with respect to the FreePool
; when AMBControl fetches pages from it. This allows AMBControl to avoid any
; cache clean/flush for moving pages out of the FreePool. This assumption is
; valid if either: FreePool pages are uncacheable; or FreePool pages are
; never used in situ; or FreePool pages are flushed after use in situ.
; AMB_ChocTrace - if {TRUE}, keep trace info for some enhanced code calls and data (probably development only)
GBLL AMB_LimpidFreePool
GBLL AMB_ChocTrace
AMB_LazyMapIn SETL {TRUE} :LAND: ChocolateAMB
AMB_LimpidFreePool SETL {TRUE} :LAND: ChocolateAMB ;allowed because FreePool is currently marked uncacheable
;current implementation assumes uncacheability as criterion
AMB_ChocTrace SETL {FALSE} :LAND: ChocolateAMB ;development only
......@@ -15,6 +15,12 @@
; > s.Workspace
[ AMB_LazyMapIn
AMBMIRegWords * (AbsMaxAppPages+31) :SHR: 5 ;no. of words for AMBMappedInRegister
;convenient to set this at fixed max size
;(only 896 bytes for 28Mb AppSpace)
;task node format
......@@ -24,11 +30,7 @@ AMBNode_id # 4 ;magic identifier
AMBNode_handle # 4 ;handle for external reference
AMBNode_prev # 4 ;ptr to previous node
AMBNode_next # 4 ;ptr to next node
AMBNode_pagetable # 0 ;data comprising page table from here on
AMBNode_Npages # 4 ;no. of pages in page list
AMBNode_startaddr # 4 ;logical address of first page (-1 means nowhere)
AMBNode_PPL # 4 ;Page flags, as limited by DynAreaFlags_AccessMask
AMBNode_pages # 0 ;list of page numbers from here on (1 word per page)
AMBNode_DANode # DANode_NodeSize ;DANode/PMP
AMBNode_HdrEnd # 0
AMBNode_HdrSize * AMBNode_HdrEnd - AMBNode_HdrStart
......@@ -42,8 +44,6 @@ AMBNhandles # 4 ;total handles available
AMBNtasks # 4 ;no. of tasks currently allocated
AMBMappedInNode # 4 ;node ptr of mapped-in task, or 0 for none
AMBNodeHandles # 4 ;ptr to node handle array (1 word per entry)
AMBPhysBin # 4 ;ptr to physical page bin array
AMBPhysBinEntries # 4 ;no. of entries in physical page bin array
[ AMB_LazyMapIn
AMBPageFlags # 4 ;L2PT page flags to use when (lazily) mapping in pages
......@@ -51,14 +51,12 @@ AMBAnchorNode # AMBNode_HdrSize ;dummy node - see note (1) below
[ ChocolateAMB
AMBFlags # 4 ;bits defined as below
AMBNContextSwitches # 4 ;monotonic count of total no. of task map-in's (eg. for performance tracing)
[ AMB_ChocTrace
AMBNmakeunsparse # 4 ;count of no. of calls to AMB_MakeUnsparse
AMBNmemmoveshrink # 4 ;count of no. of Service_MemoryMoved shrink fixups
AMBNmemmovegrow # 4 ;count of no. of Service_MemoryMoved grow fixups
AMBMappedInNpages # 4 ;no. of pages of MappedInNode really mapped in
[ AMB_LazyMapIn
AMBMappedInRegister # AMBMIRegWords*4 ;1 bit per page - see note (2) below
AMBmaxwork * :INDEX:@ ;size of main workspace (assumed to be multiple of 4 bytes)
......@@ -27,10 +27,11 @@
Push "R0,R3,R4,LR"
; Debug AMB,"allocate ",r0,r1
[ AMB_Debug
DebugReg r1, "allocate "
MOV R3,#AbsMaxAppSize
SUB R3,R3,#ApplicationStart
LDR R3,=AbsMaxAppSize-ApplicationStart
MOV R3,R3,LSR #Log2PageSize ;R3 = absolute max app pages
......@@ -49,8 +50,7 @@ allocate
;get memory for node - from system heap
MOV R3,#(AMBNode_pages - AMBNode_id) ;size excluding page list
ADD R3,R3,R1,LSL #2 ;plus one word per page
MOV R3,#AMBNode_HdrSize
BL AMB_BlockClaim
BVS alloc_done
......@@ -61,21 +61,41 @@ allocate
LDR R4,=AMBMagicNodeID
STR R4,[R2,#AMBNode_id] ;magic id
MOV R4,#0
STR R4,[R2,#AMBNode_Npages] ;number of pages = 0 (so far)
MOV R4,#ApplicationStart
STR R4,[R2,#AMBNode_startaddr]
STR R4,[R2,#AMBNode_DANode+DANode_PMPSize] ;number of pages = 0 (so far)
LDR R4,=ZeroPage+AppSpaceDANode
LDR R4,[R4,#DANode_Flags] ;Get the page flags from the DA.
LDR LR,=DynAreaFlags_AccessMask;Note that this is rather academic
AND R4,R4,LR ;because various bits of code ignore
STR R4,[R2,#AMBNode_PPL] ;or overwrite these flags!
LDR LR,=DynAreaFlags_AccessMask
ORR R4,R4,#DynAreaFlags_PMP
ORR R4,R4,#DynAreaFlags_NeedsSpecificPages
STR R4,[R2,#AMBNode_DANode+DANode_Flags]
;fill in other DANode bits
MOV R4,#0
STR R4,[R2,#AMBNode_DANode+DANode_Link]
STR R4,[R2,#AMBNode_DANode+DANode_Size]
STR R4,[R2,#AMBNode_DANode+DANode_SubLink]
STR R4,[R2,#AMBNode_DANode+DANode_SparseHWM]
STR R4,[R2,#AMBNode_DANode+DANode_SortLink]
STR R4,[R2,#AMBNode_DANode+DANode_PMP]
STR R4,[R2,#AMBNode_DANode+DANode_PMPMaxSize]
STR R2,[R2,#AMBNode_DANode+DANode_Workspace]
STR R4,[R2,#AMBNode_DANode+DANode_Handler]
STR R4,[R2,#AMBNode_DANode+DANode_Title]
LDR R4,=AbsMaxAppSize-ApplicationStart
STR R4,[R2,#AMBNode_DANode+DANode_MaxSize]
MOV R4,#ChangeDyn_AplSpace
STR R4,[R2,#AMBNode_DANode+DANode_Number]
MOV R4,#ApplicationStart
STR R4,[R2,#AMBNode_DANode+DANode_Base]
;do the actual MMU page allocation (grow from 0), for R1 pages, using node R2
BL growpages
BVS alloc_done
CMP R1,#0 ;EQ status if we were asked for 0 pages
LDR R1,[R2,#AMBNode_Npages] ;actual no. of pages we achieved
LDR R1,[R2,#AMBNode_DANode+DANode_PMPSize] ;actual no. of pages we achieved
BEQ alloc_ok ;if asked for 0, regard as ok
CMP R1,#0
......@@ -106,7 +126,10 @@ alloc_ok
; Debug AMB,"<alloc ",r1,r2
[ AMB_Debug
DebugReg r1,"<alloc "
DebugReg r2
Pull "R0,R3,R4,LR"
......@@ -118,6 +141,10 @@ alloc_zeropages
MOV R2,#0
B alloc_done
= "AMBControl DANode", 0
......@@ -27,7 +27,9 @@
Push "R0-R3,LR"
; Debug AMB,"deallocate ",r0,r2
[ AMB_Debug
DebugReg r2,"deallocate "
[ ValidateAMBHandles
;validate handle
......@@ -20,117 +20,87 @@
; entry:
; R1 = new number of pages for slot (more than current value)
; R2 -> AMB node (page table already allocated/grown to size)
; R2 -> AMB node
; exit: -
growpages ROUT
Push "R0-R7,LR"
Entry "R0-R7,R10-R11"
MOV R6,R1 ;save entry R1
LDR R5,[R2,#AMBNode_Npages]
LDR R5,[R2,#AMBNode_DANode+DANode_PMPSize]
Pull "R0-R7,PC",EQ ;done if no. of pages unchanged
MOV R0,R2 ;R0 -> AMB node
LDR R1,=ZeroPage+FreePoolDANode ;R1 := source for pages
LDR R2,=ZeroPage+AppSpaceDANode ;R2 := dest for pages
LDR R7,[R0,#AMBNode_Npages] ;R7 := current no. of pages
SUB R3,R6,R7 ;no. of pages required from FreePool
LDR R4,[R1,#DANode_PMPSize] ;no. of pages in FreePool
[ ShrinkableDAs
BLHI growp_TryToShrinkShrinkables
MOVHI R3,R4 ;R3 := no. of pages we will move
CMP R3,#0
BEQ %FT90 ;done if can't move any pages
ADD R4,R3,R7
STR R4,[R0,#AMBNode_Npages] ;new no. of pages
ADD R4,R0,#AMBNode_pages
ADD R4,R4,R7,LSL #2 ;R4 -> 1st page table entry for grow
LDR R5,[R1,#DANode_PMP]
LDR LR,[R1,#DANode_PMPSize]
ADD R5,R5,LR,LSL #2 ;current end of FreePool
;R3 = no. of pages, R4 -> buffer for page entries,
;R5 -> end of free pool PMP
; Reverse the order as we copy in order to match OS_ChangeDynamicArea
; (helps ensure pages are physically contiguous - to help with any
; potential DMA)
MOV R6,#-1
EXIT EQ ;done if no. of pages unchanged
[ AMB_Debug
DebugReg r1, "growpages to "
DebugReg r5, "from "
; Grow PMP to right size
ADD R10,R2,#AMBNode_DANode
Push "R1-R2,R10,R12"
LDR R1,[R2,#AMBNode_DANode+DANode_PMPMaxSize]
SUB R2,R6,R1
BL DynArea_PMP_Resize_WithNode
Pull "R1-R2,R10,R12"
; Check new size is correct
LDR R1,[R2,#AMBNode_DANode+DANode_PMPMaxSize]
[ AMB_Debug
DebugReg r1, "Resize result "
BNE %FT90 ;give up if PMP resize failed
; Now add pages to the PMP for the new region
Push "R5"
SUB SP,SP,#64*12 ;Temp page list
MOV R7,#-2 ;-2 = kernel picks physical page
MOV R3,#0
LDR LR,[R10,#DANode_Flags]
LDR LR,[R5,#-4]!
SUBS R2,R2,#1
STR LR,[R4],#4
STR R6,[R5]
STMIA R2!,{R5,R7,LR} ;Fill page list with increasing PMP page indices, to ensure no gaps in PMP if we hit an error
ADD R5,R5,#1
ADD R3,R3,#1
CMPNE R3,#64
SUB R4,R4,R3,LSL #2
LDR R2,=ZeroPage+AppSpaceDANode ;R2 := dest for pages
[ AMB_LazyMapIn
TST R5,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
MOVEQ R5,#-1 ;map the pages to Nowhere initially
MOVEQ R6,#AreaFlags_Duff
LDRNE R5,[R0,#AMBNode_startaddr]
ADDNE R5,R5,R7,LSL #Log2PageSize ;R5 := first new page new address
LDRNE R6,[R0,#AMBNode_PPL] ;R6 := dest PPL flags
LDR R5,[R0,#AMBNode_startaddr]
ADD R5,R5,R7,LSL #Log2PageSize ;R5 := first new page new address
LDR R6,[R0,#AMBNode_PPL] ;R6 := dest PPL flags
;entry: R3 = no. of pages, R4 -> list of page entries,
; R5 = start logical address, R6 = PPL
BL AMB_SetMemMapEntries ;remap
LDR R5,[R1,#DANode_PMPSize]
SUB R5,R5,R3
STR R5,[R1,#DANode_PMPSize] ;new FreePool size
LDR R5,[R2,#DANode_Size]
ADD R5,R5,R3,LSL #Log2PageSize
STR R5,[R2,#DANode_Size] ;new AppSpace size
LDR R6,=ZeroPage
STR R5,[R6,#MemLimit] ;update MemLimit
Push "R10,R12"
BL DynArea_PMP_PhysOp_WithNode
Pull "R10,R12"
CMP R3,#0
BNE %FT20 ; Stop if failed to allocate something
ADD SP,SP,#64*12
Pull "R5"
; Map in the new pages (if any)
Push "R1,R5"
LDR R5,[R10,#DANode_PMPSize]
MOV R7,#0
BLNE AMB_SetMemMapEntries_MapIn_Lazy
Pull "R1,R5"
; Update AplWorkSize, MemLimit
LDR R5,[R10,#DANode_PMPSize]
[ AMB_Debug
DebugReg r5, "PhysOp result "
MOV R2,#ApplicationStart
ADD R5,R2,R5,LSL #Log2PageSize
LDR R2,=ZeroPage
STR R5,[R2,#AplWorkSize]
STR R5,[R2,#MemLimit]
;;; STRVS R0,[SP]
Pull "R0-R7,PC"
[ ShrinkableDAs
; growp_TryToShrinkShrinkables - try to shrink shrinkable DAs, to grow free pool
; entry:
; R1 -> FreePool DANode
; R3 = no. of pages required in FreePool
; R4 = no. of pages in FreePool (must be less than R3)
; exit:
; R4 = new no. of pages in FreePool
; condition code GT is true if still less than required (ie. R3 > R4 on exit)
growp_TryToShrinkShrinkables ROUT
Entry "R1-R2,R11,R12"
MOV R11,R1
MOV R12,#0 ; dest node irrelevant
BL TryToShrinkShrinkables
] ;ShrinkableDAs
......@@ -14,8 +14,6 @@
; s.growshrink
; heap block can move when resized, so make sure pointers fixed-up
; change number of pages in slot (grow/shrink)
; entry:
......@@ -32,7 +30,10 @@ growshrink
Push "R0,R2,R4,R5,LR"
; Debug AMB,"growshrink ",r0,r1,r2
[ AMB_Debug
DebugReg r1, "growshrink "
DebugReg r2
MOV R5,#AbsMaxAppSize
SUB R5,R5,#ApplicationStart
......@@ -60,104 +61,49 @@ growshrink
BNE badsghandle
LDR R3,[R2,#AMBNode_Npages]
LDR R3,[R2,#AMBNode_DANode+DANode_PMPSize]
Pull "R0,R2,R4,R5,LR",EQ ; done if no change
MOV R5,R3 ; R5 := old no. pages
BLT gs_shrink
BL grwshr_node ; grow node itself first
BVS gs_done ; failed node grow is not error - means grow by 0
BL growpages ; grow the slot (MMU mapping)
Pull "R0,R2,R4,R5,LR",VS
B gs_done
BL shrinkpages ; shrink the slot (MMU mapping) first
BLVC grwshr_node ; shrink node itself
Pull "R0,R2,R4,R5,LR",VS
BEQ gs_done ; done if no change
SUB R1,R1,R3
ADD R2,R2,#AMBNode_DANode
[ {FALSE} ; Currently batcalls on PMPs will treat the PMP as if it were a regular DA (necessary for the PMP page claim implementation) - so just call our DA handler directly
MOV R0,#ChangeDyn_Batcall
MOV R1,R1,LSL #Log2PageSize
SWI XOS_ChangeDynamicArea ; Make batcall so we can specify our node
Push "R12"
MOV R0,#DAHandler_ResizePMP
ASSERT DANode_Handler = DANode_Workspace + 4
ADD R12,R2,#DANode_Workspace
LDMIA R12,{R12,PC}
Pull "R12"
[ AMB_Debug
LDR r0, [r0]
DebugReg r0, "growshrink CDA err "
; DebugReg r1, "growshrink CDA result "
LDR R1,[R2,#DANode_PMPSize]
CMP R1,#0 ; if shrunk to zero
LDR R2,[R2,#AMBNode_handle-AMBNode_DANode]
BNE gs_done
MOV R0,#1
SWI XOS_AMBControl ; then completely free the node
MOV R2,#0
STR R2,[SP,#4] ;poke freed handle to saved R2
MOV R3,R5 ;old no. of pages
CMP R2,#0 ;also clears V
LDRNE R1,[R2,#AMBNode_Npages]
CMP R2,#0 ;0 for freed node
STREQ R2,[SP,#4] ;poke freed handle to saved R2
[ AMB_Debug
DebugReg r1, "<growshrink "
DebugReg r2
DebugReg r3
Pull "R0,R2,R4,R5,LR"
;handle grow/shrink of node itself
; R1 = new no. of pages
; R2 -> node
; R5 = old no. of pages
; R2 -> node (may be moved)