ChangeDyn 263 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
        ; OS_ChangeDynamicArea optimisations:

Jeffrey Lee's avatar
Jeffrey Lee committed
19 20
        GBLL  FastCDA_Bulk ; Do all cache/TLB maintenance in bulk instead of on a per-page basis
FastCDA_Bulk SETL {TRUE}
21 22 23 24

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

Jeffrey Lee's avatar
Jeffrey Lee committed
25
        GBLL  FastCDA_Unnecessary ; Avoid unnecessary cache cleaning in DoTheGrowPagesSpecified
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
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
Jeffrey Lee's avatar
Jeffrey Lee committed
41
FastCDA_Prof_DoublyRemoveCacheability # 4
42 43 44 45 46 47 48 49 50 51 52 53
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
Jeffrey Lee's avatar
Jeffrey Lee committed
54 55
FastCDA_Prof_MMUChangingCached       # 4 ; MMU_ChangingUncached followed by Cache_CleanInvalidateaAll
FastCDA_Prof_MMUChangingUncached     # 4 ; MMU_ChangingUncached followed by nothing
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
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
;******************************************************************************
; 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.
;******************************************************************************

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
; OS access privileges (OSAP_ to differentiate from AP_ used in Hdr:MEMM.*)
OSAP_Full * 0 ; user r/w/x, priv r/w/x
OSAP_Read * 1 ; user r/x, priv r/w/x
OSAP_None * 2 ; user none, priv r/w/x
OSAP_ROM  * 3 ; user r/x, priv r/x

; Corresponding values for OS_Memory 24
; (n.b. - XN flag is inverted)
CMA_ROM  * CMA_Partially_UserR+CMA_Partially_UserXN+CMA_Partially_PrivR+CMA_Partially_PrivXN
CMA_Read * CMA_ROM+CMA_Partially_PrivW
CMA_Full * CMA_Read+CMA_Partially_UserW
CMA_None * CMA_Partially_PrivR+CMA_Partially_PrivW+CMA_Partially_PrivXN

; Convenience macro for defining DA/page flags and corresponding CMA value
        MACRO
$area   DefAreaFlags $ap, $extra
AreaFlags_$area * OSAP_$ap :OR: ($extra + 0)
CMA_$area * CMA_$ap
        MEND

; Flags for kernel-managed DAs
AppSpace         DefAreaFlags Full
SysHeap          DefAreaFlags Full
RMA              DefAreaFlags Full
Screen           DefAreaFlags Full, DynAreaFlags_NotCacheable :OR: DynAreaFlags_DoublyMapped :OR: DynAreaFlags_NeedsSpecificPages
Sprites          DefAreaFlags Full
FontArea         DefAreaFlags None
RAMDisc          DefAreaFlags None, DynAreaFlags_NotCacheable
RAMDisc_SA       DefAreaFlags None ; StrongARM-specific (~CB gives poor performance for current StrongARMs)
FreePool         DefAreaFlags None, DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable :OR: DynAreaFlags_PMP

; Flags for other kernel managed areas

Duff                 DefAreaFlags None, DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable
CursorChunkCacheable DefAreaFlags Read, PageFlags_Unavailable ; Should be OSAP_None?
CursorChunk          DefAreaFlags Read, PageFlags_Unavailable :OR: DynAreaFlags_NotCacheable
145
PageTablesAccess     DefAreaFlags None ; n.b. just the AP value, for full page flags use PageTable_PageFlags workspace var
146 147 148 149 150 151 152 153 154 155 156 157
HALWorkspace         DefAreaFlags Read, PageFlags_Unavailable
HALWorkspaceNCNB     DefAreaFlags None, DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable :OR: PageFlags_Unavailable
ZeroPage             DefAreaFlags Read, PageFlags_Unavailable
ScratchSpace         DefAreaFlags Read, PageFlags_Unavailable
DCacheClean          DefAreaFlags None ; ideally, svc read only, user none but hey ho
CAM                  DefAreaFlags None, PageFlags_Unavailable
SVCStack             DefAreaFlags Read, PageFlags_Unavailable
IRQStack             DefAreaFlags None, PageFlags_Unavailable
ABTStack             DefAreaFlags None, PageFlags_Unavailable
UNDStack             DefAreaFlags None, PageFlags_Unavailable
Kbuffs               DefAreaFlags Read, PageFlags_Unavailable
DebuggerSpace        DefAreaFlags Read, PageFlags_Unavailable
Neil Turton's avatar
Neil Turton committed
158

