; 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.growp


;grow slot by taking pages from FreePool; add them to AppSpace


; entry:
;     R1 =  new number of pages for slot (more than current value)
;     R2 -> AMB node (page table already allocated/grown to size)
;
; exit: -

growpages ROUT
        Push    "R0-R7,LR"

        MOV     R6,R1                      ;save entry R1
        LDR     R5,[R2,#AMBNode_Npages]
        CMP     R5,R6
        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_Size]
        MOV     R4,R4,LSR #Log2PageSize    ;no. of pages in FreePool
        CMP     R3,R4
  [ ShrinkableDAs
        BLGT    growp_TryToShrinkShrinkables
  ]
        MOVGT   R3,R4                      ;R3 := no. of pages we will move
        CMP     R3,#0
        BEQ     %FT02                      ;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_Base]
        LDR     LR,[R1,#DANode_Size]
        ADD     R5,R5,LR                   ;current end of FreePool
        SUB     R5,R5,R3,LSL #Log2PageSize ;R5 := first required page address

        ;entry: R3 = no. of pages, R4 -> buffer for page entries,
        ;       R5 := start logical address
        BL      AMB_FindMemMapEntries      ;find page nos.

  [ AMB_LazyMapIn
        LDR     R5,AMBFlags
        TST     R5,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
        ;
        MOVEQ   R5,#-1                     ;map the pages to Nowhere initially
        MOVEQ   R6,#AP_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_Size]
        SUB     R5,R5,R3,LSL #Log2PageSize
        STR     R5,[R1,#DANode_Size]       ;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

02
;;;        STRVS   R0,[SP]
        CLRV
        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
        Push    "R0-R2,R11,R12,LR"

        MOV     R11,R1                          ; -> FreePool DANode
        MOV     R1,R3,LSL #Log2PageSize         ;amount we need in FreePool
        MOV     R2,R4,LSL #Log2PageSize         ;amount we have in FreePool
        LDR     R10,=ZeroPage+DAList
        ASSERT  DANode_Link = 0                 ;because DAList has only link
10
        LDR     R10,[R10,#DANode_Link]          ;and load next
        CMP     R10,#1                          ;any more nodes?
        BCC     %FT99
        LDR     LR,[R10,#DANode_Flags]          ;check area is shrinkable
        TST     LR,#DynAreaFlags_Shrinkable
        BEQ     %BT10                           ;if not, try next area

        SUBS    R1,R1,R2                        ;amount we still need
        LDR     LR,[R10,#DANode_Size]           ;available size of this area
        CMP     LR,R1
        MOVCC   R1,LR                           ;min(amount we need, size of this area)
        RSB     R1,R1,#0                        ;make negative - it's a shrink
        LDR     R0,[R10,#DANode_Number]
        SWI     XOS_ChangeDynamicArea           ;should not be currently threaded during AMBControl
        MOV     R1,R3,LSL #Log2PageSize         ;original amount we need again
        LDR     R2,[R11,#DANode_Size]           ;get new size of FreePool
        CMP     R2,R1
        BCC     %BT10                           ;if still too small, loop
99
        MOV     R4,R2,LSR #Log2PageSize         ;no. of pages now in FreePool
        CMP     R3,R4
        Pull    "R0-R2,R11,R12,PC"

  ] ;ShrinkableDAs

    END