ChangeDyn 256 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
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
152
SVCStack             DefAreaFlags None, PageFlags_Unavailable
153 154 155 156 157
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
163
; -> See hdr.OSMem for other area definitions
Neil Turton's avatar
Neil Turton committed
164 165 166

; Number of entries in page block on stack

167
NumPageBlockEntries *   63
Neil Turton's avatar
Neil Turton committed
168 169 170
PageBlockSize   *       NumPageBlockEntries * 12
PageBlockChunk  *       NumPageBlockEntries * 4096

171 172 173 174 175 176 177 178 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
;
; 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
208 209 210
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)
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
;
                          ^  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)
242
DynArea_AddrLookup        # 4<<DynArea_AddrLookupBits ; Lookup table for fast logaddr -> dynarea lookup
243 244 245 246 247 248 249 250
;
DynArea_ws_size           *  :INDEX:@               ;must be multiple of 4
;
            ASSERT DynArea_QHandleArray = DynArea_FreeQHandles +4
  ]
;


Kevin Bracey's avatar
Kevin Bracey committed
251
;        InsertDebugRoutines
Neil Turton's avatar
Neil Turton committed
252 253 254 255

; Exit from ChangeDynamicArea with error Not all moved

failure_IRQgoingClearSemaphore
Jeffrey Lee's avatar
Jeffrey Lee committed
256 257
        LDR     r0, =ZeroPage
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
258
        STR     r0, [r0, #CDASemaphore]
Jeffrey Lee's avatar
Jeffrey Lee committed
259 260 261 262
      |
        MOV     r10, #0
        STR     r10, [r0, #CDASemaphore]
      ]
Neil Turton's avatar
Neil Turton committed
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 288 289 290 291 292 293 294 295 296 297 298 299 300 301
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

302 303 304 305 306
; 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
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
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

333
        ASSERT  ChangeDyn_MaxArea < ReadDyn_ReturnMax
Neil Turton's avatar
Neil Turton committed
334

335
        CMP     r0, #ChangeDyn_AplSpace         ; if finding out about app space
Jeffrey Lee's avatar
Jeffrey Lee committed
336
      [ ZeroPage = 0
Neil Turton's avatar
Neil Turton committed
337
        LDREQ   r1, [r0, #AplWorkSize+1]        ; then r1 = current size
338
        LDREQ   r2, [r0, #SoftAplWorkMaxSize+1] ; and r2 = max size
Jeffrey Lee's avatar
Jeffrey Lee committed
339
      |
340 341 342
        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
343
      ]
Neil Turton's avatar
Neil Turton committed
344 345 346 347 348 349 350 351 352 353
        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
354
        BICCC   r1, r0, #ReadDyn_ReturnMax      ; else knock off bit 7
355 356 357
  [ DynArea_QuickHandles
        BL      QCheckAreaNumber                ; out: r10 -> node
  |
Neil Turton's avatar
Neil Turton committed
358
        BL      CheckAreaNumber                 ; out: r10 -> node
359
  ]
Neil Turton's avatar
Neil Turton committed
360 361 362
        Pull    "r1,lr"
        BCC     %FT05                           ; [not a new one, so use old code]

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

434
   [ AMB_LazyMapIn
435 436 437 438 439 440 441
        ;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"
   ]

442 443 444
        ADD     r11, r10, r12, LSL #CAM_EntrySizeLog2
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
Neil Turton's avatar
Neil Turton committed
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
        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

469
        Push    "r0, r3-r5,r7-r9, r14"
Jeffrey Lee's avatar
Jeffrey Lee committed
470
        LDR     r14, =ZeroPage
471 472
        LDR     r7, [r14, #MaxCamEntry]
        LDR     r12, [r14, #CamEntriesPointer]  ; r12 -> start of cam map
Neil Turton's avatar
Neil Turton committed
473
10
474 475 476
        LDR     r3, [r0, #0]                    ; r3 = guess page number (or -1)
        CMP     r3, #-1                         ; if -1 then end of list
        Pull    "r0, r3-r5,r7-r9, r14", EQ      ; so restore registers
Neil Turton's avatar
Neil Turton committed
477 478
        ExitSWIHandler EQ                       ; and exit

479
        LDR     r4, [r0, #4]                    ; r4 = logical address
480

481
   [ AMB_LazyMapIn
482
        ;may need AMB to make mapping honest (as if not lazy), if page is in currently mapped app
483 484
        Push    "r0"
        MOV     r0, r4                          ; logical address to make honest
485
        BL      AMB_MakeHonestLA                ; note, quickly dismisses non app space addresses
486
        Pull    "r0"
487 488
   ]

489
        CMP     r3, r7                          ; if off end of CAM
Neil Turton's avatar
Neil Turton committed
490
        BHI     %FT20                           ; then don't try to use the guess
491 492 493 494
        
        ADD     r10, r12, r3, LSL #CAM_EntrySizeLog2
        LDR     lr, [r10, #CAM_LogAddr]         ; load address from guessed page
        TEQ     r4, lr                          ; compare address
Neil Turton's avatar
Neil Turton committed
495 496 497
        BEQ     %FT60                           ; if equal, then guessed page was OK
20

498 499 500 501 502 503 504 505 506 507 508
; use the page tables to perform a logical -> physical (-> page no.) conversion

        BL      logical_to_physical             ; r5 corrupt, r8,r9 = phys
        BLCC    physical_to_ppn                 ; r5,r10-r11 corrupt, r3 = page
        ; If we found a page, double-check that the logical address is a match
        ; (means we can never find the second mapping of doubly-mapped regions
        ; - is that intentional?)
        ADDCC   r10, r12, r3, LSL #CAM_EntrySizeLog2
        LDRCC   lr, [r10, #CAM_LogAddr]
        SUBCS   lr, r4, #1
        TEQ     r4, lr                          ; page found?
Neil Turton's avatar
Neil Turton committed
509
60
510
        LDREQ   lr, [r10, #CAM_PageFlags]       ; if match, then lr = PPL
Neil Turton's avatar
Neil Turton committed
511

512 513
        MOVNE   r3, #-1                         ; else unknown page number indicator
        MOVNE   lr, #3                          ; and PPL=3 (no user access)
Neil Turton's avatar
Neil Turton committed
514

515
        STMIA   r0!, {r3,r4,lr}                 ; store all 3 words
Neil Turton's avatar
Neil Turton committed
516 517 518 519 520
        B       %BT10                           ; and go back for another one

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

524 525 526 527 528
; 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
529 530 531 532
SetMemMapEntries_Code  ROUT
        Push    "r0-r6, r9, lr"
        MOV     r12, r0

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

Jeffrey Lee's avatar
Jeffrey Lee committed
536
        LDR     r9, =ZeroPage
Neil Turton's avatar
Neil Turton committed
537
        LDR     r5, [r9, #MaxCamEntry]
538 539
        LDR     r9, [r9, #CamEntriesPointer]
        ADD     r9, r9, #CAM_PageFlags
Neil Turton's avatar
Neil Turton committed
540 541 542 543 544 545 546
01
        LDR     r2, [r12], #4
        CMP     r2, r5
        BHI     %FT02                   ; finished
        LDMIA   r12!, {r3, r11}
        CMP     r3, #-1
        LDRHS   r3, =DuffEntry
547
        MOVHS   r11, #AreaFlags_Duff
548 549
        ; Ensure PMP membership flag is retained - just in case caller doesn't
        ; know what he's doing
550
        LDR     r6, =StickyPageFlags+DynAreaFlags_PMP
551
        LDR     r0, [r9, r2, LSL #CAM_EntrySizeLog2]
552 553
        AND     r0, r0, r6
        BIC     r11, r11, r6
554
        ORR     r11, r11, r0
Neil Turton's avatar
Neil Turton committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
        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
;

575 576 577

DynArea_NewAreas *      &100            ; Allocated area numbers start here
DynArea_NewAreasBase *  &04000000       ; Allocated area addresses start here
578 579
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
580

581
;
582
; Internal page flags (note - may overlap DA flags)
583 584
;
TempUncacheableShift            * 16
585
PageFlags_TempUncacheableBits   * 15 :SHL: TempUncacheableShift    ; temporary count of uncacheability, used by DMA mgr (via OS_Memory 0)
586 587
PageFlags_Required              *  1 :SHL: 21                      ; physical page asked for by handler (only set temporarily)

588
;
589
; Temporary flags only used by kernel (note - may overlap DA flags)
590
;
591 592
PageFlags_Unsafe                *  1 :SHL: 31                      ; skip cache/TLB maintenance in BangCamUpdate. flag not saved to CAM map.

593
; Mask to convert DANode_Flags to page flags (i.e. flags that are common between the two)
594 595 596 597 598
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
599

600 601 602 603 604 605 606 607 608
; 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
609

610
DynamicAreaSWI Entry
Neil Turton's avatar
Neil Turton committed
611 612 613 614 615 616 617 618 619 620 621 622 623 624
        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
625 626
 [ ShrinkableDAs
        B       DynArea_ReturnFree
627 628
 |
        B       DynArea_Unknown
Neil Turton's avatar
Neil Turton committed
629
 ]
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
 [ 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
 ]
646 647 648 649 650 651 652 653 654 655
        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
656 657 658 659 660
        B       DynArea_PMP_PhysOp
        B       DynArea_PMP_LogOp
        B       DynArea_PMP_Resize
        B       DynArea_PMP_GetInfo
        B       DynArea_PMP_GetPages
661
        B       DynArea_AplSpaceLimit
662 663 664 665 666 667 668 669 670 671
 [ ShrinkableDAs
        B       DynArea_ReturnFreePages
 |
        B       DynArea_Unknown
 ]
 [ DynArea_QuickHandles
        B       DynArea_EnumerateInfo2
 |
        B       DynArea_Unknown
 ]
672

673
;
Neil Turton's avatar
Neil Turton committed
674
; unknown OS_DynamicArea reason code
675
;
Neil Turton's avatar
Neil Turton committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
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
705 706 707 708 709
;               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
710 711
;               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!)
712 713 714
;               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
715
;
716
;       r5 = maximum size of logical area, or -1 for total RAM size
Neil Turton's avatar
Neil Turton committed
717 718 719
;       r6 -> area handler routine
;       r7 = workspace pointer for area handler (-1 => use base address)
;       r8 -> area description string (null terminated) (gets copied)
720
;       r9 = initial physical area size limit, in pages (physical memory pools), otherwise ignored
Neil Turton's avatar
Neil Turton committed
721 722 723 724 725 726 727 728
;
; 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
;

729
DynArea_Create Entry "r2,r6-r8"
Neil Turton's avatar
Neil Turton committed
730 731 732
        CMP     r1, #-1         ; do we have to allocate a new area number
        BEQ     %FT10

733 734 735 736 737 738 739 740 741 742 743
  [ 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
744
        BL      CheckAreaNumber ; see if area number is unique
745
  ]
Neil Turton's avatar
Neil Turton committed
746 747
        BCC     %FT20           ; didn't find it, so OK

748
08
Neil Turton's avatar
Neil Turton committed
749 750 751 752 753 754 755 756 757 758 759
        ADR     r0, ErrorBlock_AreaAlreadyExists
DynArea_ErrorTranslateAndExit
        PullEnv
        B       DynArea_TranslateAndReturnError

        MakeErrorBlock  AreaAlreadyExists
        MakeErrorBlock  AreaNotOnPageBdy
        MakeErrorBlock  OverlappingAreas
        MakeErrorBlock  CantAllocateArea
        MakeErrorBlock  CantAllocateLevel2
        MakeErrorBlock  UnknownAreaHandler
760 761
        MakeErrorBlock  BadDynamicAreaOptions
        MakeErrorBlock  BadPageNumber
Neil Turton's avatar
Neil Turton committed
762 763 764

; we have to allocate an area number for him

765 766
  [ DynArea_QuickHandles
10
Jeffrey Lee's avatar
Jeffrey Lee committed
767
        LDR     r11, =ZeroPage
768 769 770 771 772 773 774 775 776 777 778 779 780
        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
781 782 783 784 785 786
10
        MOV     r1, #DynArea_NewAreas
12
        BL      CheckAreaNumber
        ADDCS   r1, r1, #1      ; that area number already exists, so increment
        BCS     %BT12           ; and try again
787 788
  ]

Neil Turton's avatar
Neil Turton committed
789 790
20

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
; 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

813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
; 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
835 836
; now validate maximum size of area

837 838 839 840
  [ DynArea_QuickHandles
    ;
    ; apply clamps on max size, as set by last call to OS_DynamicArea 8
    ;
Jeffrey Lee's avatar
Jeffrey Lee committed
841
        LDR     r11, =ZeroPage
842 843 844 845 846 847 848 849 850 851
        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
852
        LDR     r10, =ZeroPage
853 854 855 856 857 858 859 860 861 862 863 864 865 866
        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
867
        LDR     r10, =ZeroPage
Neil Turton's avatar
Neil Turton committed
868 869 870 871 872
        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)

873
DAC_roundup
Neil Turton's avatar
Neil Turton committed
874 875 876 877 878
        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
879 880 881
        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
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904

        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

905
41
Neil Turton's avatar
Neil Turton committed
906
        Push    "r0,r1,r3"
907 908 909 910 911 912
  [ 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
913
        MOV     r3, #DANode_NodeSize
914
  ]
Neil Turton's avatar
Neil Turton committed
915 916 917 918 919 920 921 922 923 924 925 926
        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]
927 928 929 930 931 932 933 934 935 936 937
  [ 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
938
        STR     r4, [r2, #DANode_Flags]
939
  ]
Neil Turton's avatar
Neil Turton committed
940 941 942 943 944
        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
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
        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
980

981
        ; update lower limit on IO space growth, if this DA exceeds previous limit
Jeffrey Lee's avatar
Jeffrey Lee committed
982 983 984
      [ ZeroPage <> 0
        LDR     r7, =ZeroPage
      ]
985 986 987 988 989
        LDR     r6, [r7, #IOAllocLimit]
        ADD     lr, r3, r5
        CMP     lr, r6
        STRHI   lr, [r7, #IOAllocLimit]

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

992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
  [ 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
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
        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

1048 1049
 ] ;DynArea_QuickHandles

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

Jeffrey Lee's avatar
Jeffrey Lee committed
1052
        LDR     r8, =ZeroPage+DAList
Neil Turton's avatar
Neil Turton committed
1053 1054 1055
        LDR     r6, [r2, #DANode_Base]
60
        MOV     r7, r8
1056
        ASSERT  DANode_Link = 0                 ; For picking up pointer to first real node
Neil Turton's avatar
Neil Turton committed
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
        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]

1068
  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1069
        LDR     r11, =ZeroPage
1070
        LDR     r11, [r11, #DynArea_ws]
1071
        BL      AddDAToAddrLookupTable
1072 1073 1074 1075 1076 1077 1078 1079 1080
        ;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
1081 1082
; now we need to grow the area to its requested size

1083
        Push    "r0, r1, r2"
Neil Turton's avatar
Neil Turton committed
1084
        LDR     r0, [r2, #DANode_Number]
1085
        LDR     r1, [sp, #3*4]                  ; reload requested size off stack
1086 1087
        CMP     r1, #0                          ; skip redundant SWI
        SWINE   XOS_ChangeDynamicArea           ; deal with error - r0,r1,r2 still stacked
Neil Turton's avatar
Neil Turton committed
1088
        BVS     %FT90
1089 1090 1091 1092 1093 1094 1095
        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
1096
        LDR     r11, =ZeroPage
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
        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
1137
        LDR     r11, =ZeroPage
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 1171 1172 1173 1174
        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
1175 1176 1177

; Now issue service to tell TaskManager about it

1178 1179
        Push    "r0, r1, r2"
        MOV     r2, r1                          ; r2 = area number
Neil Turton's avatar
Neil Turton committed
1180 1181
        MOV     r1, #Service_DynamicAreaCreate
        BL      Issue_Service
1182
        Pull    "r0, r1, r2"
Neil Turton's avatar
Neil Turton committed
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194

        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
1195 1196
  [ :LNOT: DynArea_QuickHandles
        LDR     r2, [r2, #DANode_Title]
Neil Turton's avatar
Neil Turton committed
1197
        BL      FreeSysHeapNode                 ; free title string node
1198 1199
  ]
        Pull    "r0, r1, r2"                    ; pull stacked registers, and drop thru to...
Neil Turton's avatar
Neil Turton committed
1200

1201
  [ :LNOT: DynArea_QuickHandles
Neil Turton's avatar
Neil Turton committed
1202 1203 1204 1205 1206 1207 1208
; 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
1209 1210
  ]

Neil Turton's avatar
Neil Turton committed
1211 1212 1213
        Push    "r0, r1"
        BL      FreeSysHeapNode
        Pull    "r0, r1"
1214
  [ DynArea_QuickHandles
Jeffrey Lee's avatar
Jeffrey Lee committed
1215
        LDR     r11, =ZeroPage
1216 1217 1218 1219
        LDR     r11, [r11, #DynArea_ws]
        MOV     lr, #-1
        STR     lr, DynArea_CreatingHandle
  ]
Neil Turton's avatar
Neil Turton committed
1220 1221 1222
        PullEnv
        B       DynArea_ReturnError

Jeffrey Lee's avatar
Jeffrey Lee committed
1223 1224
        LTORG

1225 1226 1227 1228
; Add a dynamic area to the quick address lookup table
; In:
;  R2 = DANode ptr
;  R11 = DynArea_ws
1229
AddDAToAddrLookupTable ROUT
1230
        Entry   "r0-r1,r3,r6"
1231
        LDR     r3, [r2, #DANode_MaxSize]
1232
        ADRL    r0, DynArea_AddrLookup
1233
        TEQ     r3, #0
1234
        LDR     r1, [r2, #DANode_Flags]
1235
        BEQ     %FT90
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
        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
1258
90
1259 1260
        EXIT

Neil Turton's avatar
Neil Turton committed
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
;**************************************************************************
;
;       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
;

1274
DynArea_Remove Entry
1275 1276

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

1280
  [ DA_Batman
1281 1282
        LDR     lr,[r10,#DANode_Flags]
        TST     lr,#DynAreaFlags_SparseMap
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
        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
1294 1295 1296 1297 1298 1299
        TST     lr, #DynAreaFlags_PMP
        BEQ     DAR_notPMP
        ; Unmap all pages from logical space
        ; This is a bit of a simplistic approach - request for everything to
        ; be unmapped and leave it to PMP_LogOp to detect which pages are and
        ; aren't there
1300
        Push    "r2-r8"
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
        LDR     r6, [r10, #DANode_Base]
        MOV     r3, #0
        LDR     r4, [r10, #DANode_SparseHWM] ; Assume HWM valid
        MOV     r5, #-1
        SUB     r4, r4, r6
        MOV     r6, #0
        MOV     r4, r4, LSR #12
        MOV     r8, sp
DAR_PMP_logloop
        SUBS    r4, r4, #1
        BLT     DAR_PMP_logunmap
        STMDB   sp!, {r4-r6}
        ADD     r3, r3, #1
        CMP     r3, #85 ; Limit to 1K stack
        BLT     DAR_PMP_logloop
DAR_PMP_logunmap
        MOV     r0, #DAReason_PMP_LogOp
        MOV     r2, sp
        SWI     XOS_DynamicArea
        MOV     sp, r8