159 160 161
  [ DA_Batman
ChangeDyn_Batcall    * -3               ; special DA number to select Batman usage of OS_ChangeDynamicArea
  ]
162
; -2 was an internal value, now no longer used
Neil Turton's avatar
Neil Turton committed
163 164 165 166 167 168 169 170 171 172 173 174
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

; Number of entries in page block on stack

175
NumPageBlockEntries *   63
Neil Turton's avatar
Neil Turton committed
176 177 178
PageBlockSize   *       NumPageBlockEntries * 12
PageBlockChunk  *       NumPageBlockEntries * 4096

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
;
; 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
216 217 218
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)
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
;
                          ^  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)
250
DynArea_AddrLookup        # 4<<DynArea_AddrLookupBits ; Lookup table for fast logaddr -> dynarea lookup
251 252 253 254 255 256 257 258
;
DynArea_ws_size           *  :INDEX:@               ;must be multiple of 4
;
            ASSERT DynArea_QHandleArray = DynArea_FreeQHandles +4
  ]
;


Kevin Bracey's avatar
Kevin Bracey committed
259
;        InsertDebugRoutines
Neil Turton's avatar
Neil Turton committed
260 261 262 263

; Exit from ChangeDynamicArea with error Not all moved

failure_IRQgoingClearSemaphore
Jeffrey Lee's avatar
Jeffrey Lee committed
264 265
        LDR     r0, =ZeroPage
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
266
        STR     r0, [r0, #CDASemaphore]
Jeffrey Lee's avatar
Jeffrey Lee committed
267 268 269 270
      |
        MOV     r10, #0
        STR     r10, [r0, #CDASemaphore]
      ]
Neil Turton's avatar
Neil Turton committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
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

310 311 312 313 314
; 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
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
Call_CAM_Mapping
        Push    "r0, r1, r4, r6, lr"
        BL      BangCamUpdate
        Pull    "r0, r1, r4, r6, pc"

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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

344
        CMP     r0, #ChangeDyn_AplSpace         ; if finding out about app space
Jeffrey Lee's avatar
Jeffrey Lee committed
345
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
346
        LDREQ   r1, [r0, #AplWorkSize+1]        ; then r1 = current size
347
        LDREQ   r2, [r0, #SoftAplWorkMaxSize+1] ; and r2 = max size
Jeffrey Lee's avatar
Jeffrey Lee committed
348
      |
349 350 351
        LDREQ   r2, =ZeroPage
        LDREQ   r1, [r2, #AplWorkSize]          ; then r1 = current size
        LDREQ   r2, [r2, #SoftAplWorkMaxSize]   ; and r2 = max size
Jeffrey Lee's avatar
Jeffrey Lee committed
352
      ]
Neil Turton's avatar
Neil Turton committed
353 354 355 356 357 358 359 360 361 362 363
        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
364 365 366
  [ DynArea_QuickHandles
        BL      QCheckAreaNumber                ; out: r10 -> node
  |
Neil Turton's avatar
Neil Turton committed
367
        BL      CheckAreaNumber                 ; out: r10 -> node
368
  ]
Neil Turton's avatar
Neil Turton committed
369 370 371
        Pull    "r1,lr"
        BCC     %FT05                           ; [not a new one, so use old code]

372 373 374
        LDR     r11, [r10, #DANode_Flags]
        TST     r11, #DynAreaFlags_PMP
        BNE     %FT01
Neil Turton's avatar
Neil Turton committed
375 376 377 378 379 380
        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
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
        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
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
        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
417
      LDR      R10, =ZeroPage
Neil Turton's avatar
Neil Turton committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
      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
434
        LDR     r14, =ZeroPage
Neil Turton's avatar
Neil Turton committed
435 436 437
        LDR     r10, [r14, #CamEntriesPointer]
        LDR     r14, [r14, #MaxCamEntry]
01
438
        LDR     r12, [r0], #4                   ; page number
Neil Turton's avatar
Neil Turton committed
439 440 441
        CMP     r12, r14
        Pull    "r0,r14", HI
        ExitSWIHandler HI
442

443
   [ AMB_LazyMapIn
444 445 446 447 448 449 450
        ;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"
   ]

451 452 453
        ADD     r11, r10, r12, LSL #CAM_EntrySizeLog2
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
Neil Turton's avatar
Neil Turton committed
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
        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
479
        LDR     r14, =ZeroPage
Neil Turton's avatar
Neil Turton committed
480 481
        LDR     r9, [r14, #MaxCamEntry]
        LDR     r14, [r14, #CamEntriesPointer]  ; r14 -> start of cam map
482
        ADD     r9, r14, r9, LSL #CAM_EntrySizeLog2 ; r9 -> first word of last entry in cam map
Neil Turton's avatar
Neil Turton committed
483 484 485 486 487 488 489
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
490

491
   [ AMB_LazyMapIn
492 493 494 495 496 497 498
        ;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"
   ]

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

503
        LDR     r12, [r10, #CAM_LogAddr]        ; load address from guessed page
Neil Turton's avatar
Neil Turton committed
504 505 506 507 508 509 510 511 512 513 514 515 516
        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
Jeffrey Lee's avatar
Jeffrey Lee committed
517
        SUBEQ   r10, r9, #CAM_EntrySize         ; then invalid page so go from last one
Neil Turton's avatar
Neil Turton committed
518 519 520 521
        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
522
        LDR     r5, =ZeroPage+PhysRamTable
523
        SUB     r10, r14, #CAM_EntrySize
Neil Turton's avatar
Neil Turton committed
524 525 526 527 528 529
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
530
        ASSERT  CAM_EntrySizeLog2 <= 16
531
        BICCS   r7, r7, #&F00
532
        ADDCS   r10, r10, r7, LSR #12-CAM_EntrySizeLog2 ; then advance CAM entry position
Neil Turton's avatar
Neil Turton committed
533 534
        BCS     %BT30                           ; and loop to next bank

535
        ADD     r10, r10, r6, LSL #CAM_EntrySizeLog2 ; advance by 2 words for each page in this bank
Neil Turton's avatar
Neil Turton committed
536
40
537
        SUBCS   r10, r9, #CAM_EntrySize         ; search from last one, to fail quickly (if CS)
Neil Turton's avatar
Neil Turton committed
538 539 540 541
45
        Pull    "r5-r8"
50
        CMP     r10, r9                         ; if not just done last one,
542 543
        ASSERT  CAM_LogAddr=0
        LDRNE   r12, [r10, #CAM_EntrySize]!     ; then get logical address
Neil Turton's avatar
Neil Turton committed
544 545 546 547 548 549 550 551
        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
552
        LDREQ   r12, [r10, #CAM_PageFlags]      ; if match, then r12 = PPL
Neil Turton's avatar
Neil Turton committed
553
        SUBEQ   r10, r10, r14                   ; and page number=(r10-r14)>>3
554
        MOVEQ   r10, r10, LSR #CAM_EntrySizeLog2
Neil Turton's avatar
Neil Turton committed
555 556 557 558 559 560 561 562 563 564

        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.
565
; address of -1 means "put the page out of the way"
Neil Turton's avatar
Neil Turton committed
566 567
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

568 569 570 571 572
; 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
573 574 575 576
SetMemMapEntries_Code  ROUT
        Push    "r0-r6, r9, lr"
        MOV     r12, r0

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

Jeffrey Lee's avatar
Jeffrey Lee committed
580
        LDR     r9, =ZeroPage
Neil Turton's avatar
Neil Turton committed
581
        LDR     r5, [r9, #MaxCamEntry]
582 583
        LDR     r9, [r9, #CamEntriesPointer]
        ADD     r9, r9, #CAM_PageFlags
Neil Turton's avatar
Neil Turton committed
584 585 586 587 588 589 590
01
        LDR     r2, [r12], #4
        CMP     r2, r5
        BHI     %FT02                   ; finished
        LDMIA   r12!, {r3, r11}
        CMP     r3, #-1
        LDRHS   r3, =DuffEntry
591
        MOVHS   r11, #AreaFlags_Duff
592 593
        ; Ensure PMP membership flag is retained - just in case caller doesn't
        ; know what he's doing
594
        LDR     r6, =StickyPageFlags+DynAreaFlags_PMP
595
        LDR     r0, [r9, r2, LSL #CAM_EntrySizeLog2]
596 597
        AND     r0, r0, r6
        BIC     r11, r11, r6
598
        ORR     r11, r11, r0
Neil Turton's avatar
Neil Turton committed
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
        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
;

619 620 621

DynArea_NewAreas *      &100            ; Allocated area numbers start here
DynArea_NewAreasBase *  &04000000       ; Allocated area addresses start here
622 623
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
624

625
;
626
; Internal page flags (note - may overlap DA flags)
627 628
;
TempUncacheableShift            * 16
629
PageFlags_TempUncacheableBits   * 15 :SHL: TempUncacheableShift    ; temporary count of uncacheability, used by DMA mgr (via OS_Memory 0)
630 631
PageFlags_Required              *  1 :SHL: 21                      ; physical page asked for by handler (only set temporarily)

632
;
633
; Temporary flags only used by kernel (note - may overlap DA flags)
634
;
635 636
PageFlags_Unsafe                *  1 :SHL: 31                      ; skip cache/TLB maintenance in BangCamUpdate. flag not saved to CAM map.

637
; Mask to convert DANode_Flags to page flags (i.e. flags that are common between the two)
638 639 640 641 642
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
643

644 645 646 647 648 649 650 651 652
; Sticky page flags - they're preserved over most operations, including changes
; in ownership
StickyPageFlags * PageFlags_Reserved

; Ensure user can't specify any sticky flags for the main calls
; If this changes, lots of code will need checking/updating!
        ASSERT  (DynAreaFlags_AccessMask :AND: StickyPageFlags) = 0
        ASSERT  (DynAreaFlags_PMPLogOpAccessMask :AND: StickyPageFlags) = 0
        ASSERT  (DynAreaFlags_PMPPhysOpAccessMask :AND: StickyPageFlags) = 0
Neil Turton's avatar
Neil Turton committed
653

654
DynamicAreaSWI Entry
Neil Turton's avatar
Neil Turton committed
655 656 657 658 659 660 661 662 663 664 665 666 667 668
        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
669 670
 [ ShrinkableDAs
        B       DynArea_ReturnFree
671 672
 |
        B       DynArea_Unknown
Neil Turton's avatar
Neil Turton committed
673
 ]
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
 [ 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
 ]
690 691 692 693 694 695 696 697 698 699
        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
700 701 702 703 704
        B       DynArea_PMP_PhysOp
        B       DynArea_PMP_LogOp
        B       DynArea_PMP_Resize
        B       DynArea_PMP_GetInfo
        B       DynArea_PMP_GetPages
705
        B       DynArea_AplSpaceLimit
706

707
;
Neil Turton's avatar
Neil Turton committed
708
; unknown OS_DynamicArea reason code
709
;
Neil Turton's avatar
Neil Turton committed
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
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
739 740 741 742 743
;               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
744 745
;               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!)
746 747 748
;               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
749
;
750
;       r5 = maximum size of logical area, or -1 for total RAM size
Neil Turton's avatar
Neil Turton committed
751 752 753
;       r6 -> area handler routine
;       r7 = workspace pointer for area handler (-1 => use base address)
;       r8 -> area description string (null terminated) (gets copied)
754
;       r9 = initial physical area size limit, in pages (physical memory pools), otherwise ignored
Neil Turton's avatar
Neil Turton committed
755 756 757 758 759 760 761 762
;
; 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
;

763
DynArea_Create Entry "r2,r6-r8"
Neil Turton's avatar
Neil Turton committed
764 765 766
        CMP     r1, #-1         ; do we have to allocate a new area number
        BEQ     %FT10

767 768 769 770 771 772 773 774 775 776 777
  [ 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
778
        BL      CheckAreaNumber ; see if area number is unique
779
  ]
Neil Turton's avatar
Neil Turton committed
780 781
        BCC     %FT20           ; didn't find it, so OK

782
08
Neil Turton's avatar
Neil Turton committed
783 784 785 786 787 788 789 790 791 792 793
        ADR     r0, ErrorBlock_AreaAlreadyExists
DynArea_ErrorTranslateAndExit
        PullEnv
        B       DynArea_TranslateAndReturnError

        MakeErrorBlock  AreaAlreadyExists
        MakeErrorBlock  AreaNotOnPageBdy
        MakeErrorBlock  OverlappingAreas
        MakeErrorBlock  CantAllocateArea
        MakeErrorBlock  CantAllocateLevel2
        MakeErrorBlock  UnknownAreaHandler
794 795
        MakeErrorBlock  BadDynamicAreaOptions
        MakeErrorBlock  BadPageNumber
Neil Turton's avatar
Neil Turton committed
796 797 798

; we have to allocate an area number for him

799 800
  [ DynArea_QuickHandles
10
Jeffrey Lee's avatar
Jeffrey Lee committed
801
        LDR     r11, =ZeroPage
802 803 804 805 806 807 808 809 810 811 812 813 814
        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
815 816 817 818 819 820
10
        MOV     r1, #DynArea_NewAreas
12
        BL      CheckAreaNumber
        ADDCS   r1, r1, #1      ; that area number already exists, so increment
        BCS     %BT12           ; and try again
821 822
  ]

Neil Turton's avatar
Neil Turton committed
823 824
20

825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
; 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

847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
; Check cacheable doubly-mapped area restrictions
; * On ARMv5 and below we disallow cacheable doubly-mapped areas outright, because the virtually tagged caches simply can't deal with them (at least when it comes to writes)
; * ARMv6 can support cacheable doubly-mapped areas, but only if we comply with the page colouring restrictions, which is something we currently don't do. So disallow there as well.
; * ARMv7+ doesn't have page colouring restrictions, but due to the potential of virtually tagged instruction caches (which would complicate OS_SynchroniseCodeAreas), for simplicity we only allow the area to be cacheable if it's non-executable
        AND     r11, r4, #DynAreaFlags_DoublyMapped+DynAreaFlags_NotCacheable
        TEQ     r11, #DynAreaFlags_DoublyMapped
        BNE     %FT22
        ; Cheesy architecture check: check the identified cache/ARMop type
        LDR     r11, =ZeroPage
        LDRB    lr, [r11, #Cache_Type]
        TEQ     lr, #CT_ctype_WB_CR7_Lx
        ADRNE   r0, ErrorBlock_BadDynamicAreaOptions
        BNE     DynArea_ErrorTranslateAndExit
        ; Check the supplied access policy is XN
        LDR     r11, [r11, #MMU_PPLAccess]
        AND     lr, r4, #DynAreaFlags_APBits
        LDR     r11, [r11, lr, LSL #2]
        TST     r11, #CMA_Partially_UserXN+CMA_Partially_PrivXN ; n.b. XN flag sense is inverted in PPLAccess, so NE means executable
        ADRNE   r0, ErrorBlock_BadDynamicAreaOptions
        BNE     DynArea_ErrorTranslateAndExit
22

Neil Turton's avatar
Neil Turton committed
869 870
; now validate maximum size of area

871 872 873 874
  [ DynArea_QuickHandles
    ;
    ; apply clamps on max size, as set by last call to OS_DynamicArea 8
    ;
Jeffrey Lee's avatar
Jeffrey Lee committed
875
        LDR     r11, =ZeroPage
876 877 878 879 880 881 882 883 884 885
        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
886
        LDR     r10, =ZeroPage
887 888 889 890 891 892 893 894 895 896 897 898 899 900
        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
901
        LDR     r10, =ZeroPage
Neil Turton's avatar
Neil Turton committed
902 903 904 905 906
        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)

907
DAC_roundup
Neil Turton's avatar
Neil Turton committed
908 909 910 911 912
        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
913 914 915
        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
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938

        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

939
41
Neil Turton's avatar
Neil Turton committed
940
        Push    "r0,r1,r3"
941 942 943 944 945 946
  [ 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
947
        MOV     r3, #DANode_NodeSize
948
  ]
Neil Turton's avatar
Neil Turton committed
949 950 951 952 953 954 955 956 957 958 959 960
        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]
961 962 963 964 965 966 967 968 969 970 971
  [ 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
972
        STR     r4, [r2, #DANode_Flags]
973
  ]
Neil Turton's avatar
Neil Turton committed
974 975 976 977 978
        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
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
        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
1014

1015
        ; update lower limit on IO space growth, if this DA exceeds previous limit
Jeffrey Lee's avatar
Jeffrey Lee committed
1016 1017 1018
      [ ZeroPage <> 0
        LDR     r7, =ZeroPage
      ]
1019 1020 1021 1022 1023
        LDR     r6, [r7, #IOAllocLimit]
        ADD     lr, r3, r5
        CMP     lr, r6
        STRHI   lr, [r7, #IOAllocLimit]

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

1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
  [ 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
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
        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

1082 1083
 ] ;DynArea_QuickHandles

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

Jeffrey Lee's avatar
Jeffrey Lee committed
1086
        LDR     r8, =ZeroPage+DAList
Neil Turton's avatar
Neil Turton committed
1087 1088 1089
        LDR     r6, [r2, #DANode_Base]
60
        MOV     r7, r8
1090
        ASSERT  DANode_Link = 0                 ; For picking up pointer to first real node
Neil Turton's avatar
Neil Turton committed
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
        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]

1102
  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1103
        LDR     r11, =ZeroPage
1104
        LDR     r11, [r11, #DynArea_ws]
1105
        BL      AddDAToAddrLookupTable
1106 1107 1108 1109 1110 1111 1112 1113 1114
        ;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
1115 1116
; now we need to grow the area to its requested size

1117
        Push    "r0, r1, r2"
Neil Turton's avatar
Neil Turton committed
1118
        LDR     r0, [r2, #DANode_Number]
1119
        LDR     r1, [sp, #3*4]                  ; reload requested size off stack
1120 1121
        CMP     r1, #0                          ; skip redundant SWI
        SWINE   XOS_ChangeDynamicArea           ; deal with error - r0,r1,r2 still stacked
Neil Turton's avatar
Neil Turton committed
1122
        BVS     %FT90
1123 1124 1125 1126 1127 1128 1129
        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
1130
        LDR     r11, =ZeroPage
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
        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, #DANode_Title]
76
        LDRB    r4, [r3],#1
        uk_LowerCase r4,r11
        LDRB    r5, [r9],#1
        uk_LowerCase r5,r11
        CMP     r4, r5
        BNE     %FT77
        CMP     r4, #0
        BNE     %BT76
77
        BHI     %BT75
78
        STR     r2, [r7, #DANode_SortLink]
        STR     r8, [r2, #DANode_SortLink]
79
        Pull    "r3,r4,r5,r7,r8,r9"
  ] ;DynArea_QuickHandles

  [ DA_Batman
        TST     r4, #DynAreaFlags_SparseMap
        LDRNE   r11, [r2, #DANode_Flags]
        ORRNE   r11, r11, #DynAreaFlags_SparseMap ; set this in node now (after initial grow)
        STRNE   r11, [r2, #DANode_Flags]
        LDRNE   r11, [r2, #DANode_Size]
        LDRNE   lr,  [r2, #DANode_Base]
        ADDNE   r11, r11, lr
        STRNE   r11, [r2, #DANode_SparseHWM]      ; initial high water mark
  ]

  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1171
        LDR     r11, =ZeroPage
1172 1173 1174 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
        LDR     r11, [r11, #DynArea_ws]

        TST     r4, #DynAreaFlags_Shrinkable
        LDRNE   lr, DynArea_ShrinkableSubList
        STRNE   lr, [r2, #DANode_SubLink]
        STRNE   r2, DynArea_ShrinkableSubList   ;link onto front of Shrinkable sublist if Shrinkable

        MOV     lr, #-1
        STR     lr, DynArea_CreatingHandle      ;invalidate this now
        CMP     r1, #ChangeDyn_MaxArea
        BHI     %FT72
        ADR     lr, DynArea_SysQHandleArray
        STR     r2, [lr, r1, LSL #2]            ;system handle - store ptr to node for quick reference
        B       %FT80
72
        LDR     lr, DynArea_OD6Signature
        STR     lr, DynArea_OD6PrevSignature
        ORR     lr, lr, #1
        STR     lr, DynArea_OD6Signature
        STR     r1, DynArea_OD6Handle
        CMP     r1, #DynArea_NewAreas
        BLO     %FT80
        CMP     r1, #DynArea_NewAreas+DynArea_NumQHandles
        BHS     %FT74
        SUB     r10, r1, #DynArea_NewAreas
        ADR     lr, DynArea_QHandleArray
        LDR     r6, [lr, r10, LSL #2]           ;pick up index of next free quick handle
        STR     r6, DynArea_FreeQHandles        ;store as index of first free quick handle
        STR     r2, [lr, r10, LSL #2]           ;store ptr to node for quick reference
        B       %FT80
74
        LDR     r10, DynArea_TreacleGuess
        ADD     r10, r10, #1
        STR     r10, DynArea_TreacleGuess       ;non-quick handle allocated, increment for next allocate
80
  ] ;DynArea_QuickHandles

Neil Turton's avatar
Neil Turton committed
1209 1210 1211

; Now issue service to tell TaskManager about it

1212 1213
        Push    "r0, r1, r2"
        MOV     r2, r1                          ; r2 = area number
Neil Turton's avatar
Neil Turton committed
1214 1215
        MOV     r1, #Service_DynamicAreaCreate
        BL      Issue_Service
1216
        Pull    "r0, r1, r2"
Neil Turton's avatar
Neil Turton committed
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228

        CLRV
        EXIT

90

; The dynamic area is not being created, because we failed to grow the area to the required size.
; The area itself will have no memory allocated to it (since if grow fails it doesn't move any).
; We must delink the node from our list, free the string node, and then the area node itself.

        STR     r0, [sp, #0*4]                  ; remember error pointer in stacked r0
        STR     r8, [r7, #DANode_Link]          ; delink area
1229 1230
  [ :LNOT: DynArea_QuickHandles
        LDR     r2, [r2, #DANode_Title]
Neil Turton's avatar
Neil Turton committed
1231
        BL      FreeSysHeapNode                 ; free title string node
1232 1233
  ]
        Pull    "r0, r1, r2"                    ; pull stacked registers, and drop thru to...
Neil Turton's avatar
Neil Turton committed
1234

1235
  [ :LNOT: DynArea_QuickHandles
Neil Turton's avatar
Neil Turton committed
1236 1237 1238 1239 1240 1241 1242
; The dynamic area is not being created, because there is no room to allocate space for the title string
; We must free the DANode we have allocated
; It would be nice to also free the backing L2, but we'll leave that for now.

; in: r2 -> DANode

StringNodeClaimFailed
1243 1244
  ]

Neil Turton's avatar
Neil Turton committed
1245 1246 1247
        Push    "r0, r1"
        BL      FreeSysHeapNode
        Pull    "r0, r1"
1248
  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1249
        LDR     r11, =ZeroPage
1250 1251 1252 1253
        LDR     r11, [r11, #DynArea_ws]
        MOV     lr, #-1
        STR     lr, DynArea_CreatingHandle
  ]
Neil Turton's avatar
Neil Turton committed
1254 1255 1256
        PullEnv
        B       DynArea_ReturnError

Jeffrey Lee's avatar
Jeffrey Lee committed
1257 1258
        LTORG

1259 1260 1261 1262
; Add a dynamic area to the quick address lookup table
; In:
;  R2 = DANode ptr
;  R11 = DynArea_ws
1263
AddDAToAddrLookupTable ROUT
1264
        Entry   "r0-r1,r3,r6"
1265
        LDR     r3, [r2, #DANode_MaxSize]
1266
        ADRL    r0, DynArea_AddrLookup
1267
        TEQ     r3, #0
1268
        LDR     r1, [r2, #DANode_Flags]
1269
        BEQ     %FT90
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
        LDR     r6, [r2, #DANode_Base]
        TST     r1, #DynAreaFlags_DoublyMapped
        SUBNE   r6, r6, r3                      ; Get true start address
        MOVNE   r3, r3, LSL #1
        AND     r1, r6, #DynArea_AddrLookupMask ; Round down start address
        ADD     lr, r6, r3
        AND     r3, lr, #DynArea_AddrLookupMask
        TEQ     lr, r3
        ADDNE   r3, r3, #DynArea_AddrLookupSize ; Round up end address
        SUB     r3, r3, r1
        ADD     r0, r0, r1, LSR #30-DynArea_AddrLookupBits
71
        LDR     lr, [r0], #4
        TEQ     lr, #0
        STREQ   r2, [r0, #-4]
        BEQ     %FT72
        LDR     lr, [lr, #DANode_Base]
        CMP     lr, r6
        STRHI   r2, [r0, #-4]                   ; Update LUT if current entry starts after us
72
        SUBS    r3, r3, #DynArea_AddrLookupSize
        BNE     %BT71
1292
90
1293 1294
        EXIT

Neil Turton's avatar
Neil Turton committed
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
;**************************************************************************
;
;       DynArea_Remove - Remove a dynamic area
;
;       Internal routine called by DynamicAreaSWI
;
; in:   r0 = reason code (1)
;       r1 = area number
;
; out:  r10-r12 may be corrupted
;       All other registers preserved
;

1308
DynArea_Remove Entry
1309 1310

        ;*MUST NOT USE QCheckAreaNumber* (need r11 = previous)
Neil Turton's avatar
Neil Turton committed
1311 1312 1313
        BL      CheckAreaNumber         ; check that area is there
        BCC     UnknownDyn              ; [not found]

1314
  [ DA_Batman
1315 1316
        LDR     lr,[r10,#DANode_Flags]
        TST     lr,#DynAreaFlags_SparseMap
1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
        BEQ     DAR_notsparse
        Push    "r0,r2-r3"
        MOV     r0,#DAReason_SparseRelease
        LDR     r2,[r10,#DANode_Base]
        LDR     r3,[r10,#DANode_MaxSize]
        SWI     XOS_DynamicArea            ;release all pages in sparse area
        STRVS   r0,[SP]
        Pull    "r0,r2-r3"
        EXIT    VS
        B       DAR_delink
DAR_notsparse
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348