ChangeDyn 275 KB
Newer Older
Neil Turton's avatar
Neil Turton committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
        TTL   => ChangeDyn

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        ; OS_ChangeDynamicArea optimisations:

        GBLL  FastCDA_UpFront ; Do all cache/TLB maintenance upfront instead of on a per-page basis
FastCDA_UpFront SETL {TRUE}

        GBLL  FastCDA_FIQs ; Don't thrash ClaimFIQ/ReleaseFIQ in DoTheGrowPagesSpecified
FastCDA_FIQs SETL {TRUE}

        GBLL  FastCDA_Unnecessary ; Avoid unnecessary MMU_ChangingEntry calls in DoTheGrowPagesSpecified
FastCDA_Unnecessary SETL {TRUE}

        ; DoTheGrowPagesSpecified profiling code
        ; Written to use Cortex-A8 cycle count performance counter - will need modifying for other CPUs!

        GBLL  FastCDA_Prof
FastCDA_Prof SETL {FALSE}

      [ FastCDA_Prof
        ; Squeeze profiling workspace into "free space after envstring"
                                 ^ ExtendedROMFooter+4
        ! 0, "FastCDA_Prof workspace at ":CC::STR:@
FastCDA_Prof_DoTheGrowInit           # 4
FastCDA_Prof_MarkRequired            # 4
FastCDA_Prof_PagesUnsafe             # 4
FastCDA_Prof_DoublyCheckCacheability # 4
FastCDA_Prof_DoublyMovePages         # 4
FastCDA_Prof_FindSpare               # 4
FastCDA_Prof_ClaimFIQ                # 4
FastCDA_Prof_AccessPhysical          # 4
FastCDA_Prof_CopyPage                # 4
FastCDA_Prof_ReleasePhysical         # 4
FastCDA_Prof_MoveReplacement         # 4
FastCDA_Prof_MoveNeeded              # 4
FastCDA_Prof_ReleaseFIQ              # 4
FastCDA_Prof_PagesSafe               # 4
FastCDA_Prof_CallPreGrow             # 4
FastCDA_Prof_CallPostGrow            # 4
FastCDA_Prof_MMUChanging             # 4
FastCDA_Prof_MMUChangingUncached     # 4
FastCDA_Prof_ChangingEntry           # 4
        ASSERT @ <= &500
      ]

        MACRO
        FastCDA_ProfInit $temp
      [ FastCDA_Prof
        MVN     $temp,#0
        MCR     p15,0,$temp,c9,c12,2
        MOV     $temp,#1<<31
        MCR     p15,0,$temp,c9,c12,1
        MOV     $temp,#7
        MCR     p15,0,$temp,c9,c12,0
      ]
        MEND

        MACRO
        FastCDA_ProfStart $var,$temp,$temp2,$temp3,$cc
      [ FastCDA_Prof
        LDR$cc  $temp,=ZeroPage+FastCDA_Prof_$var
        LDR$cc  $temp2,[$temp]
        MRC$cc  p15,0,$temp3,c9,c13,0
        SUB$cc  $temp2,$temp2,$temp3
        STR$cc  $temp2,[$temp]
      ]
        MEND

        MACRO
        FastCDA_ProfEnd $var,$temp,$temp2,$temp3,$cc
      [ FastCDA_Prof
        MRC$cc  p15,0,$temp3,c9,c13,0
        LDR$cc  $temp,=ZeroPage+FastCDA_Prof_$var
        LDR$cc  $temp2,[$temp]
        ADD$cc  $temp2,$temp2,$temp3
        STR$cc  $temp2,[$temp]
      ]
        MEND

Neil Turton's avatar
Neil Turton committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
;******************************************************************************
; ChangeDynamic SWI
; In  : R0 =  0 => System Heap,
;             1 => RMA
;             2 => Screen
;             3 => Sprite area
;             4 => Font cache
;             5 => RAM disc
;             6 => Free pool
;       R1 = no of bytes to change by
;
; Out : V set if CAO in AplWork or couldn't move all the bytes requested.
;       R1 set to bytes moved.
;******************************************************************************

AP_AppSpace     *       0                                       ; user r/w, CB
AP_SysHeap      *       0                                       ; user r/w, CB
AP_RMA          *       0                                       ; user r/w, CB
AP_Screen       *       0 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped :OR: DynAreaFlags_NeedsSpecificPages
AP_Sprites      *       0                                       ; user r/w, CB
AP_FontArea     *       2                                       ; user none, CB
115 116
AP_RAMDisc      *       2 :OR: DynAreaFlags_NotCacheable        ; user none, ~CB (poor performance for current StrongARMs)
AP_RAMDisc_SA   *       2                                       ; user none,
Neil Turton's avatar
Neil Turton committed
117
AP_Duff         *       2 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable ; user none, ~C~B
118
AP_FreePool     *       2 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable :OR: DynAreaFlags_PMP
Neil Turton's avatar
Neil Turton committed
119
AP_CursorChunk  *       1 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable :OR: PageFlags_Unavailable
120

Neil Turton's avatar
Neil Turton committed
121 122 123 124
AP_L2PT         *       2 :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable ; user none, ~C~B
AP_L1PT         *       AP_L2PT :OR: PageFlags_Unavailable
AP_UndStackSoftCam *    PageFlags_Unavailable

125 126 127
  [ DA_Batman
ChangeDyn_Batcall    * -3               ; special DA number to select Batman usage of OS_ChangeDynamicArea
  ]
Neil Turton's avatar
Neil Turton committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
ChangeDyn_FreeAndApl * -2               ; special reason code for when we're sucking out of free pool and apl space
ChangeDyn_AplSpace   * -1
ChangeDyn_SysHeap    * 0
ChangeDyn_RMA        * 1
ChangeDyn_Screen     * 2
ChangeDyn_SpriteArea * 3
ChangeDyn_FontArea   * 4
ChangeDyn_RamFS      * 5
ChangeDyn_FreePool   * 6
ChangeDyn_MaxArea    * 6

; Area handler reason codes

DAHandler_PreGrow       *       0
DAHandler_PostGrow      *       1
DAHandler_PreShrink     *       2
DAHandler_PostShrink    *       3
145 146
 [ ShrinkableDAs
DAHandler_TestShrink    *       4       ; new reason added to find amount area could shrink by
Neil Turton's avatar
Neil Turton committed
147
 ]
148 149
DAHandler_Abort         *       5       ; ROL abortable DAs
DAHandler_ResizePMP     *       6       ; Called on OS_ChangeDynamicArea
Neil Turton's avatar
Neil Turton committed
150 151 152

; Number of entries in page block on stack

153
NumPageBlockEntries *   63
Neil Turton's avatar
Neil Turton committed
154 155 156
PageBlockSize   *       NumPageBlockEntries * 12
PageBlockChunk  *       NumPageBlockEntries * 4096

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
;
; mjs - performance enhancements (from Ursula, merged into HALised kernel June 2001)
; Workspace for acceleration of operations on a DA, by reducing need to traverse DA list.
;
; - accelerates allocating non-quick DA numbers to O(n) instead of laughable O(n*n), where n is no. of DAs
; - accelerates enumeration to O(n) instead of laughable O(n*n)
; - allocation of a quick handle (DA number) is O(1)
; - access of a DA node from a quick handle is O(1)
; - access of a DA node from a non-quick handle is O(1), if it repeats the most recent non-quick handle access (else O(n))
;
; - creation of a DA still has some O(n) work (requires search for address space), but is now rather quicker
; - removal of a DA is still O(n) (requires traversal of list in order to get previous node)
; - other uses of a DA with a quick handle (eg. get info, change size) avoid any O(n) work
;
; - all system handles will be quick.
; - non-system handles will be quick, except for very large numbers of DAs, or silly modules like the Wimp who insist on
;   their own silly DA number (the latter can still benefit from LastTreacleHandle - see below)
;
; Limitations:
; - does not allow anyone to choose their own DA number that clashes with the quick handle set - should not
;   be a problem since choosing own number reserved for Acorn use
; - does not allow anyone to renumber a DA with a quick handle - again, reserved for system use
; - DA names will be truncated to a maximum of 31 characters (or as defined below)
;
                                  GBLL DynArea_QuickHandles
DynArea_QuickHandles              SETL {TRUE}
;
      ;various bad things happen if DynArea_QuickHandles is FALSE (eg. some new API disappears)
      ;should remove FALSE build option to simplify source code next time kernel is updated (kept for reference/testing now)
      ASSERT DynArea_QuickHandles

                                  GBLL DynArea_NullNamePtrMeansHexString
DynArea_NullNamePtrMeansHexString SETL {TRUE} :LAND: DynArea_QuickHandles
;
  [ DynArea_QuickHandles
DynArea_MaxNameLength     * 31                      ;maximum length of DA name, excluding terminator (multiple of 4, -1)
DynArea_NumQHandles       * 256                     ;maximum no. of non-system quick handles available simultaneously
194 195 196
DynArea_AddrLookupBits    * 8                       ;LUT covers entire 4G logical space, so 4G>>8 = 16M granularity
DynArea_AddrLookupSize    * 1<<(32-DynArea_AddrLookupBits) ; Address space covered by each entry
DynArea_AddrLookupMask    * &FFFFFFFF-(DynArea_AddrLookupSize-1)
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
;
                          ^  0,R11
DynArea_TreacleGuess      # 4                       ;guess for next non-quick handle to allocate, if needed, is TreacleGuess+1
DynArea_CreatingHandle    # 4                       ;handle proposed but not yet committed, during DynArea_Create, or -1 if none
DynArea_CreatingPtr       # 4                       ;ptr to proposed DANode during DynArea_Create (invalid if CreatingHandle = -1)
DynArea_LastTreacleHandle # 4                       ;last non-quick handle accessed by a client (usually the Wimp), or -1 if none
DynArea_LastTreaclePtr    # 4                       ;ptr to DANode for last non-quick handle accessed (invalid if LastTreacleHandle = -1)
DynArea_LastEnumHandle    # 4                       ;last handle enumerated, or -1 if none
DynArea_LastEnumPtr       # 4                       ;ptr to DANode for last handle enumerated (invalid if LastEnumHandle = -1)
DynArea_ShrinkableSubList # 4                       ;sub list of dynamic areas that are Shrinkable (0 if none)
DynArea_OD6Signature      # 4                       ;signature of changes to non-system DAs since last call to OS_DynamicArea 6
                                                    ;bit  0 = 1 if any DAs have been created
                                                    ;bit  1 = 1 if any DAs have been removed
                                                    ;bit  2 = 1 if any DAs have been resized (excluding grow or shrink at creation or removal)
                                                    ;bit  3 = 1 if any DAs have been renumbered
                                                    ;bits 4-30   reserved (0)
                                                    ;bit 31 = 1 if next resize is not to update signature (used during create, remove)
DynArea_OD6PrevSignature  # 4                       ;previous signature, used to distinguish single from multiple changes
DynArea_OD6Handle         # 4                       ;handle of last DA that affected signature
DynArea_OD8Clamp1         # 4                       ;clamp value on area max size for OS_DynamicArea 0 with R5 = -1
                                                    ;(default -1, set by R1 of OS_DynamicArea 8)
DynArea_OD8Clamp2         # 4                       ;clamp value on area max size for OS_DynamicArea 0 with R5 > 0 (not Sparse)
                                                    ;(default -1, set by R2 of OS_DynamicArea 8)
DynArea_OD8Clamp3         # 4                       ;clamp value on area max size for OS_DynamicArea 0 for a Sparse area
                                                    ;(default 4G-4k, set by R3 of OS_DynamicArea 8)
DynArea_SortedList        # 4                       ;alphabetically sorted list of non-system areas, or 0 if none
DynArea_SysQHandleArray   # 4*(ChangeDyn_MaxArea+1) ;for system areas 0..MaxArea, word = ptr to DANode, or 0 if not created yet
DynArea_FreeQHandles      # 4                       ;index of first free quick handle, starting at 1 (or 0 for none)
DynArea_QHandleArray      # 4*DynArea_NumQHandles   ;1 word per quick handle
                                                    ; - if free, word = index of next free quick handle (or 0 if none)
                                                    ; - if used, word = ptr to DANode (must be > DynArea_NumQHandles)
228
DynArea_AddrLookup        # 4<<DynArea_AddrLookupBits ; Lookup table for fast logaddr -> dynarea lookup
229 230 231 232 233 234 235 236
;
DynArea_ws_size           *  :INDEX:@               ;must be multiple of 4
;
            ASSERT DynArea_QHandleArray = DynArea_FreeQHandles +4
  ]
;


Kevin Bracey's avatar
Kevin Bracey committed
237
;        InsertDebugRoutines
Neil Turton's avatar
Neil Turton committed
238 239 240 241

; Exit from ChangeDynamicArea with error Not all moved

failure_IRQgoingClearSemaphore
Jeffrey Lee's avatar
Jeffrey Lee committed
242 243
        LDR     r0, =ZeroPage
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
244
        STR     r0, [r0, #CDASemaphore]
Jeffrey Lee's avatar
Jeffrey Lee committed
245 246 247 248
      |
        MOV     r10, #0
        STR     r10, [r0, #CDASemaphore]
      ]
Neil Turton's avatar
Neil Turton committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
failure_IRQgoing
        ADR     r0, ErrorBlock_ChDynamNotAllMoved
ChangeDynamic_Error
        MOV     r10, #0
        STR     r0, [stack]
        LDR     lr, [stack, #4*10]
        ORR     lr, lr, #V_bit
        STR     lr, [stack, #4*10]
CDS_PostServiceWithRestore
      [ International
        LDR     r0, [stack]
        BL      TranslateError
        STR     r0, [stack]
      ]

; and drop thru to ...

CDS_PostService
        MOV     r1, #Service_MemoryMoved
        MOV     r0, r10                 ; amount moved
        MOVS    r2, r11                 ; which way was transfer?
        BMI     %FT47                   ; [definitely a grow]
        CMP     r11, #ChangeDyn_FreePool
        BNE     %FT48                   ; [definitely a shrink]
        CMP     r12, #ChangeDyn_AplSpace
        BEQ     %FT48                   ; [a shrink]
47
        RSB     r0, r0, #0             ; APLwork or free was source
        MOV     r2, r12                ; r2 = area indicator
48
        BL      Issue_Service

        MOV     r1, r10                ; amount moved

        Pull    "r0, r2-r9, r10, lr"
        ExitSWIHandler

        MakeErrorBlock ChDynamNotAllMoved

288

Neil Turton's avatar
Neil Turton committed
289 290
; in:   r0 = logical address where page is now

291
GetPageFlagsForR0IntoR6 Entry "R0-R2, R4-R5, R7"
Neil Turton's avatar
Neil Turton committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
;
; code from MoveCAMatR0toR3
;
        LDR     r5, =L2PT
        ADD     r4, r5, r0, LSR #10             ; r4 -> L2PT for log addr r0
        MOV     r2, r4, LSR #12
        LDR     r2, [r5, r2, LSL #2]            ; r2 = L2PT entry for r4
        TST     r2, #3                          ; if no page there
        BEQ     %FT90                           ; then cam corrupt

        LDR     r4, [r4]                        ; r4 = L2PT entry for r0
        TST     r4, #3                          ; check entry is valid too
        BEQ     %FT91
        MOV     r4, r4, LSR #12                 ; r4 = phys addr >> 12

Jeffrey Lee's avatar
Jeffrey Lee committed
307
        LDR     r2, =ZeroPage
Neil Turton's avatar
Neil Turton committed
308
        LDR     r6, [r2, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
309 310 311 312
        ADD     r5, r2, #PhysRamTable
      [ ZeroPage <> 0
        MOV     r2, #0
      ]
Neil Turton's avatar
Neil Turton committed
313 314 315 316 317 318 319 320 321 322 323 324 325
10
        CMP     r2, r6                          ; if page we've got to is > max
        BHI     %FT92                           ; then corrupt
        LDMIA   r5!, {r7, lr}                   ; get phys.addr, size
        SUB     r7, r4, r7, LSR #12             ; number of pages into this bank
        CMP     r7, lr, LSR #12                 ; if too many
        ADDCS   r2, r2, lr, LSR #12             ; then advance physical page no.
        BCS     %BT10                           ; and loop

        ADD     r2, r2, r7                      ; add on number of pages within bank
;
; code from BangCamUpdate
;
Jeffrey Lee's avatar
Jeffrey Lee committed
326
        LDR     r1, =ZeroPage
Neil Turton's avatar
Neil Turton committed
327
        LDR     r1, [r1, #CamEntriesPointer]
328 329 330
        ADD     r1, r1, r2, LSL #CAM_EntrySizeLog2 ; point at cam entry (logaddr, PPL)
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
Neil Turton's avatar
Neil Turton committed
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
        LDMIA   r1, {r0, r6}                    ; r0 = current logaddress, r6 = current PPL
        EXIT

90
        ADR     lr, NoL2ForPageBeingRemovedError ; NB don't corrupt r0 yet - we need that in block as evidence
95
        STR     lr, [sp]                        ; update returned r0
        BL      StoreDebugRegs
        PullEnv                                 ; seriously broken memory
        SETV
        MOV     pc, lr

91
        ADR     lr, PageBeingRemovedNotPresentError
        B       %BT95

92
        ADR     lr, PhysicalAddressNotFoundError
        B       %BT95


; MoveCAMatR0toR3
; in:   r0 = old logaddr
;       r3 = new logaddr
355
;       r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both)
Neil Turton's avatar
Neil Turton committed
356 357 358 359 360 361
;       r11 = page protection level
;
; out:  r2 = physical page number of page moved, unless there was a serious error
;       r0,r1,r3,r6-r12 preserved
;       r4,r5 corrupted

362
MoveCAMatR0toR3 Entry "r0,r1,r6,r7"
Neil Turton's avatar
Neil Turton committed
363 364 365 366 367 368 369 370 371 372 373 374
        LDR     r5, =L2PT
        ADD     r4, r5, r0, LSR #10             ; r4 -> L2PT for log addr r0
        MOV     r2, r4, LSR #12
        LDR     r2, [r5, r2, LSL #2]            ; r2 = L2PT entry for r4
        TST     r2, #3                          ; if no page there
        BEQ     %FT90                           ; then cam corrupt

        LDR     r4, [r4]                        ; r4 = L2PT entry for r0
        TST     r4, #3                          ; check entry is valid too
        BEQ     %FT91
        MOV     r4, r4, LSR #12                 ; r4 = phys addr >> 12

Jeffrey Lee's avatar
Jeffrey Lee committed
375
        LDR     r2, =ZeroPage
Neil Turton's avatar
Neil Turton committed
376
        LDR     r6, [r2, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
377 378 379 380
        ADD     r5, r2, #PhysRamTable
      [ ZeroPage <> 0
        MOV     r2, #0
      ]
Neil Turton's avatar
Neil Turton committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
10
        CMP     r2, r6                          ; if page we've got to is > max
        BHI     %FT92                           ; then corrupt
        LDMIA   r5!, {r7, lr}                   ; get phys.addr, size
        SUB     r7, r4, r7, LSR #12             ; number of pages into this bank
        CMP     r7, lr, LSR #12                 ; if too many
        ADDCS   r2, r2, lr, LSR #12             ; then advance physical page no.
        BCS     %BT10                           ; and loop

        ADD     r2, r2, r7                      ; add on number of pages within bank
        BL      BangCamUpdate
        CLRV
        EXIT

90
        ADR     lr, NoL2ForPageBeingRemovedError ; NB don't corrupt r0 yet - we need that in block as evidence
95
        STR     lr, [sp]                        ; update returned r0
        BL      StoreDebugRegs
        PullEnv                                 ; seriously broken memory
        SETV
        MOV     pc, lr

91
        ADR     lr, PageBeingRemovedNotPresentError
        B       %BT95

92
        ADR     lr, PhysicalAddressNotFoundError
        B       %BT95

Jeffrey Lee's avatar
Jeffrey Lee committed
412
StoreDebugRegs ; Note: Corrupts R0,R1
Neil Turton's avatar
Neil Turton committed
413
        Push    "lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
414 415 416 417 418
        LDR     lr, =ZeroPage+CamMapCorruptDebugBlock
        STMIA   lr, {r0-r12}
        STR     sp, [lr, #13*4]!
        LDMIA   sp, {r0,r1}                     ; reload stacked LR & return R0 (error pointer)
        STMIB   lr, {r0,r1}                     ; LR -> LR, error -> PC
Neil Turton's avatar
Neil Turton committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        Pull    "pc"

NoL2ForPageBeingRemovedError
        &       0
        =       "Memory Corrupt: No L2PT for page being removed", 0
        ALIGN

PageBeingRemovedNotPresentError
        &       0
        =       "Memory Corrupt: Page being removed was not present", 0
        ALIGN

PhysicalAddressNotFoundError
        &       0
        =       "Memory Corrupt: Physical address not found", 0
        ALIGN

CamMapBroke
        &       0
        =       "!!!! CAM Map Corrupt !!!!", 0
        ALIGN
440 441 442 443 444
; Call_CAM_Mapping
; in:   r2 = physical page number
;       r3 = logical address (2nd copy of doubly mapped area)
;       r9 = offset from 1st to 2nd copy of doubly mapped area (either source or dest, but not both)
;       r11 = PPL + CB bits
Neil Turton's avatar
Neil Turton committed
445 446 447 448 449
Call_CAM_Mapping
        Push    "r0, r1, r4, r6, lr"
        BL      BangCamUpdate
        Pull    "r0, r1, r4, r6, pc"

450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
  [ FastCDA_UpFront
; CheckCacheabilityR0ByMinusR2
; in:   r0 = end of area
;       r2 = size of area (must be nonzero)
; out:  r6 has DynAreaFlags_NotCacheable set if entire region noncacheable
;              Flag clear if at least one page is cacheable
;       r0 points to start of area
;
;       4K page size assumed!
CheckCacheabilityR0ByMinusR2 ROUT
        Entry   "r2"
10
        SUB     r0, r0, #4096
        BL      GetPageFlagsForR0IntoR6
        SUBS    r2, r2, #4096
        TSTNE   r6, #DynAreaFlags_NotCacheable
        BNE     %BT10
        SUB     r0, r0, r2
        EXIT
  ]
Neil Turton's avatar
Neil Turton committed
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r0 bits 0..6 = area number
;       r0 bit 7 set => return max area size in r2 (implemented 13 Jun 1990)
;                       this will return an error if not implemented
; Out   r0 = address of area
;       r1 = current size of area
;       r2 = max size of area if r0 bit 7 set on entry (preserved otherwise)

; TMD 19-May-93: When this is updated to new CDA list, change meaning as follows:

; r0 in range 0..&7F    return address, size of area r0
;             &80..&FF  return address, size, maxsize of area (r0-&80)
;             &100..    return address, size, maxsize of area r0

; TMD 20-Aug-93: New bit added - if r0 = -1 on entry, then returns info on application space
; r0 = base address (&8000)
; r1 = current size (for current task)
; r2 = maximum size (eg 16M-&8000)

ReadDynamicArea ROUT

readdyn_returnR2bit     *       &80
        ASSERT  ChangeDyn_MaxArea < readdyn_returnR2bit

495
        CMP     r0, #ChangeDyn_AplSpace         ; if finding out about app space
Jeffrey Lee's avatar
Jeffrey Lee committed
496
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
497
        LDREQ   r1, [r0, #AplWorkSize+1]        ; then r1 = current size
Jeffrey Lee's avatar
Jeffrey Lee committed
498 499 500 501
      |
        LDREQ   r1, =ZeroPage
        LDREQ   r1, [r1, #AplWorkSize]
      ]
502 503 504
; [ HAL32
;        LDREQ   r2, [r0, #RAMLIMIT+1]
; |
Neil Turton's avatar
Neil Turton committed
505
        LDREQ   r2, =AplWorkMaxSize             ; and r2 = max size
506
; ]
Neil Turton's avatar
Neil Turton committed
507 508 509 510 511 512 513 514 515 516 517
        MOVEQ   r0, #&8000                      ; r0 = base address
        SUBEQ   r1, r1, r0                      ; adjust size and maxsize
        SUBEQ   r2, r2, r0                      ; to remove bottom 32K
        ExitSWIHandler EQ

; first check if it's one of the new ones

        Push    "r1,lr"
        CMP     r0, #&100                       ; if area >= &100
        MOVCS   r1, r0                          ; then just use area
        BICCC   r1, r0, #readdyn_returnR2bit    ; else knock off bit 7
518 519 520
  [ DynArea_QuickHandles
        BL      QCheckAreaNumber                ; out: r10 -> node
  |
Neil Turton's avatar
Neil Turton committed
521
        BL      CheckAreaNumber                 ; out: r10 -> node
522
  ]
Neil Turton's avatar
Neil Turton committed
523 524 525
        Pull    "r1,lr"
        BCC     %FT05                           ; [not a new one, so use old code]

526 527 528
        LDR     r11, [r10, #DANode_Flags]
        TST     r11, #DynAreaFlags_PMP
        BNE     %FT01
Neil Turton's avatar
Neil Turton committed
529 530 531 532 533 534
        CMP     r0, #&80                        ; CS => load maxsize into R2
                                                ; (do this either if bit 7 set, or area >=&100)
        LDRCS   r2, [r10, #DANode_MaxSize]
        LDR     r1, [r10, #DANode_Size]         ; r1 = current size
        LDR     r0, [r10, #DANode_Base]         ; r0 -> base
        TST     r11, #DynAreaFlags_DoublyMapped
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
        SUBNE   r0, r0, r1                      ; if doubly mapped then return start of 1st copy for compatibility
        ExitSWIHandler
01
        ; Convert physical parameters into byte counts
        CMP     r0, #&80
        BCC     %FT02
        LDR     r2, [r10, #DANode_PMPMaxSize]
        CMP     r2, #DynArea_PMP_BigPageCount
        MOVLO   r2, r2, LSL #12
        LDRHS   r2, =DynArea_PMP_BigByteCount
02
        LDR     r1, [r10, #DANode_PMPSize]
        CMP     r1, #DynArea_PMP_BigPageCount
        MOVLO   r1, r1, LSL #12
        LDRHS   r1, =DynArea_PMP_BigByteCount
        LDR     r0, [r10, #DANode_Base]
Neil Turton's avatar
Neil Turton committed
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
        ExitSWIHandler
05
        ADRL    r0, ErrorBlock_BadDynamicArea
      [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
      ]
        B       SLVK_SetV

        MakeErrorBlock  BadDynamicArea

; *************************************************************************
; User access to CAM mapping
; ReadMemMapInfo:
; returns R0 = pagsize
;         R1 = number of pages in use  (= R2 returned from SetEnv/Pagesize)
; *************************************************************************

ReadMemMapInfo_Code
Jeffrey Lee's avatar
Jeffrey Lee committed
571
      LDR      R10, =ZeroPage
Neil Turton's avatar
Neil Turton committed
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
      LDR      R0, [R10, #Page_Size]
      LDR      R1, [R10, #RAMLIMIT]    ; = total memory size
      ADRL     R11, PageShifts-1
      LDRB     R11, [R11, R0, LSR #12]
      MOV      R1, R1, LSR R11
      ExitSWIHandler

; ************************************************************************
; SWI ReadMemMapEntries: R0 pointer to list.
;  Entries are three words long, the first of which is the CAM page number.
;  List terminated by -1.
; Returns pagenumber (unaltered)/address/PPL triads as below
; ************************************************************************

ReadMemMapEntries_Code  ROUT
        Push    "r0,r14"
Jeffrey Lee's avatar
Jeffrey Lee committed
588
        LDR     r14, =ZeroPage
Neil Turton's avatar
Neil Turton committed
589 590 591
        LDR     r10, [r14, #CamEntriesPointer]
        LDR     r14, [r14, #MaxCamEntry]
01
592
        LDR     r12, [r0], #4                   ; page number
Neil Turton's avatar
Neil Turton committed
593 594 595
        CMP     r12, r14
        Pull    "r0,r14", HI
        ExitSWIHandler HI
596 597 598 599 600 601 602 603 604

   [ ChocolateAMB
        ;may need AMB to make mapping honest (as if not lazy), if page is in currently mapped app
        Push    "r0, lr"
        MOV     r0, r12                         ; page number to make honest
        BL      AMB_MakeHonestPN
        Pull    "r0, lr"
   ]

605 606 607
        ADD     r11, r10, r12, LSL #CAM_EntrySizeLog2
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
Neil Turton's avatar
Neil Turton committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
        LDMIA   r11, {r11, r12}
        STMIA   r0!, {r11, r12}
        B       %BT01

; ************************************************************************
; SWI FindMemMapEntries:
; In:  R0 -> table of 12-byte page entries
;       +0      4       probable page number (0..npages-1) (use 0 if no idea)
;       +4      4       logical address to match with
;       +8      4       undefined
;       terminated by a single word containing -1
;
; Out: table of 12-byte entries updated:
;       +0      4       actual page number (-1 => not found)
;       +4      4       address (preserved)
;       +8      4       page protection level (3 if not found)
;       terminator preserved
;
; ************************************************************************

FindMemMapEntries_Code  ROUT

; Code for expanded CAM map version

        Push    "r0, r9, r14"
Jeffrey Lee's avatar
Jeffrey Lee committed
633
        LDR     r14, =ZeroPage
Neil Turton's avatar
Neil Turton committed
634 635
        LDR     r9, [r14, #MaxCamEntry]
        LDR     r14, [r14, #CamEntriesPointer]  ; r14 -> start of cam map
636
        ADD     r9, r14, r9, LSL #CAM_EntrySizeLog2 ; r9 -> first word of last entry in cam map
Neil Turton's avatar
Neil Turton committed
637 638 639 640 641 642 643
10
        LDR     r10, [r0, #0]                   ; r10 = guess page number (or -1)
        CMP     r10, #-1                        ; if -1 then end of list
        Pull    "r0, r9, r14", EQ               ; so restore registers
        ExitSWIHandler EQ                       ; and exit

        LDR     r11, [r0, #4]                   ; r11 = logical address
644 645 646 647 648 649 650 651 652

   [ ChocolateAMB
        ;may need AMB to make mapping honest (as if not lazy), if page is in currently mapped app
        Push    "r0, lr"
        MOV     r0, r11                         ; logical address to make honest
        BL      AMB_MakeHonestLA                ; note, quickly dismisses non app space addresses
        Pull    "r0, lr"
   ]

653
        ADD     r10, r14, r10, LSL #CAM_EntrySizeLog2 ; form address with 'guess' page
Neil Turton's avatar
Neil Turton committed
654 655 656
        CMP     r10, r9                         ; if off end of CAM
        BHI     %FT20                           ; then don't try to use the guess

657
        LDR     r12, [r10, #CAM_LogAddr]        ; load address from guessed page
Neil Turton's avatar
Neil Turton committed
658 659 660 661 662 663 664 665 666 667 668 669 670
        TEQ     r11, r12                        ; compare address
        BEQ     %FT60                           ; if equal, then guessed page was OK
20

; for now, cheat by looking in L2PT, to see if we can speed things up

        Push    "r5-r8"                         ; need some registers here!
        LDR     r10, =L2PT
        MOV     r8, r11, LSR #12                ; r8 = logical page number
        ADD     r8, r10, r8, LSL #2             ; r8 -> L2PT entry for log.addr
        MOV     r5, r8, LSR #12                 ; r5 = page offset to L2PT entry for log.addr
        LDR     r5, [r10, r5, LSL #2]           ; r5 = L2PT entry for L2PT entry for log.addr
        TST     r5, #3                          ; if page not there
671
        SUBEQ   r10, r9, #CAM_EntrySizeLog2     ; then invalid page so go from last one
Neil Turton's avatar
Neil Turton committed
672 673 674 675
        BEQ     %FT45
        LDR     r8, [r8]                        ; r8 = L2PT entry for log.addr
        MOV     r8, r8, LSR #12                 ; r8 = physaddr / 4K

Jeffrey Lee's avatar
Jeffrey Lee committed
676
        LDR     r5, =ZeroPage+PhysRamTable
677
        SUB     r10, r14, #CAM_EntrySize
Neil Turton's avatar
Neil Turton committed
678 679 680 681 682 683
30
        CMP     r10, r9                         ; have we run out of RAM banks?
        BCS     %FT40                           ; then fail
        LDMIA   r5!, {r6,r7}                    ; load next address, size
        SUB     r6, r8, r6, LSR #12             ; number of pages into this bank
        CMP     r6, r7, LSR #12                 ; if more than there are
684
        ASSERT  CAM_EntrySizeLog2 <= 16
685
        BICCS   r7, r7, #&F00
686
        ADDCS   r10, r10, r7, LSR #12-CAM_EntrySizeLog2 ; then advance CAM entry position
Neil Turton's avatar
Neil Turton committed
687 688
        BCS     %BT30                           ; and loop to next bank

689
        ADD     r10, r10, r6, LSL #CAM_EntrySizeLog2 ; advance by 2 words for each page in this bank
Neil Turton's avatar
Neil Turton committed
690
40
691
        SUBCS   r10, r9, #CAM_EntrySize         ; search from last one, to fail quickly (if CS)
Neil Turton's avatar
Neil Turton committed
692 693 694 695
45
        Pull    "r5-r8"
50
        CMP     r10, r9                         ; if not just done last one,
696 697
        ASSERT  CAM_LogAddr=0
        LDRNE   r12, [r10, #CAM_EntrySize]!     ; then get logical address
Neil Turton's avatar
Neil Turton committed
698 699 700 701 702 703 704 705
        TEQNE   r11, r12                        ; compare address
        BNE     %BT50                           ; loop if not same and not at end

; either found page or run out of pages

        TEQ     r11, r12                        ; see if last one matched
                                                ; (we always load at least one!)
60
706
        LDREQ   r12, [r10, #CAM_PageFlags]      ; if match, then r12 = PPL
Neil Turton's avatar
Neil Turton committed
707
        SUBEQ   r10, r10, r14                   ; and page number=(r10-r14)>>3
708
        MOVEQ   r10, r10, LSR #CAM_EntrySizeLog2
Neil Turton's avatar
Neil Turton committed
709 710 711 712 713 714 715 716 717 718

        MOVNE   r10, #-1                        ; else unknown page number indicator
        MOVNE   r12, #3                         ; and PPL=3 (no user access)

        STMIA   r0!, {r10-r12}                  ; store all 3 words
        B       %BT10                           ; and go back for another one

;**************************************************************************
; SWI SetMemMapEntries: R0 pointer to list of CAM page/address/PPL triads,
;  terminated by -1.
719
; address of -1 means "put the page out of the way"
Neil Turton's avatar
Neil Turton committed
720 721
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

722 723 724 725 726
; note, if ChocolateAMB, no MakeHonest consideration here, this SWI just
; changes the mapping of pages regardless of their current mapping, and
; assumes the caller knows what he is doing (ho ho)
;

Neil Turton's avatar
Neil Turton committed
727 728 729 730
SetMemMapEntries_Code  ROUT
        Push    "r0-r6, r9, lr"
        MOV     r12, r0

731
; BangCamUpdate takes entry no in r2, logaddr to set to in r3, r11 = PPL
Neil Turton's avatar
Neil Turton committed
732 733
; corrupts r0,r1,r4,r6

Jeffrey Lee's avatar
Jeffrey Lee committed
734
        LDR     r9, =ZeroPage
Neil Turton's avatar
Neil Turton committed
735
        LDR     r5, [r9, #MaxCamEntry]
736 737
        LDR     r9, [r9, #CamEntriesPointer]
        ADD     r9, r9, #CAM_PageFlags
Neil Turton's avatar
Neil Turton committed
738 739 740 741 742
01
        LDR     r2, [r12], #4
        CMP     r2, r5
        BHI     %FT02                   ; finished
        LDMIA   r12!, {r3, r11}
Kevin Bracey's avatar
Kevin Bracey committed
743
 [ {FALSE}
Neil Turton's avatar
Neil Turton committed
744
        AND     r11, r11, #3
Kevin Bracey's avatar
Kevin Bracey committed
745
 ]
Neil Turton's avatar
Neil Turton committed
746 747 748
        CMP     r3, #-1
        LDRHS   r3, =DuffEntry
        MOVHS   r11, #AP_Duff
749 750 751 752 753 754
        ; Ensure PMP membership flag is retained - just in case caller doesn't
        ; know what he's doing
        LDR     r0, [r9, r2, LSL #CAM_EntrySizeLog2]
        AND     r0, r0, #DynAreaFlags_PMP
        BIC     r11, r11, #DynAreaFlags_PMP
        ORR     r11, r11, r0
Neil Turton's avatar
Neil Turton committed
755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
        BL      BangCamUpdate
        B       %BT01
02
        Pull    "r0-r6, r9, lr"
        ExitSWIHandler

        LTORG



;**************************************************************************
;
;       DynamicAreaSWI - Code to handle SWI OS_DynamicArea
;
; in:   r0 = reason code
;       Other registers depend on reason code
;
; out:  Depends on reason code
;

775 776 777 778 779 780

DAReason_Create          *  0
DAReason_Remove          *  1
DAReason_GetInfo         *  2
DAReason_Enumerate       *  3
DAReason_Renumber        *  4
781
 [ ShrinkableDAs
782
DAReason_ReturnFree      *  5   ;if ShrinkableDAs, else reason code invalid
Neil Turton's avatar
Neil Turton committed
783
 ]
784 785 786 787
 [ DynArea_QuickHandles
DAReason_GetChangeInfo   *  6   ;if DynArea_Quickhandles, else reason code invalid
DAReason_EnumerateInfo   *  7   ;if DynArea_Quickhandles, else reason code invalid
DAReason_SetClamps       *  8   ;if DynArea_Quickhandles, else reason code invalid
Neil Turton's avatar
Neil Turton committed
788
 ]
789 790 791 792
 [ DA_Batman
DAReason_SparseClaim     *  9   ;if DA_Batman, else reason code invalid
DAReason_SparseRelease   * 10   ;if DA_Batman, else reason code invalid
 ]
793
DAReason_LocateAddress   * 20
794 795 796 797 798 799
DAReason_PMP_PhysOp      * 21
DAReason_PMP_LogOp       * 22
DAReason_PMP_Resize      * 23
DAReason_PMP_GetInfo     * 24
DAReason_PMP_GetPages    * 25
DAReason_Limit           * 26   ;end of defined DA reasons
Neil Turton's avatar
Neil Turton committed
800 801


802 803
DynArea_NewAreas *      &100            ; Allocated area numbers start here
DynArea_NewAreasBase *  &04000000       ; Allocated area addresses start here
804 805
DynArea_PMP_BigPageCount * 1:SHL:(31-12) ; If PMP has >= this many pages...
DynArea_PMP_BigByteCount * &7FFFF000     ; Then convert to this byte value
Neil Turton's avatar
Neil Turton committed
806

807 808 809 810 811 812 813 814 815 816 817 818 819 820
; Bits in dynamic area flags (and page flags)
;
; rearranged slightly for Ursula - allow room for some expansion of DA flags in future without moving page flags
; mjs June 2001 merged the Ursula arrangement into HALised kernel
;
DynAreaFlags_APBits             * 15 :SHL:  0   ; currently only uses 2 bits, but may extend to allow svc/usr read-only
DynAreaFlags_NotBufferable      *  1 :SHL:  4
DynAreaFlags_NotCacheable       *  1 :SHL:  5
DynAreaFlags_DoublyMapped       *  1 :SHL:  6
DynAreaFlags_NotUserDraggable   *  1 :SHL:  7
DynAreaFlags_NeedsSpecificPages *  1 :SHL:  8   ; whether area will ever require particular physical pages
DynAreaFlags_Shrinkable         *  1 :SHL:  9   ; whether area may be shrunk when need more space in free pool
DynAreaFlags_SparseMap          *  1 :SHL: 10   ; whether area may have non-contiguous mapping of pages (Holey dynamic areas Batman!)
DynAreaFlags_PiersBinding       *  1 :SHL: 11   ; whether area is bound to client application, and so may be swapped out with it (not implemented yet)
Kevin Bracey's avatar
Kevin Bracey committed
821 822 823 824 825 826
DynAreaFlags_CPBits             *  7 :SHL: 12   ; cache policy variant for NotBufferable and NotCacheable bits

; Cache policies
;
CP_NCNB_Default                 * 0             ; no policy variants

827
CP_NCB_Default                  * 0             ; OS decides buffer policy (currently always MergingIdempotent)
Kevin Bracey's avatar
Kevin Bracey committed
828 829
CP_NCB_NonMerging               * 1             ; Non-merging write buffer. If not available, unbuffered.
CP_NCB_Merging                  * 2             ; Merging write buffer. If not available, non-merging.
830
CP_NCB_MergingIdempotent        * 3             ; Merging write buffer with idempotent memory (i.e. VMSA "Normal" non-cacheable type). If not available, merging write buffer.
Kevin Bracey's avatar
Kevin Bracey committed
831 832 833 834 835 836 837 838 839 840 841

CP_CNB_Default                  * 0             ; OS decides cache policy (writethrough). NCNB if not available
CP_CNB_Writethrough             * 1             ; Writethrough cacheable, non-buffered. If not available, NCNB.
CP_CNB_Writeback                * 2             ; Writeback cacheable, non-buffered. If not available,CNB_Writethrough.

CP_CB_Default                   * 0             ; OS decides cache policy (WB if available, W alloc if HAL requests)
CP_CB_Writethrough              * 1             ; Writethrough cacheable, read allocate. If not available, NCB_Merging
CP_CB_WritebackReadAlloc        * 2             ; Writeback cacheable, read allocate. If not available, writethrough.
CP_CB_WritebackWriteAlloc       * 3             ; Writeback cacheable, write allocate. If not available, WB/R.
CP_CB_AlternativeDCache         * 4             ; Use XScale/SA11x0 mini-data cache. If not available, CB_Default.

842
DynAreaFlags_NeedsDMA           *  1 :SHL: 15   ; only allocate from DMAable memory
843 844 845 846
; Bits 16-19 are used by RISCOS Ltd. We can reuse them for internal flags, but
; should probably avoid allocating any public flags.
DynAreaFlags_PMP                *  1 :SHL: 20   ; DA is backed by PMP/page is member of PMP

847
;
848 849
; Public page flags (note - may overlap DA flags)
; DynAreaFlags_[PMP]AccessMask also describes public page flags
850
;
851 852
PageFlags_Unavailable           *  1 :SHL: 15                      ; physical page has been claimed by someone for exclusive use (can't be requested by PreGrow handler or PMP PhysOp page list)

853
;
854
; Internal page flags (note - may overlap DA flags)
855 856
;
TempUncacheableShift            * 16
857
PageFlags_TempUncacheableBits   * 15 :SHL: TempUncacheableShift    ; temporary count of uncacheability, used by DMA mgr (via OS_Memory 0)
858 859
PageFlags_Required              *  1 :SHL: 21                      ; physical page asked for by handler (only set temporarily)

860
;
861
; Temporary flags only used by kernel (note - may overlap DA flags)
862
;
863 864 865 866 867 868 869 870
PageFlags_Unsafe                *  1 :SHL: 31                      ; skip cache/TLB maintenance in BangCamUpdate. flag not saved to CAM map.

; Mask to convert DANode_Flags to page flags
DynAreaFlags_AccessMask * DynAreaFlags_APBits :OR: DynAreaFlags_NotBufferable :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped :OR: DynAreaFlags_CPBits :OR: DynAreaFlags_PMP
; PMP LogOp can specify these flags
DynAreaFlags_PMPLogOpAccessMask * (DynAreaFlags_AccessMask :OR: PageFlags_Unavailable) :AND: :NOT: (DynAreaFlags_DoublyMapped :OR: DynAreaFlags_PMP)
; PMP PhysOp can specify these flags
DynAreaFlags_PMPPhysOpAccessMask * PageFlags_Unavailable
Neil Turton's avatar
Neil Turton committed
871 872


873
DynamicAreaSWI Entry
Neil Turton's avatar
Neil Turton committed
874 875 876 877 878 879 880 881 882 883 884 885 886 887
        BL      DynAreaSub
        PullEnv
        ORRVS   lr, lr, #V_bit
        ExitSWIHandler

DynAreaSub
        CMP     r0, #DAReason_Limit
        ADDCC   pc, pc, r0, LSL #2
        B       DynArea_Unknown
        B       DynArea_Create
        B       DynArea_Remove
        B       DynArea_GetInfo
        B       DynArea_Enumerate
        B       DynArea_Renumber
888 889
 [ ShrinkableDAs
        B       DynArea_ReturnFree
890 891
 |
        B       DynArea_Unknown
Neil Turton's avatar
Neil Turton committed
892
 ]
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
 [ DynArea_QuickHandles
        B       DynArea_GetChangeInfo
        B       DynArea_EnumerateInfo
        B       DynArea_SetClamps
 |
        B       DynArea_Unknown
        B       DynArea_Unknown
        B       DynArea_Unknown
 ]
 [ DA_Batman
        B       DynArea_SparseClaim
        B       DynArea_SparseRelease
 |
        B       DynArea_Unknown
        B       DynArea_Unknown
 ]
909 910 911 912 913 914 915 916 917 918
        B       DynArea_Unknown ; 11
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; |--Reserved for ROL
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; |
        B       DynArea_Unknown ; 19
        B       DynArea_Locate
919 920 921 922 923
        B       DynArea_PMP_PhysOp
        B       DynArea_PMP_LogOp
        B       DynArea_PMP_Resize
        B       DynArea_PMP_GetInfo
        B       DynArea_PMP_GetPages
924

925
;
Neil Turton's avatar
Neil Turton committed
926
; unknown OS_DynamicArea reason code
927
;
Neil Turton's avatar
Neil Turton committed
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
DynArea_Unknown
        ADRL    r0, ErrorBlock_HeapBadReason
DynArea_TranslateAndReturnError
      [ International
        Push    lr
        BL      TranslateError
        Pull    lr
      ]
DynArea_ReturnError
        SETV
        MOV     pc, lr

;**************************************************************************
;
;       DynArea_Create - Create a dynamic area
;
;       Internal routine called by DynamicAreaSWI and by reset code
;
; in:   r0 = reason code (0)
;       r1 = new area number, or -1 => RISC OS allocates number
;       r2 = initial size of area (in bytes)
;       r3 = base logical address of area, or -1 => RISC OS allocates address space
;       r4 = area flags
;               bits 0..3 = access privileges
;               bit  4 = 1 => not bufferable
;               bit  5 = 1 => not cacheable
;               bit  6 = 0 => area is singly mapped
;                      = 1 => area is doubly mapped
;               bit  7 = 1 => area is not user draggable in TaskManager window
957 958 959 960 961
;               bit  8 = 1 => area may require specific physical pages
;               bit  9 = 1 => area is shrinkable (only implemented if ShrinkableDAs)
;               bit 10 = 1 => area may be sparsely mapped (only implemented if DA_Batman)
;               bit 11 = 1 => area is bound to client application (allows areas to be overlayed in address space)
;                             not implemented yet, but declared in public API for Ursula
962 963
;               bits 12..14 => cache policy (if bits 4 or 5 set)
;               bit 15 = 1 => area requires DMA capable pages (is bit 12 in ROL's OS!)
964 965 966
;               bits 16-19 used by ROL
;               bit 20 = 1 => area is backed by physical memory pool
;               other bits reserved for future expansion + internal page flags (should be 0)
Neil Turton's avatar
Neil Turton committed
967
;
968
;       r5 = maximum size of logical area, or -1 for total RAM size
Neil Turton's avatar
Neil Turton committed
969 970 971
;       r6 -> area handler routine
;       r7 = workspace pointer for area handler (-1 => use base address)
;       r8 -> area description string (null terminated) (gets copied)
972
;       r9 = initial physical area size limit, in pages (physical memory pools), otherwise ignored
Neil Turton's avatar
Neil Turton committed
973 974 975 976 977 978 979 980
;
; out:  r1 = given or allocated area number
;       r3 = given or allocated base address of area
;       r5 = given or allocated maximum size
;       r0, r2, r4, r6-r9 preserved
;       r10-r12 may be corrupted
;

981
DynArea_Create Entry "r2,r6-r8"
Neil Turton's avatar
Neil Turton committed
982 983 984
        CMP     r1, #-1         ; do we have to allocate a new area number
        BEQ     %FT10

985 986 987 988 989 990 991 992 993 994 995
  [ DynArea_QuickHandles
        CMP     r1, #DynArea_NewAreas
        BLO     %FT06
        CMP     r1, #DynArea_NewAreas+DynArea_NumQHandles
        BLO     %FT08           ; can't choose your own quick handle
  ]

06
  [ DynArea_QuickHandles
        BL      QCheckAreaNumber ; see if area number is unique
  |
Neil Turton's avatar
Neil Turton committed
996
        BL      CheckAreaNumber ; see if area number is unique
997
  ]
Neil Turton's avatar
Neil Turton committed
998 999
        BCC     %FT20           ; didn't find it, so OK

1000
08
Neil Turton's avatar
Neil Turton committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
        ADR     r0, ErrorBlock_AreaAlreadyExists
DynArea_ErrorTranslateAndExit
        PullEnv
        B       DynArea_TranslateAndReturnError

        MakeErrorBlock  AreaAlreadyExists
        MakeErrorBlock  AreaNotOnPageBdy
        MakeErrorBlock  OverlappingAreas
        MakeErrorBlock  CantAllocateArea
        MakeErrorBlock  CantAllocateLevel2
        MakeErrorBlock  UnknownAreaHandler
1012 1013
        MakeErrorBlock  BadDynamicAreaOptions
        MakeErrorBlock  BadPageNumber
Neil Turton's avatar
Neil Turton committed
1014 1015 1016

; we have to allocate an area number for him

1017 1018
  [ DynArea_QuickHandles
10
Jeffrey Lee's avatar
Jeffrey Lee committed
1019
        LDR     r11, =ZeroPage
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
        LDR     r11, [r11, #DynArea_ws ]
        LDR     r1, DynArea_FreeQHandles          ;get index of next available quick handle, if any free
        CMP     r1, #0
        ADDNE   r1, r1, #DynArea_NewAreas-1       ;compute quick handle from index
        BNE     %FT20
        LDR     r1, DynArea_TreacleGuess          ;last non-quick number allocated
12
        ADD     r1, r1, #1                        ; increment for next guess (collisions should be *very* rare)
        CMP     r1, #DynArea_NewAreas+DynArea_NumQHandles
        MOVLO   r1, #DynArea_NewAreas+DynArea_NumQHandles
        BL      QCheckAreaNumber
        BCS     %BT12                             ; and try again
  |
Neil Turton's avatar
Neil Turton committed
1033 1034 1035 1036 1037 1038
10
        MOV     r1, #DynArea_NewAreas
12
        BL      CheckAreaNumber
        ADDCS   r1, r1, #1      ; that area number already exists, so increment
        BCS     %BT12           ; and try again
1039 1040
  ]

Neil Turton's avatar
Neil Turton committed
1041 1042
20

1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
; Check PMP settings
; If PMP is requested:
; * Must require specific pages
; * Mustn't be sparse
; * Mustn't be doubly mapped
; * Mustn't be requesting DMA auto-alloc
; * Must be zero initial size
; * Must have handler code
; Some of these restrictions may be lifted in future (e.g. if not requesting specific pages, kernel could implement OS_ChangeDynamicArea?)
        TST     r4, #DynAreaFlags_PMP
        BEQ     %FT21
        LDR     r11, =DynAreaFlags_DoublyMapped+DynAreaFlags_NeedsSpecificPages+DynAreaFlags_SparseMap+DynAreaFlags_NeedsDMA
        AND     r11, r4, r11
        TEQ     r11, #DynAreaFlags_NeedsSpecificPages
        TEQEQ   r2, #0
        ADRNE   r0, ErrorBlock_BadDynamicAreaOptions
        BNE     DynArea_ErrorTranslateAndExit
        TEQ     r6, #0
        ADREQ   r0, ErrorBlock_BadDynamicAreaOptions
        BEQ     DynArea_ErrorTranslateAndExit
21

Neil Turton's avatar
Neil Turton committed
1065 1066
; now validate maximum size of area

1067 1068 1069 1070
  [ DynArea_QuickHandles
    ;
    ; apply clamps on max size, as set by last call to OS_DynamicArea 8
    ;
Jeffrey Lee's avatar
Jeffrey Lee committed
1071
        LDR     r11, =ZeroPage
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
        LDR     r11, [r11, #DynArea_ws]
    [ DA_Batman
        TST     r4, #DynAreaFlags_SparseMap
        BEQ     DAC_notsparse
        LDR     r10, DynArea_OD8Clamp3   ; clamp for sparse dynamic area
        CMP     r5, r10                  ; if requested max size is > relevant clamp
        MOVHI   r5, r10                  ; then clamp it!
        LDR     r10, [sp]                ; requested initial size, from stack
        CMP     r5, r10
        MOVLO   r5, r10                  ; we must try to honour initial size (allowed to break clamp)
Jeffrey Lee's avatar
Jeffrey Lee committed
1082
        LDR     r10, =ZeroPage
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
        LDR     r11, [r10, #Page_Size]
        B       DAC_roundup
DAC_notsparse
    ]
        CMP     r5, #-1
        LDREQ   r10, DynArea_OD8Clamp1   ; clamp for max size requested of -1
        LDRNE   r10, DynArea_OD8Clamp2   ; clamp for max size requested of some specific value
        CMP     r5, r10                  ; if requested max size is > relevant clamp
        MOVHI   r5, r10                  ; then clamp it!
        LDR     r10, [sp]                ; requested initial size, from stack
        CMP     r5, r10
        MOVLO   r5, r10                  ; we must try to honour initial size (allowed to break clamp)
  ]

Jeffrey Lee's avatar
Jeffrey Lee committed
1097
        LDR     r10, =ZeroPage
Neil Turton's avatar
Neil Turton committed
1098 1099 1100 1101 1102
        LDR     r11, [r10, #Page_Size]
        LDR     r10, [r10, #RAMLIMIT]   ; get total RAM size
        CMP     r5, r10                 ; if requested maximum size is > total
        MOVHI   r5, r10                 ; then set max to total (NB. -1 passed in always yields HI)

1103
DAC_roundup
Neil Turton's avatar
Neil Turton committed
1104 1105 1106 1107 1108
        SUB     r10, r11, #1            ; also round up to a page multiple
        ADD     r5, r5, r10
        BIC     r5, r5, r10

; now see if we have to allocate a logical address space
1109 1110 1111
        TEQ     r5, #0                  ; If no logical size (i.e. purely physical PMP)
        MOVEQ   r3, #0                  ; Then set base addr to 0
        BEQ     %FT41                   ; And skip straight to claiming the DANode
Neil Turton's avatar
Neil Turton committed
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134

        CMP     r3, #-1                 ; if we are to allocate the address space
        BEQ     %FT30                   ; then go do it

; otherwise we must check that the address does not clash with anything else

        TST     r3, r10                         ; does it start on a page boundary
        ADRNE   r0, ErrorBlock_AreaNotOnPageBdy ; if not then error
        BNE     DynArea_ErrorTranslateAndExit

        BL      CheckForOverlappingAreas        ; in: r3 = address, r4 = flags, r5 = size; out: if error, r0->error, V=1
        BVC     %FT40
25
        PullEnv
        B       DynArea_ReturnError

30
        BL      AllocateAreaAddress             ; in: r4 = flags, r5 = size of area needed; out: r3, or V=1, r0->error
        BVS     %BT25
40
        BL      AllocateBackingLevel2           ; in: r3 = address, r4 = flags, r5 = size; out: VS if error
        BVS     %BT25

1135
41
Neil Turton's avatar
Neil Turton committed
1136
        Push    "r0,r1,r3"
1137 1138 1139 1140 1141 1142
  [ DynArea_QuickHandles
    ;we save work and reduce stress on system heap by claiming only one block, consisting of node followed by
    ;string space (always maximum length, but typically not overly wasteful compared to 2nd block overhead)
    ;
        MOV     r3, #DANode_NodeSize + DynArea_MaxNameLength + 1
  |
Neil Turton's avatar
Neil Turton committed
1143
        MOV     r3, #DANode_NodeSize
1144
  ]
Neil Turton's avatar
Neil Turton committed
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
        BL      ClaimSysHeapNode                ; out: r2 -> node
        STRVS   r0, [sp]
        Pull    "r0,r1,r3"
        BVS     %BT25                           ; failed to claim node

; now store data in node (could probably use STM if we shuffled things around)

        CMP     r7, #-1                         ; if workspace ptr = -1
        MOVEQ   r7, r3                          ; then use base address

        STR     r1, [r2, #DANode_Number]
        STR     r3, [r2, #DANode_Base]
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
  [ DA_Batman
        ;disallow some awkward flag options if SparseMap set (no error), and temporarily create as not sparse
        ;also disallow a DA handler
        TST     r4, #DynAreaFlags_SparseMap
        STREQ   r4, [r2, #DANode_Flags]
        BICNE   r7, r4, #DynAreaFlags_DoublyMapped + DynAreaFlags_NeedsSpecificPages + DynAreaFlags_Shrinkable + DynAreaFlags_SparseMap
        ORRNE   r7, r7, #DynAreaFlags_NotUserDraggable
        STRNE   r7, [r2, #DANode_Flags]
        MOVNE   r6, #0
        MOVNE   r7, #0
  |
Neil Turton's avatar
Neil Turton committed
1168
        STR     r4, [r2, #DANode_Flags]
1169
  ]
Neil Turton's avatar
Neil Turton committed
1170 1171 1172 1173 1174
        STR     r5, [r2, #DANode_MaxSize]
        STR     r6, [r2, #DANode_Handler]
        STR     r7, [r2, #DANode_Workspace]
        MOV     r7, #0                          ; initial size is zero
        STR     r7, [r2, #DANode_Size]          ; before we grow it
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
        TST     r4, #DynAreaFlags_PMP
        STR     r7, [r2, #DANode_PMP]
        STREQ   r7, [r2, #DANode_PMPMaxSize]
        STR     r7, [r2, #DANode_PMPSize]
        BEQ     %FT44
        STR     r3, [r2, #DANode_SparseHWM]
        TEQ     r9, #0
        STR     r9, [r2, #DANode_PMPMaxSize]
        BEQ     %FT44
        ; Allocate and initialise PMP for this DA
        Push    "r0-r3"
        LDR     r0, =ZeroPage
        LDR     r0, [r0, #MaxCamEntry]
        CMP     r9, r0
        ADDHI   r9, r0, #1
        MOV     r3, r9, LSL #2
        BL      ClaimSysHeapNode
        BVS     %FT43
        MOV     r10, r2
        MOV     r0, #-1
42
        SUBS    r3, r3, #4
        STR     r0, [r2], #4
        BNE     %BT42
        Pull    "r0-r3"
        STR     r10, [r2, #DANode_PMP]
        B       %FT44
43
        STR     r0, [sp]
        LDR     r2, [sp, #8]
        BL      FreeSysHeapNode
        Pull    "r0-r3"
        SETV
        B       %BT25
44
Neil Turton's avatar
Neil Turton committed
1210

1211 1212
  [ HAL
        ; update lower limit on IO space growth, if this DA exceeds previous limit
Jeffrey Lee's avatar
Jeffrey Lee committed
1213 1214 1215
      [ ZeroPage <> 0
        LDR     r7, =ZeroPage
      ]
1216 1217 1218 1219 1220 1221
        LDR     r6, [r7, #IOAllocLimit]
        ADD     lr, r3, r5
        CMP     lr, r6
        STRHI   lr, [r7, #IOAllocLimit]
  ]

Neil Turton's avatar
Neil Turton committed
1222 1223
; now make copy of string - first find out length of string

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
  [ DynArea_QuickHandles

        ADD     r7, r2, #DANode_NodeSize
        STR     r7, [r2, #DANode_Title]
        Push    "r0"
        MOV     r0, #DynArea_MaxNameLength
        TEQ     r8, #0
    [ DynArea_NullNamePtrMeansHexString
        ASSERT  DynArea_MaxNameLength > 8
        BNE     %FT45
        Push    "r1, r2"
        MOV     r0, r1                          ;string is 8-digit hex of DA number
        MOV     r1, r7
        MOV     r2, #DynArea_MaxNameLength+1
        SWI     XOS_ConvertHex8
        Pull    "r1, r2"
        B       %FT55
    |
        BEQ     %FT50                           ;assume NULL ptr to mean no DA name
    ]
45
        LDRB    r6, [r8], #1
        STRB    r6, [r7], #1
        SUB     r0, r0, #1
        TEQ     r6, #0
        TEQNE   r0, #0
        BNE     %BT45
50
        MOV     r0, #0
        STRB    r0, [r7], #1
55
        Pull    "r0"

  |

Neil Turton's avatar
Neil Turton committed
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
        MOV     r7, r8
45
        LDRB    r6, [r7], #1
        TEQ     r6, #0
        BNE     %BT45

        Push    "r0-r3"
        SUB     r3, r7, r8                      ; r3 = length inc. term.
        BL      ClaimSysHeapNode
        STRVS   r0, [sp]
        MOV     r7, r2
        Pull    "r0-r3"
        BVS     StringNodeClaimFailed

        STR     r7, [r2, #DANode_Title]
50
        LDRB    r6, [r8], #1                    ; copy string into claimed block
        STRB    r6, [r7], #1
        TEQ     r6, #0
        BNE     %BT50

1280 1281
 ] ;DynArea_QuickHandles

Neil Turton's avatar
Neil Turton committed
1282 1283
; now put node on list - list is sorted in ascending base address order

Jeffrey Lee's avatar
Jeffrey Lee committed
1284
        LDR     r8, =ZeroPage+DAList
Neil Turton's avatar
Neil Turton committed
1285 1286 1287
        LDR     r6, [r2, #DANode_Base]
60
        MOV     r7, r8
1288
        ASSERT  DANode_Link = 0                 ; For picking up pointer to first real node
Neil Turton's avatar
Neil Turton committed
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
        LDR     r8, [r7, #DANode_Link]          ; get next node
        TEQ     r8, #0                          ; if no more
        BEQ     %FT70                           ; then put it on here
        LDR     lr, [r8, #DANode_Base]
        CMP     lr, r6                          ; if this one is before ours
        BCC     %BT60                           ; then loop

70
        STR     r8, [r2, #DANode_Link]
        STR     r2, [r7, #DANode_Link]

1300
  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1301
        LDR     r11, =ZeroPage
1302
        LDR     r11, [r11, #DynArea_ws]
1303
        BL      AddDAToAddrLookupTable
1304 1305 1306 1307 1308 1309 1310 1311 1312
        ;so XOS_ChangeDynamicArea can pick up the node we are still creating
        STR     r1, DynArea_CreatingHandle
        STR     r2, DynArea_CreatingPtr
        ;so initial grow won't leave resize signature
        LDR     lr, DynArea_OD6Signature
        ORR     lr, lr, #&80000000
        STR     lr, DynArea_OD6Signature
  ]

Neil Turton's avatar
Neil Turton committed
1313 1314
; now we need to grow the area to its requested size

1315
        Push    "r0, r1, r2"
Neil Turton's avatar
Neil Turton committed
1316
        LDR     r0, [r2, #DANode_Number]
1317
        LDR     r1, [sp, #3*4]                  ; reload requested size off stack
1318 1319
        CMP     r1, #0                          ; skip redundant SWI
        SWINE   XOS_ChangeDynamicArea           ; deal with error - r0,r1,r2 still stacked
Neil Turton's avatar
Neil Turton committed
1320
        BVS     %FT90
1321 1322 1323 1324 1325 1326 1327
        Pull    "r0, r1, r2"

  [ DynArea_QuickHandles
;
; Now put node on alphabetically sorted list
;
        Push    "r3,r4,r5,r7,r8,r9"
Jeffrey Lee's avatar
Jeffrey Lee committed
1328
        LDR     r11, =ZeroPage
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
        LDR     r11, [r11, #DynArea_ws]
        ADR     r8, DynArea_SortedList - DANode_SortLink ;so that [r8, #DANode_SortLink] addresses list header)
75
        MOV     r7, r8                       ; previous
        LDR     r8, [r7, #DANode_SortLink]
        TEQ     r8, #0
        BEQ     %FT78
        ;ho hum, UK case insensitive string compare
        LDR     r3, [r2, #DANode_Title]
        LDR     r9, [r8, #