HAL 118 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
; Copyright 2000 Pace Micro Technology plc
;
; 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.
;
15
        GBLL    MinorL2PThack
Kevin Bracey's avatar
Kevin Bracey committed
16
MinorL2PThack SETL {TRUE}
17 18 19 20 21 22 23

; Fixed page allocation is as follows

                        ^       0
DRAMOffset_FirstFixed   #       0
DRAMOffset_ScratchSpace #       16*1024
DRAMOffset_PageZero     #       16*1024
Jeffrey Lee's avatar
Jeffrey Lee committed
24
DRAMOffset_PageTables   #       0               ; Base of the page tables used during init; just a useful symbol we can use for relative offsets
25

Jeffrey Lee's avatar
Jeffrey Lee committed
26
 [ LongDesc
27
                        ^       DRAMOffset_PageTables
Jeffrey Lee's avatar
Jeffrey Lee committed
28 29
DRAMOffset_LL2PT        #       16*1024         ; Each page needs to be page-aligned
DRAMOffset_LL1PT        #       4096            ; Only needs to be 32 byte aligned
30 31 32 33 34
DRAMOffset_LastFixed_LongDesc # 0
 ]

 [ ShortDesc
                        ^       DRAMOffset_PageTables
35
DRAMOffset_L1PT         #       16*1024         ; L1PT must be 16K-aligned
36
DRAMOffset_LastFixed_ShortDesc # 0
Jeffrey Lee's avatar
Jeffrey Lee committed
37
 ]
38

39 40
;        IMPORT  Init_ARMarch
;        IMPORT  ARM_Analyse
41

42
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
43 44 45 46
mmuc_init_new
        ; MMUC initialisation flags for ARMv6/ARMv7
        ; This tries to leave the reserved/unpredictable bits untouched, while initialising everything else to what we want
                ; ARMv7MP (probably) wants SW. ARMv6 wants U+XP (which should both be fixed at 1 on ARMv7)
Ben Avison's avatar
Ben Avison committed
47
        DCD     MMUC_BEN+MMUC_SW+MMUC_U+MMUC_XP
Jeffrey Lee's avatar
Jeffrey Lee committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
                ; M+C+W+Z+I+L2 clear to keep MMU/caches off.
                ; A to keep alignment exceptions off (for now at least)
                ; B+EE clear for little-endian
                ; S+R+RR clear to match mmuc_init_old
                ; V+VE clear to keep processor vectors at &0
                ; FI clear to disable fast FIQs (interruptible LDM/STM)
                ; TRE+AFE clear for our VMSAv6 implementation
                ; TE clear for processor vectors to run in ARM mode
        DCD     MMUC_M+MMUC_A+MMUC_C+MMUC_W+MMUC_B+MMUC_S+MMUC_R+MMUC_Z+MMUC_I+MMUC_V+MMUC_RR+MMUC_FI+MMUC_VE+MMUC_EE+MMUC_L2+MMUC_TRE+MMUC_AFE+MMUC_TE
mmuc_init_old
        ; MMUC initialisation flags for ARMv5 and below, as per ARM600 MMU code
                ; Late abort (ARM6 only), 32-bit Data and Program space. No Write buffer (ARM920T
                ; spec says W bit should be set, but I reckon they're bluffing).
                ;
                ; The F bit's tricky. (1 => CPCLK=FCLK, 0=>CPCLK=FCLK/2). The only chip using it was the
                ; ARM700, it never really reached the customer, and it's always been programmed with
                ; CPCLK=FCLK. Therefore we'll keep it that way, and ignore the layering violation.
        DCD     MMUC_F+MMUC_L+MMUC_D+MMUC_P
                ; All of these bits should be off already, but just in case...
        DCD     MMUC_B+MMUC_W+MMUC_C+MMUC_A+MMUC_M+MMUC_RR+MMUC_V+MMUC_I+MMUC_Z+MMUC_R+MMUC_S
68
 ]
69 70 71 72 73 74 75

; void RISCOS_InitARM(unsigned int flags)
;
RISCOS_InitARM
        MOV     a4, lr
        ; Check if we're architecture 3. If so, don't read the control register.
        BL      Init_ARMarch
76 77
        MOVEQ   a3, #0
        ARM_read_control a3, NE
78
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
79 80 81 82 83
        CMP     a1, #ARMv6
        CMPNE   a1, #ARMvF
        ADREQ   a2, mmuc_init_new
        ADRNE   a2, mmuc_init_old
        LDMIA   a2, {a2, lr}
84
        ORR     a3, a3, a2
Jeffrey Lee's avatar
Jeffrey Lee committed
85
        BIC     a3, a3, lr
86
 |
87 88 89 90 91 92
        ; Late abort (ARM6 only), 32-bit Data and Program space. No Write buffer (ARM920T
        ; spec says W bit should be set, but I reckon they're bluffing).
        ;
        ; The F bit's tricky. (1 => CPCLK=FCLK, 0=>CPCLK=FCLK/2). The only chip using it was the
        ; ARM700, it never really reached the customer, and it's always been programmed with
        ; CPCLK=FCLK. Therefore we'll keep it that way, and ignore the layering violation.
93
        ORR     a3, a3, #MMUC_F+MMUC_L+MMUC_D+MMUC_P
94
        ; All of these bits should be off already, but just in case...
95 96
        BIC     a3, a3, #MMUC_B+MMUC_W+MMUC_C+MMUC_A+MMUC_M
        BIC     a3, a3, #MMUC_RR+MMUC_V+MMUC_I+MMUC_Z+MMUC_R+MMUC_S
97
 ]
98 99

        ; Off we go.
100
        ARM_write_control a3
101
        MOV     a2, #0
102
 [ MEMM_Type = "VMSAv6"
103
        myISB   ,a2,,y ; Ensure the update went through
104
 ]
105 106

        ; In case it wasn't a hard reset
107
 [ MEMM_Type = "VMSAv6"
108 109
        CMP     a1, #ARMvF
        ; Assume that all ARMvF ARMs have multi-level caches and thus no single MCR op for invalidating all the caches
Ben Avison's avatar
Ben Avison committed
110 111
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
112
        MCRNE   ARM_config_cp,0,a2,ARMv4_cache_reg,C7           ; invalidate I+D caches
Ben Avison's avatar
Ben Avison committed
113
01
114
 ]
115
        CMP     a1, #ARMv3
Ben Avison's avatar
Ben Avison committed
116
        BNE     %FT01
117
        MCREQ   ARM_config_cp,0,a2,ARMv3_TLBflush_reg,C0        ; flush TLBs
Ben Avison's avatar
Ben Avison committed
118 119 120
        B       %FT02
01      MCRNE   ARM_config_cp,0,a2,ARMv4_TLB_reg,C7             ; flush TLBs
02
121
 [ MEMM_Type = "VMSAv6"
122 123
        myDSB   ,a2,,y
        myISB   ,a2,,y
124
 ]
125

126 127
        ; We assume that ARMs with an I cache can have it enabled while the MMU is off.
        [ :LNOT:CacheOff
128 129
        ORRNE   a3, a3, #MMUC_I
        ARM_write_control a3, NE                                ; whoosh
130
 [ MEMM_Type = "VMSAv6"
131
        myISB   ,a2,,y ; Ensure the update went through
132
 ]
133 134
        ]

135 136
        ; Check if we are in a 26-bit mode.
        MRS     a2, CPSR
137 138
        ; Keep a soft copy of the CR in a banked register (R13_und)
        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
139
        MOV     sp, a3
140 141 142 143 144 145 146 147
        ; Switch into SVC32 mode (we may have been in SVC26 before).
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode

        ; If we were in a 26-bit mode, the lr value given to us would have had PSR flags in.
        TST     a2, #2_11100
        MOVNE   pc, a4
        BICEQ   pc, a4, #ARM_CC_Mask

148
; void *RISCOS_AddRAM(unsigned int flags, uintptr_t start, uintptr_t end, uintptr_t sigbits, void *ref)
149 150
;   Entry:
;     flags   bit 0: video memory (currently only one block permitted)
Kevin Bracey's avatar
Kevin Bracey committed
151
;             bit 1: video memory is not suitable for general use
152
;             bit 2: memory can't be used for DMA (sound, video, or other)
153
;             bits 8-11: speed indicator (arbitrary, higher => faster)
154
;             bit 12: start, end, sigbits are shifted right 12 bits (for supporting large physical addresses)
155 156 157 158 159
;             other bits reserved (SBZ)
;     start   = start address of RAM (inclusive) (no alignment requirements)
;     end     = end address of RAM (exclusive) (no alignment requirements, but must be >= start)
;     sigbits = significant address bit mask (1 => this bit of addr decoded, 0 => this bit ignored)
;     ref     = reference handle (NULL for first call)
160 161 162 163
;
; The first registered block must be in the low 4GB, and blocks must not cross
; 4GB thresholds.
; The (unshifted) sigbits is assumed to be the same across all calls.
164 165

; A table is built up at the head of the first block of memory.
166 167 168 169
; The table consists of (addr, len, flags) pairs, terminated by a count of
; those pairs; ref points to that counter.
; The table stores addresses are in terms of 4K pages, allowing us to
; theoretically support a 44 bit physical space.
170
; Twelve bits of flags are stored at the bottom of the length word.
171 172
; The remaining 20 length bits are the length of the block in 4K pages, minus
; one (so a full 4GB region will have length &FFFFF)
173 174 175

        ROUT
RISCOS_AddRAM
176
        Entry   "v1-v4"
177
        LDR     v4, [sp, #5*4]          ; Get ref
178 179 180 181 182

        ; Round to pages. If we were extra sneaky we could not do this and chuck out incomplete
        ; pages after concatanation, but it would be a weird HAL that gave us pages split across
        ; calls.
        ;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
        TST     a1, #OSAddRAM_LargeAddresses
        ADDEQ   a2, a2, #4096           ; round start address up
        SUBEQ   a2, a2, #1
        MOVEQ   a2, a2, LSR #12
        MOVEQ   a3, a3, LSR #12         ; round end address down
        MOVEQ   a4, a4, LSR #12
        ORREQ   a4, a4, #&FF000000
        ORREQ   a4, a4, #&00F00000
        BIC     a1, a1, #OSAddRAM_LargeAddresses ; Flag no longer relevant

      [ :LNOT: LongDesc
        ; Ignore any RAM above the 32bit barrier if we've been built with
        ; long-descriptor support disabled (HAL may not know our build settings)
        CMP     a2, #1:SHL:20
        BHS     %FT90
      ]
199 200 201 202 203 204 205

        CMP     a3, a2
        BLS     %FT90                   ; check we aren't now null

        CMP     v4, #0
        BEQ     %FT20

206

207 208 209
        ; We are not dealing with the first block since v4 != 0.  Make an attempt to merge this block
        ; with the previous block.
        LDMDB   v4, {v1, v2}            ; Get details of the previous block
210 211 212
        EOR     ip, v1, a2
        CMP     ip, #1:SHL:20
        BHS     %FT20                   ; Don't merge if they're in different 4GB blocks
213
        MOV     v3, v2, LSL #20         ; Isolate flags
214
        MOV     v2, v2, LSR #12         ; And get length in pages
215
        ADD     v2, v1, v2              ; Get the end address
216
        ADD     v2, v2, #1
217 218 219 220 221 222 223 224 225 226
        EOR     v2, v2, a2              ; Compare with the current block start address...
        TST     v2, a4                  ; ... but only check the decoded bits.
        EOR     v2, v2, a2              ; Restore the previous block end address.
        TEQEQ   v3, a1, LSL #20         ; And are the page flags the same?
        BNE     %FT10                   ; We can't merge it after the previous block

        ; v1 = previous start
        ; v2 = previous end
        ; The block is just after the previous block.  That means the start address is unchanged, but
        ; the length is increased.
227
        LDR     v2, [v4, #-4]           ; Reload length+flags
228 229
        SUB     a3, a3, a2              ; Find the length of the new block.
        ; a3 = length of block
230
        ADD     v2, v2, a3, LSL #12     ; Add it to the previous length.
231 232
        STR     v2, [v4, #-4]           ; Update the block size in memory.
        MOV     a1,v4
233
        EXIT
234 235 236 237

        ; The block is not just after the previous block, but it may be just before.  This may be the
        ; case if we are softloaded.
10      SUB     v1, v1, #1              ; Compare the address before the previous block start ...
238
        SUB     a3, a3, #1              ; ... with the address of the last page in this block ...
239 240 241 242 243 244 245
        EOR     v1, v1, a3
        TST     v1, a4                  ; ... but check only the decoded bits.
        ADD     a3, a3, #1              ; Restore the end address.
        TEQEQ   v3, a1, LSL #20         ; And are the page flags the same?
        BNE     %FT20                   ; Skip if we cannot merge the block.

        ; The block is just before the previous block.  The start address and length both change.
246
        LDMDB   v4, {v1, v2}            ; Get the previous block again
247 248
        SUB     a3, a3, a2              ; Calculate the current block size.
        SUB     v1, v1, a3              ; Subtract from the previous block start address.
249
        ADD     v2, v2, a3, LSL #12     ; Calculate the new length+flags
250 251
        STMDB   v4, {v1, v2}            ; Update the block info in memory.
        MOV     a1,v4
252
        EXIT
253 254 255 256

        ; We now have a region which does not merge with a previous region.  We move it up to the
        ; highest address we can in the hope that this block will merge with the next block.
20      SUB     a3, a3, a2              ; Calculate the block size
257 258 259
        SUB     a3, a3, #1
        ORR     a3, a3, a1, LSL #20     ; Put the flags in
        MOV     a3, a3, ROR #20         ; And rotate so they're at the bottom
260 261 262 263
        MVN     v1, a4                  ; Get the non-decoded address lines.
        ORR     a2, v1, a2              ; Set the non-decoded address bit in the start address.

30      CMP     v4, #0                  ; If the workspace has not been allocated...
264
        MOVEQ   v4, a2, LSL #12         ; ... use this block.
265 266 267 268 269 270 271 272 273
        MOVEQ   v1, #0                  ; Initialise the counter.

        ; The block/fragment to be added is between a2 and a2+a3.
        LDRNE   v1, [v4]                ; Get the old counter if there was one.
        STMIA   v4!, {a2, a3}           ; Store address and size.
        ADD     v1, v1, #1              ; Increment the counter.
        STR     v1, [v4]                ; Store the counter.

90      MOV     a1,v4
274
        EXIT                            ; We've done with this block now.
275 276 277



Kevin Bracey's avatar
Kevin Bracey committed
278 279 280 281 282 283 284 285 286 287 288
; Subtractv1v2fromRAMtable
;
; On entry: v1 = base of memory area
;           v2 = size of memory area
;           a4 = RAM table handle (ie pointer to terminator word containing number of entries)
;
; On exit:  a1-a3 preserved
;           a4 and RAM table updated
;           other registers corrupted
Subtractv1v2fromRAMtable
        ADD     v2, v1, v2              ; v2 = end address
289
        MOV     v1, v1, LSR #12         ; round base down
Kevin Bracey's avatar
Kevin Bracey committed
290 291
        ADD     v2, v2, #4096
        SUB     v2, v2, #1
292
        MOV     v2, v2, LSR #12         ; round end up
Kevin Bracey's avatar
Kevin Bracey committed
293 294 295 296 297 298

        LDR     v5, [a4]
        SUB     v8, a4, v5, LSL #3
10      TEQ     v8, a4
        MOVEQ   pc, lr
        LDMIA   v8!, {v3, v4}
299 300
        ADD     v6, v3, v4, LSR #12
        ADD     v6, v6, #1              ; v6 = end of RAM block
Kevin Bracey's avatar
Kevin Bracey committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314
        CMP     v2, v3                  ; if our end <= RAM block start
        CMPHI   v6, v1                  ; or RAM block end <= our start
        BLS     %BT10                   ; then no intersection

        MOV     v4, v4, LSL #20         ; extract flags

        CMP     v1, v3
        BHI     not_bottom

        ; our area is at the bottom
        CMP     v2, v6
        BHS     remove_block

        SUB     v6, v6, v2              ; v6 = new size
315 316
        SUB     v6, v6, #1
        MOV     v6, v6, LSL #12
Kevin Bracey's avatar
Kevin Bracey committed
317 318 319 320 321 322
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v2, v6}            ; store new base (= our end) and size
        B       %BT10

        ; we've completely covered a block. Remove it.
remove_block
323 324 325 326 327 328
        MOV     v7, v8
20      TEQ     v7, a4                  ; shuffle down subsequent blocks in table
        LDMNEIA v7, {v3, v4}
        STMNEDB v7, {v3, v4}
        ADDNE   v7, v7, #8
        BNE     %BT20
Kevin Bracey's avatar
Kevin Bracey committed
329 330 331 332 333 334 335 336 337 338 339 340 341
        SUB     v5, v5, #1
        SUB     a4, a4, #8
        STR     v5, [a4]
        SUB     v8, v8, #8
        B       %BT10

        ; our area is not at the bottom.
not_bottom
        CMP     v2, v6
        BLO     split_block

        ; our area is at the top
        SUB     v6, v1, v3              ; v6 = new size
342 343
        SUB     v6, v6, #1
        MOV     v6, v6, LSL #12
Kevin Bracey's avatar
Kevin Bracey committed
344 345 346 347 348
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v6}            ; store original base and new size
        B       %BT10

split_block
349 350
        MOV     v7, a4
30      TEQ     v7, v8                  ; shuffle up subsequent blocks in table
Robert Sprowson's avatar
Robert Sprowson committed
351
        LDMDB   v7, {v3, v4}
352 353
        STMNEIA v7, {v3, v4}
        SUBNE   v7, v7, #8
Kevin Bracey's avatar
Kevin Bracey committed
354 355 356 357 358
        BNE     %BT30
        ADD     v5, v5, #1
        ADD     a4, a4, #8
        STR     v5, [a4]

Robert Sprowson's avatar
Robert Sprowson committed
359 360
        MOV     v4, v4, LSL #20         ; (re)extract flags

Kevin Bracey's avatar
Kevin Bracey committed
361 362
        SUB     v7, v1, v3              ; v7 = size of first half
        SUB     v6, v6, v2              ; v6 = size of second half
363 364 365 366
        SUB     v7, v7, #1
        SUB     v6, v6, #1
        MOV     v7, v7, LSL #12
        MOV     v6, v6, LSL #12
Kevin Bracey's avatar
Kevin Bracey committed
367 368 369 370 371 372
        ORR     v7, v7, v4, LSR #20
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v7}
        STMIA   v8!, {v2, v6}
        B       %BT10

373 374 375 376 377 378 379 380 381 382 383 384 385

;void RISCOS_Start(unsigned int flags, int *riscos_header, int *hal_header, void *ref)
;

; We don't return, so no need to obey ATPCS, except for parameter passing.
; register usage:   v4 = location of VRAM
;                   v6 = amount of VRAM

        ROUT
RISCOS_Start
        TEQ     a4, #0
01      BEQ     %BT01                           ; Stop here if no RAM

Kevin Bracey's avatar
Kevin Bracey committed
386 387 388 389 390 391 392 393 394
        ; subtract the HAL and OS from the list of RAM areas
        MOV     v1, a2
        LDR     v2, [a2, #OSHdr_ImageSize]
        BL      Subtractv1v2fromRAMtable
        LDR     v1, [a3, #HALDesc_Start]
        ADD     v1, a3, v1
        LDR     v2, [a3, #HALDesc_Size]
        BL      Subtractv1v2fromRAMtable

395 396 397
        LDR     v5, [a4]                        ; v5 = the number of RAM blocks
        SUB     v8, a4, v5, LSL #3              ; Jump back to the start of the list.

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
 [ LongDesc :LAND: ShortDesc
        ; Check and see if there's any RAM above the 4GB limit
        MOV     v1, v8
02
        LDR     v2, [v1], #8
        CMP     v2, #1:SHL:20
        BHS     RISCOS_Start_LongDesc
        CMP     v1, a4
        BNE     %BT02
        B       RISCOS_Start_ShortDesc
 ]

        ; MMU initialisation is tricky, so just duplicate all of this code
        ; if we need to support multiple page table formats
        GBLA    ptcounter
ptcounter SETA    0
        WHILE   ptcounter < 2
      [ ptcounter = 0 :LAND: ShortDesc
pt      SETS    "ShortDesc"
      ELIF ptcounter = 1 :LAND: LongDesc
pt      SETS    "LongDesc"
      |
pt      SETS    ""
      ]
      [ "$pt" <> ""
RISCOS_Start_$pt
        ROUT

426 427
        ; Search for some VRAM
05      LDMIA   v8!, {v1, v2}                   ; Get a block from the list. (v1,v2)=(addr,size+flags)
428
        TST     v2, #OSAddRAM_IsVRAM            ; Is it VRAM?
429 430 431 432
        BNE     %FT20                           ; If so, deal with it below
        TEQ     v8, a4                          ; Carry on until end of list or we find some.
        BNE     %BT05

433
        ; Extract some pseudo-VRAM from first DMA-capable RAM block
434
        SUB     v8, a4, v5, LSL #3              ; Rewind again.
435 436 437 438
06      LDMIA   v8!, {v1, v2}
        TEQ     v8, a4                          ; End of list?
        TSTNE   v2, #OSAddRAM_NoDMA             ; DMA capable?
        BNE     %BT06
439
        MOV     v2, v2, LSR #12                 ; Remove flags
440
        ADD     v2, v2, #1
441 442 443 444 445 446 447 448 449 450 451 452 453
        ; Is this the only DMA-capable block?
        MOV     v4, v8
        MOV     v6, #OSAddRAM_NoDMA
07      TEQ     v4, a4
        BEQ     %FT08
        LDR     v6, [v4, #4]
        ADD     v4, v4, #8
        TST     v6, #OSAddRAM_NoDMA
        BNE     %BT07
08
        ; v6 has NoDMA set if v8 was the only block
        TST     v6, #OSAddRAM_NoDMA
        MOV     v4, v1                          ; Allocate block as video memory
454
        MOV     v6, v2
455
        BEQ     %FT09
456
        SUBS    v6, v6, #(16*1024*1024):SHR:12  ; Leave 16M if it was the only DMA-capable block
457
        MOVLS   v6, v2, LSR #1                  ; If that overflowed, take half the bank.
458
09
459 460
        CMP     v6, #(32*1024*1024):SHR:12
        MOVHS   v6, #(32*1024*1024):SHR:12      ; Limit allocation to 32M (arbitrary)
461 462 463

        ADD     v1, v1, v6                      ; Adjust the RAM block base...
        SUBS    v2, v2, v6                      ; ... and the size
464 465
        LDREQ   v6, [v8, #-4]
        BEQ     %FT21                           ; pack array tighter if this block is all gone
466 467
        STR     v1, [v8, #-8]                   ; update base
        LDR     v1, [v8, #-4]
468 469 470 471 472 473
        MOV     v1, v1, LSL #20                 ; original flags
        ORR     v6, v6, v1                      ; merged into VRAM size
        ORR     v1, v1, v2                      ; and into new size
        MOV     v1, v1, ROR #20
        MOV     v6, v6, ROR #20
        SUB     v1, v1, #4096
474
        STR     v1, [v8, #-4]                   ; update size
475 476 477
        B       %FT30

        ; Note real VRAM parameters
478 479 480
20      MOV     v6, v2                          ; Remember the size+flags and
        MOV     v4, v1                          ; address of the VRAM
21      ADD     v6, v6, #4096                   ; Assume <4GB of VRAM!
481 482 483 484 485 486 487 488
22      TEQ     v8, a4                          ; if not at the end of the array
        LDMNEIA v8, {v1, v2}                    ; pack the array tighter
        STMNEDB v8, {v1, v2}
        ADDNE   v8, v8, #8
        BNE     %BT22
25      SUB     v5, v5, #1                      ; decrease the counter
        STR     v5, [a4, #-8]!                  ; and move the end marker down

489
30      SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
490

491
        ; Scan forwards to find the fastest block of non-DMAable memory which is at least DRAMOffset_LastFixed size, at least 16KB aligned, and located in the first 4GB
492 493 494
        LDMIA   v8!, {v1, v2}
31
        TEQ     v8, a4
495
        MOVEQ   v1, v1, LSL #12
496 497
        BEQ     %FT32
        LDMIA   v8!, {v7, ip}
498 499 500
        MOV     sp, v7, ROR #2                  ; Bottom two bits (for 16KB alignment) rotated high
        CMP     sp, #1:SHL:18                   ; Ignore if not aligned, or base address >= 4GB
        BHS     %BT31
501
        CMP     ip, #DRAMOffset_LastFixed_$pt-4096
502 503 504 505 506 507 508 509 510 511
        ANDHS   sp, ip, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ANDHS   lr, v2, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ASSERT  OSAddRAM_Speed = 1:SHL:8
        ASSERT  OSAddRAM_NoDMA < OSAddRAM_Speed
        MOVHS   sp, sp, ROR #8                  ; Give NoDMA flag priority over speed when sorting
        CMPHS   sp, lr, ROR #8
        MOVHI   v1, v7
        MOVHI   v2, ip
        B       %BT31
32
512

513 514 515 516 517 518 519 520 521 522 523 524
        ; Fill in the Kernel's permanent memory table, sorting by address, speed and DMA ability.
        ; * Address: All memory that falls in the low 4GB of the physical map
        ;   comes first. This makes it easier for our initial memory allocation
        ;   (no danger of allocating pages which can't be accessed with the MMU
        ;   off), but may also help with wider software compatibility (all low-
        ;   RAM pages occupy the lowest physical page numbers)
        ; * Non-DMAable RAM is preferred over DMAable, as the kernel requires
        ;   very little DMAable RAM, and we don't want to permanently claim
        ;   DMAable RAM if we're not actually using it for DMA (in case machine
        ;   only has a tiny amount available)
        ; * Speed: Fastest RAM is listed first, so that we'll prefer to allocate
        ;   it for these important kernel/system areas
525
        ADD     ip, v1, #DRAMOffset_PageZero
526
        ASSERT  DRAMOffset_PageZero > 0         ; If the workspace block is the block containing the OS_AddRAM list, make sure the two don't overlap otherwise we might corrupt it while we copy it
527 528 529 530 531

        ADD     sp, v1, #DRAMOffset_ScratchSpace + ScratchSpaceSize

        Push    "a1,a2,a3"                      ; Remember our arguments

532
        SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
533 534 535
        CMP     v5, #DRAMPhysTableSize          ; Don't overflow our table
        ADDHI   a4, v8, #DRAMPhysTableSize*8 - 8

536 537 538
        ; First put the VRAM information in to free up some regs
        ADD     v7, ip, #VideoPhysAddr
        STMIA   v7!, {v4, v6}
539

540 541
        ; Now fill in the rest
        ASSERT  DRAMPhysAddrA = VideoPhysAddr+8
542
        MOV     v1, v1, LSR #12
543 544
        ADDS    v2, v2, #4096                   ; Store true length
        ADDCS   v2, v2, #1:SHL:31               ; If it overflowed, must have been 4GB block, so clamp at 2GB (loop below will add the second 2GB)
545 546 547 548 549
        STMIA   v7!, {v1, v2}                   ; workspace block must be first
33
        TEQ     v8, a4
        BEQ     %FT39
        LDMIA   v8!, {v1, v2}
550 551 552
        ADDS    v2, v2, #4096                   ; Get true length
        ADDCS   v2, v2, #1:SHL:31               ; If it overflowed, must have been 4GB block, so split into two 2GB blocks
        SUBCS   v2, v2, #4096
553
        ADDCS   v1, v1, #1:SHL:(31-12)
554 555
        STMCSDB v8!, {v1, v2}
        ADDCS   v2, v2, #4096
556
        SUBCS   v1, v1, #1:SHL:(31-12)
557 558 559 560
        ADD     a1, ip, #DRAMPhysAddrA
        LDMIA   a1!, {a2, a3}
        TEQ     v1, a2
        BEQ     %BT33                           ; don't duplicate the initial block
561 562
        ; Perform insertion sort
        ; a1-a3, v3-v6, ip, lr free
563 564 565 566 567
        AND     v3, v2, #&F*OSAddRAM_Speed
        CMP     v1, #1:SHL:20
        ORRLO   v3, v3, #1:SHL:31               ; Low RAM takes priority
        TST     v2, #OSAddRAM_NoDMA
        ORRNE   v3, v3, #1:SHL:30               ; Followed by non-DMA
568
34
569 570 571 572 573 574
        AND     v4, a3, #&F*OSAddRAM_Speed
        CMP     a2, #1:SHL:20
        ORRLO   v4, v4, #1:SHL:31               ; Low RAM takes priority
        TST     a3, #OSAddRAM_NoDMA
        ORRNE   v4, v4, #1:SHL:30               ; Followed by non-DMA
        CMP     v3, v4                          ; Compare priority value
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
        BHI     %FT35
        TEQ     a1, v7
        LDMNEIA a1!, {a2, a3}
        BNE     %BT34
        ADD     a1, a1, #8
35
        ADD     v7, v7, #8
        ; Insert at a1-8, overwriting {a2, a3}
36
        STMDB   a1, {v1, v2}                   ; store new entry
        TEQ     a1, v7
        MOVNE   v1, a2                         ; if not at end, shuffle
        MOVNE   v2, a3                         ; overwritten entry down one,
        LDMNEIA a1!, {a2, a3}                  ; load next to be overwritten,
        BNE     %BT36                          ; and loop
        B       %BT33

39
593 594
        ; Now we have to work out the total RAM size
        MOV     a2, #0
595 596
        ADD     v6, ip, #PhysRamTable
        MOV     a3, v6
597 598
40
        LDMIA   v6!, {v1, v2}                   ; get address, size
599
        ADD     a2, a2, v2, LSR #12             ; add on size
600 601 602
        TEQ     v6, v7
        BNE     %BT40

603 604 605 606
        ; Work out how much DMAable RAM the HAL/kernel needs
        LDR     a1, [sp, #8]
        LDR     a1, [a1, #HALDesc_Flags]
        TST     a1, #HALFlag_NCNBWorkspace              ; do they want uncacheable workspace?
607 608
        LDRNE   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + 32*1024 + DRAMOffset_LastFixed_$pt
        LDREQ   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + DRAMOffset_LastFixed_$pt
609 610 611 612 613 614 615 616 617 618 619 620 621 622
        ; Scan PhysRamTable for a DMAable block of at least this size, extract it, and stash it in InitDMABlock
        ; Once the initial memory claiming is done we can re-insert it
        ADD     a4, a3, #DRAMPhysAddrA-VideoPhysAddr    ; don't claim VRAM

        ; First block needs special treatment as we've already claimed some of it
        LDMIA   a4!, {v1, v2}
        TST     v2, #OSAddRAM_NoDMA
        BNE     %FT41
        CMP     v2, a1
        BLO     %FT41
        ; Oh crumbs, the first block is a match for our DMA block
        ; Claim it as normal, but set InitDMAEnd to v1+DRAMOffset_LastFixed so
        ; that the already used bit won't get used for DMA
        ; We also need to be careful later on when picking the initial v2 value
623
        MOV     lr, v1, LSL #12
624
        ADD     lr, lr, #DRAMOffset_LastFixed_$pt
625 626 627 628
        STR     lr, [ip, #InitDMAEnd]
        B       %FT43
41
        ; Go on to check the rest of PhysRamTable
629
        SUB     a1, a1, #DRAMOffset_LastFixed_$pt
630 631 632 633 634 635
42
        LDMIA   a4!, {v1, v2}
        TST     v2, #OSAddRAM_NoDMA
        BNE     %BT42
        CMP     v2, a1
        BLO     %BT42
636 637
        CMP     v1, #1:SHL:20 ; <4GB only for now
        BHS     %BT42
638
        ; Make a note of this block
639 640
        MOV     lr, v1, LSL #12
        STR     lr, [ip, #InitDMAEnd]
641 642 643 644 645 646 647
43
        STR     v1, [ip, #InitDMABlock]
        STR     v2, [ip, #InitDMABlock+4]
        SUB     lr, a4, a3
        STR     lr, [ip, #InitDMAOffset]
        ; Now shrink/remove this memory from PhysRamTable
        SUB     v2, v2, a1
648
        ADD     v1, v1, a1, LSR #12
649 650 651 652 653 654 655 656 657 658
        CMP     v2, #4096               ; Block all gone?
        STMHSDB a4, {v1, v2}            ; no, just shrink it
        BHS     %FT55
45
        CMP     a4, v7
        LDMNEIA a4, {v1, v2}
        STMNEDB a4, {v1, v2}
        ADDNE   a4, a4, #8
        BNE     %BT45
        SUB     v7, v7, #8
659

660
; a2 = Total memory size (pages)
661 662
; a3 = PhysRamTable
; v7 = After last used entry in PhysRamTable
663
; ip -> ZeroPage
664 665 666 667 668 669 670 671 672 673 674 675

; now store zeros to fill out table

55
        ADD     v2, a3, #PhysRamTableEnd-PhysRamTable
        MOV     v3, #0
        MOV     v4, #0
57
        CMP     v7, v2
        STMLOIA v7!, {v3, v4}
        BLO     %BT57

676 677 678
; Calculate PhysIllegalMask before anything tries to use it
        BL      DeterminePhysIllegalMask

679 680
; Time to set up the L1PT. Just zero it out for now.

681
 [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
682 683 684 685 686
        ASSERT  DRAMOffset_LL1PT = DRAMOffset_LL2PT+16*1024
        LDR     a4, =DRAMOffset_LL1PT+4096-(PhysRamTable+DRAMOffset_PageZero) ; offset from a3 to L1PT end
        ADD     a3, a3, a4
        MOV     a4, #16*1024+4096 ; Clear the full L1PT page, even though we only need/use a small part of it
 |
687 688
        LDR     a4, =DRAMOffset_L1PT+16*1024-(PhysRamTable+DRAMOffset_PageZero) ; offset from a3 to L1PT end
        ADD     a3, a3, a4
689
        MOV     a4, #16*1024
Jeffrey Lee's avatar
Jeffrey Lee committed
690
 ]
691 692 693 694 695 696 697 698 699 700 701 702 703
        MOV     v2, #0
        MOV     v3, #0
        MOV     v4, #0
        MOV     v5, #0
        MOV     v6, #0
        MOV     v7, #0
        MOV     v8, #0
        MOV     ip, #0
60
        STMDB   a3!, {v2-v8,ip}                         ; start at end and work back
        SUBS    a4, a4, #8*4
        BNE     %BT60

704
 [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
        ; a3 -> L2PT
        ; Set up L1PT
        ADD     lr, a3, #DRAMOffset_LL1PT - DRAMOffset_PageTables
        ASSERT  :INDEX: DRAMOffset_PageTables = :INDEX: DRAMOffset_LL2PT
        ORR     v1, a3, #LL12_Table
        MOV     v2, #0
        STRD    v1, [lr], #8
        ADD     v1, v1, #4096
        STRD    v1, [lr], #8
        ADD     v1, v1, #4096
        STRD    v1, [lr], #8
        ADD     v1, v1, #4096
        STRD    v1, [lr], #8
 ]

        ADD     v1, a3, #DRAMOffset_PageZero - DRAMOffset_PageTables
721
        ADD     v2, a3, #DRAMOffset_LastFixed_$pt - DRAMOffset_PageTables
722
        STR     a2, [v1, #RAMLIMIT]                     ; remember the RAM size
723
        SUB     lr, a2, #1
724
        STR     lr, [v1, #MaxCamEntry]
725 726 727
        MOV     lr, a2, LSR #12-CAM_EntrySizeLog2       ; no. of pages needed for CAM
        CMP     a2, lr, LSL #12-CAM_EntrySizeLog2
        ADDNE   lr, lr, #1                              ; round up
728 729 730 731 732
        MOV     lr, lr, LSL #12
        STR     lr, [v1, #SoftCamMapSize]
        STR     a3, [v1, #InitUsedStart]                ; store start of L1PT

        ADD     v1, v1, #DRAMPhysAddrA
733
        MOV     v2, v2, LSR #12
734 735
        MOV     v3, a3

736 737 738
        ; Detect if the DMA claiming adjusted the first block
        ; If so, we'll need to reset v2 to the start of the block at v1
        LDR     a1, [v1]
739
        ADD     lr, a1, #DRAMOffset_LastFixed_$pt:SHR:12
740 741 742
        TEQ     lr, v2
        MOVNE   v2, a1

743 744
; For the next batch of allocation routines, v1-v3 are treated as globals.
; v1 -> current entry in PhysRamTable
745
; v2 -> next address to allocate in v1 (may point at end of v1), in units of pages
746 747
; v3 -> L1PT (or 0 if MMU on - not yet)

748
; Set up some temporary PCBTrans and PPLTrans pointers, and the initial page flags used by the page tables
Jeffrey Lee's avatar
Jeffrey Lee committed
749
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
750
        BL      Init_PCBTrans_$pt
751

752 753
; Allocate the L2PT backing store for the logical L2PT space, to
; prevent recursion.
754
  [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
755 756 757 758 759 760
        ; L3PT is 8MB in size, and each 4KB of L3PT only covers 2MB of RAM
        ; This means we'll need 4 pages of L3PT to create the full logical
        ; mapping of L3PT. So to avoid recursion, we need to start by explicitly
        ; allocating the area that will be used for the logical mapping of L3PT.
        LDR     a1, =LL3PT+(LL3PT:SHR:9)
        MOV     a2, #&00800000:SHR:9
761
        BL      AllocateL2PT_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
762 763 764
        ; Now allocate the rest of the L3PT logical mapping
        LDR     a1, =LL3PT
        MOV     a2, #&00800000
765
        BL      AllocateL2PT_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
766 767 768 769 770
  |
        ; Each 4KB of L2PT covers 4MB of RAM, and L2PT is 4MB in size, so the
        ; first page we allocate here will allow us to create the full logical
        ; mapping of L2PT (protecting against any recursion in the allocation
        ; routines)
771
        LDR     a1, =L2PT
Kevin Bracey's avatar
Kevin Bracey committed
772
        MOV     a2, #&00400000
773
        BL      AllocateL2PT_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
774
  ]
775

776 777
; Allocate workspace for the HAL

Jeffrey Lee's avatar
Jeffrey Lee committed
778
        ADD     a4, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
779 780
        LDR     a3, [sp, #8]                            ; recover pushed HAL header
        LDR     a1, =HALWorkspace
781
        LDR     a2, =AreaFlags_HALWorkspace
782 783
        LDR     lr, [a3, #HALDesc_Workspace]            ; their workspace
        LDR     ip, [a3, #HALDesc_NumEntries]           ; plus 1 word per entry
784 785
        CMP     ip, #KnownHALEntries
        MOVLO   ip, #KnownHALEntries
786 787
        ADD     ip, ip, #1                              ; round up so that HAL workspace is doubleword aligned
        BIC     ip, ip, #1
788
        ADD     lr, lr, ip, LSL #2
789 790 791 792
        MOV     a3, lr, LSR #12                         ; round workspace up to whole
        MOV     a3, a3, LSL #12                         ; number of pages
        CMP     a3, lr
        ADDNE   a3, a3, #&1000
793 794 795
        STR     a3, [a4, #HAL_WsSize]                   ; Make a note of allocated space
        ADD     ip, a1, ip, LSL #2                      ; Their workspace starts
        STR     ip, [a4, #HAL_Workspace]                ; after our table of entries
796
        BL      Init_MapInRAM_$pt
797

798 799 800 801
        LDR     a3, [sp, #8]                            ; recover pushed HAL header
        LDR     lr, [a3, #HALDesc_Flags]
        TST     lr, #HALFlag_NCNBWorkspace              ; do they want uncacheable
        LDRNE   a1, =HALWorkspaceNCNB                   ; workspace?
802
        LDRNE   a2, =AreaFlags_HALWorkspaceNCNB
803
        LDRNE   a3, =32*1024
804
        BLNE    Init_MapInRAM_DMA_$pt
805

806 807 808 809 810 811 812
; Bootstrap time. We want to get the MMU on ASAP. We also don't want to have to
; clear up too much mess later. So what we'll do is map in the three fixed areas
; (L1PT, scratch space and page zero), the CAM, ourselves, and the HAL,
; then turn on the MMU. The CAM will be filled in once the MMU is on, by
; reverse-engineering the page tables?

        ; Map in page zero
Jeffrey Lee's avatar
Jeffrey Lee committed
813
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
Jeffrey Lee's avatar
Jeffrey Lee committed
814
        LDR     a2, =ZeroPage
815
        LDR     a3, =AreaFlags_ZeroPage
816
        MOV     a4, #16*1024
817
        BL      Init_MapIn_$pt
818 819

        ; Map in scratch space
Jeffrey Lee's avatar
Jeffrey Lee committed
820
        ADD     a1, v3, #DRAMOffset_ScratchSpace - DRAMOffset_PageTables
821
        MOV     a2, #ScratchSpace
822
        LDR     a3, =AreaFlags_ScratchSpace
823
        MOV     a4, #16*1024
824
        BL      Init_MapIn_$pt
825

826
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
827 828 829 830 831 832 833 834
        ; Map in L1PT+L2PT
        MOV     a1, v3
        LDR     a2, =LL2PT
        ADD     a3, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
        LDR     a3, [a3, #PageTable_PageFlags]
        ORR     a3, a3, #PageFlags_Unavailable
        ASSERT  LL1PT=LL2PT+16*1024
        MOV     a4, #16*1024+4096
835
        BL      Init_MapIn_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
836
      |
837 838 839
        ; Map in L1PT
        MOV     a1, v3
        LDR     a2, =L1PT
Jeffrey Lee's avatar
Jeffrey Lee committed
840
        ADD     a3, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
841 842
        LDR     a3, [a3, #PageTable_PageFlags]
        ORR     a3, a3, #PageFlags_Unavailable
843
        MOV     a4, #16*1024
844
        BL      Init_MapIn_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
845
      ]
846 847

        ; Map in L1PT again in PhysicalAccess (see below)
848
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
849 850 851 852
        MOV     a1, v3, LSR #21
        MOV     a1, a1, LSL #21                 ; 2MB containing L1PT
        MOV     a4, #2*1024*1024
      |
853 854
        MOV     a1, v3, LSR #20
        MOV     a1, a1, LSL #20                 ; megabyte containing L1PT
Jeffrey Lee's avatar
Jeffrey Lee committed
855 856
        MOV     a4, #1024*1024
      ]
857
        LDR     a2, =PhysicalAccess
Jeffrey Lee's avatar
Jeffrey Lee committed
858
        ADD     a3, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
859 860
        LDR     a3, [a3, #PageTable_PageFlags]
        ORR     a3, a3, #PageFlags_Unavailable
861
        BL      Init_MapIn_$pt
862

863

864 865 866 867 868 869 870
        ; Examine HAL and RISC OS locations
        LDMFD   sp, {v4,v5,v6}                  ; v4 = flags, v5 = RO desc, v6 = HAL desc
        LDR     lr, [v6, #HALDesc_Size]
        LDR     v7, [v6, #HALDesc_Start]
        ADD     v6, v6, v7                      ; (v6,v8)=(start,end) of HAL
        ADD     v8, v6, lr

871
        LDR     v7, [v5, #OSHdr_ImageSize]
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
        ADD     v7, v5, v7                      ; (v5,v7)=(start,end) of RISC OS

        TEQ     v8, v5                          ; check contiguity (as in a ROM image)
        BNE     %FT70

        ; HAL and RISC OS are contiguous. Yum.
        MOV     a1, v6
        LDR     a2, =RISCOS_Header
        SUB     a2, a2, lr

        SUB     ip, a2, a1                      ; change physical addresses passed in
        LDMIB   sp, {a3, a4}                    ; into logical addresses
        ADD     a3, a3, ip
        ADD     a4, a4, ip
        STMIB   sp, {a3, a4}
887 888
        LDR     a3, [v5, #OSHdr_DecompressHdr]  ; check if ROM is compressed, and if so, make writeable
        CMP     a3, #0
889 890
        MOVNE   a3, #OSAP_None
        MOVEQ   a3, #OSAP_ROM
891
        SUB     a4, v7, v6
892
        BL      Init_MapIn_$pt
893
        MOV     a3, v6
894 895 896
        B       %FT75

70
897 898
        ; HAL is separate. (We should cope with larger images)
        LDR     a2, =ROM
899 900 901 902 903 904
        MOV     a1, v6
        SUB     ip, a2, a1                      ; change physical address passed in
        LDR     a3, [sp, #8]                    ; into logical address
        ADD     a3, a3, ip
        STR     a3, [sp, #8]
        SUB     a4, v8, v6
905
        MOV     a3, #OSAP_ROM
906
        BL      Init_MapIn_$pt
907 908 909 910 911 912 913 914 915

        ; And now map in RISC OS
        LDR     a2, =RISCOS_Header              ; Hmm - what if position independent?
        MOV     a1, v5
        SUB     ip, a2, a1                      ; change physical address passed in
        LDR     a3, [sp, #4]                    ; into logical address
        ADD     a3, a3, ip
        STR     a3, [sp, #4]
        SUB     a4, v7, v5
916 917
        LDR     a3, [v5, #OSHdr_DecompressHdr]
        CMP     a3, #0
918
        MOVNE   a3, #OSAP_None
919
        MOVEQ   a3, #OSAP_ROM
920
        BL      Init_MapIn_$pt
921
        MOV     a3, v5
922 923 924
75
        ; We've now allocated all the pages we're going to before the MMU comes on.
        ; Note the end address (for RAM clear)
Jeffrey Lee's avatar
Jeffrey Lee committed
925
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_PageTables
926
        STR     v1, [a1, #InitUsedBlock]
927
        STR     v2, [a1, #InitUsedEnd]
928
        STR     a3, [a1, #ROMPhysAddr]
929

930 931
        ; Note the HAL flags passed in.
        LDR     a2, [sp, #0]
932
        STR     a2, [a1, #HAL_StartFlags]
933

934
        ; Set up a reset IRQ handler (for IIC CMOS access)
Kevin Bracey's avatar
Kevin Bracey committed
935
        MSR     CPSR_c, #IRQ32_mode + I32_bit + F32_bit
936
        LDR     sp_irq, =ScratchSpace + 1024    ; 1K is plenty since Reset_IRQ_Handler now runs in SVC mode
Kevin Bracey's avatar
Kevin Bracey committed
937 938 939 940
        MSR     CPSR_c, #SVC32_mode + I32_bit + F32_bit
        LDR     a2, =Reset_IRQ_Handler
        STR     a2, [a1, #InitIRQHandler]

941 942 943 944 945 946 947 948 949 950
        ; Fill in some initial processor vectors. These will be used during ARM
        ; analysis, once the MMU is on. We do it here before the data cache is
        ; activated to save any IMB issues.
        ADRL    a2, InitProcVecs
        ADD     a3, a2, #InitProcVecsEnd - InitProcVecs
76      LDR     a4, [a2], #4
        CMP     a2, a3
        STR     a4, [a1], #4
        BLO     %BT76

951
MMU_activation_zone_$pt
952 953 954 955 956 957
; The time has come to activate the MMU. Steady now... Due to unpredictability of MMU
; activation, need to ensure that mapped and unmapped addresses are equivalent. To
; do this, we temporarily make the section containing virtual address MMUon_instr map
; to the same physical address. In case the code crosses a section boundary, do the
; next section as well.
;
958 959
        MOV     a1, #4_0000000000000001                         ; domain 0 client only
        ARM_MMU_domain a1
960

961 962
        ADR     a1, MMU_activation_zone_$pt
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
        ; To avoid refactoring things too much, only touch one page table
        ; entry instead of two. However because each L2PT entry is 2MB we end
        ; up covering the same area (just 2MB aligned instead of the 1MB
        ; alignment that you'd get with short descriptor L1PT).
        MOV     a3, a1, LSR #21                 ; a3 = 2MB number (stays there till end)
        ADD     lr, v3, a3, LSL #3              ; lr -> L2PT entry
        LDRD    a1, [lr]                        ; remember old mapping
        Push    "a1,a2"
        MOV     a1, a3, LSL #21
        ORR     a1, a1, #LL12_Block + LLAttr_Nrm_NC + LL_Page_LowAttr_AP2 ; Non-cacheable, read-only
        ORR     a1, a1, #LL_Page_LowAttr_AF
        MOV     a2, #0
        STRD    a1, [lr]
        Pull    "a1,a2"
      |
978 979 980
        MOV     a1, a1, LSR #20                 ; a1 = megabyte number (stays there till end)
        ADD     lr, v3, a1, LSL #2              ; lr -> L1PT entry
        LDMIA   lr, {a2, a3}                    ; remember old mappings
981 982 983
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
984 985 986 987 988
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
989
 ]
990 991 992
        ORR     a4, ip, a1, LSL #20             ; not cacheable, as we don't want
        ADD     v4, a4, #1024*1024              ; to fill the cache with rubbish
        STMIA   lr, {a4, v4}
Jeffrey Lee's avatar
Jeffrey Lee committed
993
      ]
994

995
        MOV     a4, a1
996
        Push    "a2,lr"
997
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
998 999
        ADD     a1, v3, #DRAMOffset_LL1PT-DRAMOffset_PageTables
      |
1000
        MOV     a1, v3
Jeffrey Lee's avatar
Jeffrey Lee committed
1001 1002
      ]
        ADD     a2, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables
1003
        PTOp    SetTTBR
1004
        Pull    "a2,lr"
1005
        BL      Init_ARMarch                    ; corrupts a1 and ip
1006
        MOV     ip, a1                          ; Remember architecture for later
1007
        MOV     a1, a4
1008

1009
        MSREQ   CPSR_c, #F32_bit+I32_bit+UND32_mode ; Recover the soft copy of the CR
1010
        MOVEQ   v5, sp
1011
        ARM_read_control v5, NE
1012
  [ CacheOff
1013
        ORR     v5, v5, #MMUC_M                 ; MMU on
1014 1015
        ORR     v5, v5, #MMUC_R                 ; ROM mode enable
  |
1016
        ORR     v5, v5, #MMUC_W+MMUC_C+MMUC_M   ; Write buffer, data cache, MMU on
1017
        ORR     v5, v5, #MMUC_R+MMUC_Z          ; ROM mode enable, branch predict enable
1018 1019 1020 1021 1022
  ]
  [ MEMM_Type = "VMSAv6"
        ORR     v5, v5, #MMUC_XP ; Extended pages enabled (v6)
        BIC     v5, v5, #MMUC_TRE+MMUC_AFE ; TEX remap, Access Flag disabled
        BIC     v5, v5, #MMUC_EE+MMUC_TE+MMUC_VE ; Exceptions = nonvectored LE ARM
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
      [ SupportARMv6 :LAND: NoARMv7
        ; Deal with a couple of ARM11 errata
        ARM_read_ID lr
        LDR     a4, =&FFF0
        AND     lr, lr, a4
        LDR     a4, =&B760
        TEQ     lr, a4
        BNE     %FT01
        ORR     v5, v5, #MMUC_FI ; Erratum 716151: Disable hit-under-miss (enable fast interrupt mode) to prevent D-cache corruption from D-cache cleaning (the other workaround, ensuring a DSB exists inbetween the clean op and the next store access to that cache line, feels a bit heavy-handed since we'd probably have to disable IRQs to make it fully safe)
        ; Update the aux control register
        MRC     p15, 0, lr, c1, c0, 1
        ; Bit 28: Erratum 714068: Set PHD bit to prevent deadlock from PLI or I-cache invalidate by MVA
        ; Bit 31: Erratum 716151: Set FIO bit to override some of the behaviour implied by FI bit
        ORR     lr, lr, #(1:SHL:28)+(1:SHL:31)
        MCR     p15, 0, lr, c1, c0, 1
        myISB   ,lr
Jeffrey Lee's avatar
Jeffrey Lee committed
1039
        TEQ     pc, #0 ; Restore NE condition from Init_ARMarch
1040 1041
01
      ]
1042
  ]
1043 1044 1045
  [ NoUnaligned
        ORR     v5, v5, #MMUC_A ; Alignment exceptions on
  ]
Jeffrey Lee's avatar
Jeffrey Lee committed
1046 1047 1048
  [ HiProcVecs
        ORR     v5, v5, #MMUC_V ; High processor vectors enabled
  ]
1049

1050
MMUon_instr_$pt
1051 1052 1053
; Note, no RAM access until we've reached MMUon_nol1ptoverlap and the flat
; logical-physical mapping of the ROM has been removed (we can't guarantee that
; the RAM mapping hasn't been clobbered, and SP is currently bogus).
1054
        ARM_write_control v5
1055
  [ MEMM_Type = "VMSAv6"
1056 1057
        MOV     lr, #0
        myISB   ,lr,,y ; Just in case
1058
  ]
1059
        MOVEQ   sp, v5
1060 1061
        MSREQ   CPSR_c, #F32_bit+I32_bit+SVC32_mode

1062
  [ MEMM_Type = "VMSAv6"
1063
        CMP     ip, #ARMvF
Ben Avison's avatar
Ben Avison committed
1064
        BEQ     %FT01
1065
        MCRNE   ARM_config_cp,0,lr,ARMv4_cache_reg,C7           ; junk MMU-off contents of I-cache (works on ARMv3)
Ben Avison's avatar
Ben Avison committed
1066 1067
        B       %FT02
01      MCREQ   p15, 0, lr, c7, c5, 0           ; invalidate instruction cache
1068
        MCREQ   p15, 0, lr, c8, c7, 0           ; invalidate TLBs
1069
        MCREQ   p15, 0, lr, c7, c5, 6           ; invalidate branch predictor
1070
        myISB   ,lr,,y ; Ensure below branch works
1071
        BLEQ    HAL_InvalidateCache_ARMvF       ; invalidate data cache (and instruction+TLBs again!)
Ben Avison's avatar
Ben Avison committed
1072
02
1073 1074 1075 1076
  |
        MOV     lr, #0                                          ; junk MMU-off contents of I-cache
        MCR     ARM_config_cp,0,lr,ARMv4_cache_reg,C7           ; (works on ARMv3)
  ]
1077 1078 1079 1080 1081 1082 1083 1084

; MMU now on. Need to jump to logical copy of ourselves. Complication arises if our
; physical address overlaps our logical address - in that case we need to map
; in another disjoint copy of ourselves and branch to that first, then restore the
; original two sections.
        ADRL    a4, RISCOS_Header
        LDR     ip, =RISCOS_Header
        SUB     ip, ip, a4
1085 1086
        ADR     a4, MMU_activation_zone_$pt
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1087 1088 1089
        MOV     a4, a4, LSR #21
        MOV     a4, a4, LSL #21                 ; a4 = base of scrambled region
      |
1090 1091
        MOV     a4, a4, LSR #20
        MOV     a4, a4, LSL #20                 ; a4 = base of scrambled region
Jeffrey Lee's avatar
Jeffrey Lee committed
1092
      ]
1093 1094
        ADD     v4, a4, #2*1024*1024            ; v4 = top of scrambled region
        SUB     v4, v4, #1                      ;      (inclusive, in case wrapped to 0)
1095
        ADR     v5, MMUon_resume_$pt
1096 1097
        ADD     v5, v5, ip                      ; v5 = virtual address of MMUon_resume
        CMP     v5, a4
1098
        BLO     MMUon_nooverlap_$pt
1099
        CMP     v5, v4
1100
        BHI     MMUon_nooverlap_$pt
1101

1102
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
        ASSERT  ROM > 4*1024*1024
; Oh dear. We know the ROM lives high up, so we'll mangle 00200000-003FFFFF.
; But as we're overlapping the ROM, we know we're not overlapping the page tables.
        LDR     lr, =LL2PT                      ; accessing the L2PT virtually now
        ; Use IP+SP as temp
        ORR     ip, a4, #LL12_Block + LLAttr_Nrm_NC + LL_Page_LowAttr_AP2 ; Non-cacheable, read-only
        ORR     ip, ip, #LL_Page_LowAttr_AF
        MOV     sp, #0
        LDRD    v7, [lr, #8]
        STRD    ip, [lr, #8]
        myDSB   ,ip                             ; there shouldn't have been anything at the target, so DSB+ISB is all that's needed for synchronisation
        myISB   ,ip,,y
        RSB     ip, a4, #&00200000
        ADD     pc, pc, ip
        NOP
1118
MMUon_overlapresume_$pt                         ; now executing from 00200000
Jeffrey Lee's avatar
Jeffrey Lee committed
1119 1120 1121 1122 1123 1124 1125 1126
        ADD     ip, lr, a4, LSR #18
        STRD    a1, [ip]                        ; restore original set of mappings
        BL      Init_PageTablesChanged

        MOV     a1, v7                          ; arrange for code below
        MOV     a2, v8                          ; to restore this area instead
        MOV     a3, #1
      |
1127 1128 1129 1130
        ASSERT  ROM > 3*1024*1024
; Oh dear. We know the ROM lives high up, so we'll mangle 00100000-002FFFFF.
; But as we're overlapping the ROM, we know we're not overlapping the page tables.
        LDR     lr, =L1PT                       ; accessing the L1PT virtually now
1131 1132 1133
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
1134 1135 1136 1137 1138
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
1139
 ]
1140 1141 1142 1143
        ORR     v6, a4, ip
        ADD     ip, v6, #1024*1024
        LDMIB   lr, {v7, v8}                    ; sections 1 and 2
        STMIB   lr, {v6, ip}
Jeffrey Lee's avatar
Jeffrey Lee committed
1144 1145 1146 1147
 [ MEMM_Type = "VMSAv6"
        myDSB   ,ip                             ; there shouldn't have been anything at the target, so DSB+ISB is all that's needed for synchronisation
        myISB   ,ip,,y
 ]
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
        RSB     ip, a4, #&00100000
        ADD     pc, pc, ip
        NOP
MMUon_overlapresume                             ; now executing from 00100000
        ADD     ip, lr, a4, LSR #18
        STMIA   ip, {a2, a3}                    ; restore original set of mappings
        BL      Init_PageTablesChanged

        MOV     a2, v7                          ; arrange for code below
        MOV     a3, v8                          ; to restore section 1+2 instead
        MOV     a1, #1
Jeffrey Lee's avatar
Jeffrey Lee committed
1159
      ]
1160

Jeffrey Lee's avatar
Jeffrey Lee committed
1161
; Jump to the final logical mapping of ROM
1162
MMUon_nooverlap_$pt
1163 1164 1165 1166 1167
        ADRL    lr, RISCOS_Header
        LDR     ip, =RISCOS_Header
        SUB     ip, ip, lr
        ADD     pc, pc, ip
        NOP
1168
MMUon_resume_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
1169 1170
; Repair the page table mapping that we temporarily modified.
; But what if the logical address of the page tables is at the physical address of the code? (i.e. our temporary modification is blocking access to the page tables)
1171
; Then we have to access it via PhysicalAccess instead.
1172
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1173 1174
        LDR     lr, =LL2PT
      |
1175
        LDR     lr, =L1PT
Jeffrey Lee's avatar
Jeffrey Lee committed
1176
      ]
1177
        CMP     lr, a4
1178
        BLO     MMUon_nol1ptoverlap_$pt
1179
        CMP     lr, v4
1180
        BHI     MMUon_nol1ptoverlap_$pt
1181 1182
; PhysicalAccess points to the megabyte containing the L1PT. Find the L1PT within it.
        LDR     lr, =PhysicalAccess
1183
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1184 1185
        MOV     v6, v3, LSL #11
        ORR     lr, lr, v6, LSR #11
1186
MMUon_nol1ptoverlap_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
1187 1188 1189
        ADD     lr, lr, a3, LSL #3
        STRD    a1, [lr]
      |
1190 1191
        MOV     v6, v3, LSL #12
        ORR     lr, lr, v6, LSR #12
1192
MMUon_nol1ptoverlap_$pt
1193 1194
        ADD     lr, lr, a1, LSL #2
        STMIA   lr, {a2, a3}
Jeffrey Lee's avatar
Jeffrey Lee committed
1195
      ]
1196 1197 1198
        BL      Init_PageTablesChanged

; The MMU is now on. Wahey. Let's get allocating.
Jeffrey Lee's avatar
Jeffrey Lee committed
1199 1200 1201 1202 1203 1204
;
; Input:
; v3 = phys addr of DRAMOffset_PageTables
; R13_und = MMU control register soft copy (for ARMv3)
;
; All other registers are set up from scratch
1205 1206 1207

        LDR     sp, =ScratchSpace + ScratchSpaceSize - 4*3 ; 3 items already on stack :)

1208 1209
        LDR     a1, =ZeroPage

Jeffrey Lee's avatar
Jeffrey Lee committed
1210
        ADD     lr, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables ; lr = PhysAddr of zero page
1211

Jeffrey Lee's avatar
Jeffrey Lee committed
1212 1213 1214 1215 1216
        LDR     v1, [a1, #InitUsedBlock]                ; turn this from Phys to Log
        SUB     v1, v1, lr
        ADD     v1, v1, a1
        STR     v1, [a1, #InitUsedBlock]
        LDR     v2, [a1, #InitUsedEnd]
1217

1218 1219 1220 1221
; Store the logical address of the HAL descriptor
        LDR     a2, [sp, #8]
        STR     a2, [a1, #HAL_Descriptor]

1222 1223 1224 1225
        MOV     v3, #0                                  ; "MMU is on" signal

        BL      ARM_Analyse

Kevin Bracey's avatar
Kevin Bracey committed
1226 1227
        ChangedProcVecs a1

Jeffrey Lee's avatar
Jeffrey Lee committed
1228 1229 1230
      [ LongDesc
        ASSERT  L1_Fault = LL_Fault
      ]
1231
        MOV     a1, #L1_Fault
1232
        PTOp    ReleasePhysicalAddress
1233 1234

        LDR     a1, =HALWorkspace
Jeffrey Lee's avatar
Jeffrey Lee committed
1235
        LDR     a2, =ZeroPage
1236
        LDR     a3, [a2, #HAL_WsSize]
Jeffrey Lee's avatar
Jeffrey Lee committed
1237 1238 1239
      [ ZeroPage <> 0
        MOV     a2, #0
      ]
1240 1241
        BL      memset

Jeffrey Lee's avatar
Jeffrey Lee committed
1242
        LDR     a2, =ZeroPage
1243 1244
        LDR     a1, =IOLimit
        STR     a1, [a2, #IOAllocLimit]
Jeffrey Lee's avatar
Jeffrey Lee committed
1245 1246
        LDR     a1, [a2, #SoftCamMapSize]
        RSB     a1, a1, #CAMTop ; Start of CAM
1247
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1248 1249 1250 1251 1252
        BFC     a1, #0, #21 ; Round down to 2MB for IO start
      |
        MOV     a1, a1, LSR #20 ; Round down to 1MB for IO start
        MOV     a1, a1, LSL #20
      ]
1253
        STR     a1, [a2, #IOAllocPtr]
Jeffrey Lee's avatar
Jeffrey Lee committed
1254
        STR     a1, [a2, #IOAllocTop]
1255 1256 1257

        BL      SetUpHALEntryTable

1258 1259 1260
; Initialise the HAL. Due to its memory claiming we need to get our v1 and v2 values
; into workspace and out again around it.

Jeffrey Lee's avatar
Jeffrey Lee committed
1261
        LDR     a1, =ZeroPage
1262 1263 1264
        STR     v1, [a1, #InitUsedBlock]
        STR     v2, [a1, #InitUsedEnd]

1265
        LDR     a1, =RISCOS_Header
1266
        LDR     a2, =HALWorkspaceNCNB
1267 1268 1269
        AddressHAL
        CallHAL HAL_Init

1270
        DebugTX "HAL initialised"
1271

1272 1273 1274 1275 1276 1277 1278 1279 1280
        MOV     a1, #64 ; Old limit prior to OMAP3 port
        CallHAL HAL_IRQMax
        CMP     a1, #MaxInterrupts
        MOVHI   a1, #MaxInterrupts ; Avoid catastrophic failure if someone forgot to increase MaxInterrupts
        LDR     a2, =ZeroPage
        STR     a1, [a2, #IRQMax]

        LDR     v1, [a2, #InitUsedBlock]
        LDR     v2, [a2, #InitUsedEnd]
1281

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
; Start timer zero, at 100 ticks per second
        MOV     a1, #0
        CallHAL HAL_TimerGranularity

        MOV     a2, a1
        MOV     a1, #100
        BL      __rt_udiv

        MOV     a2, a1
        MOV     a1, #0
        CallHAL HAL_TimerSetPeriod
1293

1294 1295
        DebugTX "IICInit"

1296 1297
        BL      IICInit

1298
; Remember some stuff that's about to get zapped
1299 1300 1301 1302 1303
        LDR     ip, =ZeroPage
        LDR     v4, [ip, #ROMPhysAddr]
        LDR     v5, [ip, #RAMLIMIT]
        LDR     v7, [ip, #MaxCamEntry]
        LDR     v8, [ip, #IRQMax]
1304

1305
        LDR     a1, [ip, #HAL_StartFlags]
Kevin Bracey's avatar
Kevin Bracey committed
1306
        TST     a1, #OSStartFlag_RAMCleared
1307
        BLEQ    ClearWkspRAM            ; Only clear the memory if the HAL didn't
1308

1309
; Put it back
Jeffrey Lee's avatar
Jeffrey Lee committed
1310 1311 1312 1313 1314 1315 1316 1317 1318
        LDR     a1, =ZeroPage
        STR     v4, [a1, #ROMPhysAddr]
        STR     v5, [a1, #RAMLIMIT]
        STR     v7, [a1, #MaxCamEntry]
        STR     v8, [a1, #IRQMax]
        MSR     CPSR_c, #F32_bit + UND32_mode           ; retrieve the MMU control register soft copy
        STR     sp, [a1, #MMUControlSoftCopy]
        MSR     CPSR_c, #F32_bit + SVC32_mode
        MOV     v8, a1
1319

1320
; Calculate CPU feature flags
1321 1322
        BL      ReadCPUFeatures

1323 1324
        DebugTX "HAL_CleanerSpace"

1325
; Set up the data cache cleaner space if necessary (eg. for StrongARM core)
Kevin Bracey's avatar
Kevin Bracey committed
1326
        MOV     a1, #-1
1327 1328 1329 1330
        CallHAL HAL_CleanerSpace
        CMP     a1, #-1          ;-1 means none needed (HAL only knows this if for specific ARM core eg. system-on-chip)
        BEQ     %FT20
        LDR     a2, =DCacheCleanAddress
1331
        LDR     a3, =AreaFlags_DCacheClean
1332 1333 1334 1335 1336 1337
        ASSERT  DCacheCleanSize = 4*&10000                ; 64k of physical space used 4 times (allows large page mapping)
        MOV     a4, #&10000
        MOV     ip, #4
        SUB     sp, sp, #5*4       ;room for a1-a4,ip
10
        STMIA   sp, {a1-a4, ip}
1338
        BL      Init_MapIn_$pt
1339 1340 1341 1342 1343
        LDMIA   sp, {a1-a4, ip}
        SUBS    ip, ip, #1
        ADD     a2, a2, #&10000
        BNE     %BT10
        ADD     sp, sp, #5*4
1344

1345
20
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
; Decompress the ROM
        LDR     a1, =RISCOS_Header
        LDR     a2, [a1, #OSHdr_DecompressHdr]
        CMP     a2, #0
        BEQ     %FT30
        ADD     ip, a1, a2
        ASSERT  OSDecompHdr_WSSize = 0
        ASSERT  OSDecompHdr_Code = 4
        LDMIA   ip, {a3-a4}
        ADRL    a2, SyncCodeAreas
        CMP     a3, #0 ; Any workspace required?
        ADD     a4, a4, ip
   [ DebugHALTX
        BNE     %FT25
        DebugTX "Decompressing ROM, no workspace required"
      [ NoARMv5
        MOV     lr, pc
        MOV     pc, a4
      |
        BLX     a4
      ]
        DebugTX "Decompression complete"
        B       %FT27
25
   |
        ADREQ   lr, %FT27
        MOVEQ   pc, a4
   ]
        Push    "a1-a4,v1-v2,v5-v7"
; Allocate workspace for decompression code
; Workspace is located at a 4MB-aligned log addr, and is a multiple of 1MB in
; size. This greatly simplifies the code required to free the workspace, since
; we can guarantee it will have been section-mapped, and won't hit any
; partially-allocated L2PT blocks (where 4 L1PT entries point to subsections of
; the same L2PT page)
; This means all we need to do to free the workspace is zap the L1PT entries
; and rollback v1 & v2
; Note: This is effectively a MB-aligned version of Init_MapInRAM
1384 1385 1386
ROMDecompWSAddr_$pt * 4<<20
   [ pt = "LongDesc"
ROMDecompAlign_$pt * 21 ; 2MB aligned for long descriptor format
Jeffrey Lee's avatar
Jeffrey Lee committed
1387
   |
1388
ROMDecompAlign_$pt * 20
Jeffrey Lee's avatar
Jeffrey Lee committed
1389
   ]
1390
        DebugTX "Allocating decompression workspace"
1391
        LDR     v5, =(1<<ROMDecompAlign_$pt)-1
1392 1393 1394
        ADD     v7, a3, v5
        BIC     v7, v7, v5 ; MB-aligned size
        STR     v7, [sp, #8] ; Overwrite stacked WS size
1395
        MOV     v6, #ROMDecompWSAddr_$pt ; Current log addr
1396
26
Jeffrey Lee's avatar
Jeffrey Lee committed
1397 1398
        ADD     v2, v2, v5, LSR #12
        BIC     v2, v2, v5, LSR #12 ; MB-aligned physram
1399
        LDMIA   v1, {a2, a3}
Jeffrey Lee's avatar
Jeffrey Lee committed
1400 1401 1402
        SUB     a2, v2, a2 ; Amount of bank used (page units)
        RSB     a2, a2, a3, LSR #12 ; Amount of bank remaining (page units)
        MOVS    a2, a2, ASR #ROMDecompAlign_$pt-12 ; Round down to nearest MB
1403 1404
        LDRLE   v2, [v1, #8]! ; Move to next bank if 0MB left
        BLE     %BT26
1405
        CMP     a2, v7, LSR #ROMDecompAlign_$pt
1406
        MOVHS   a4, v7
1407
        MOVLO   a4, a2, LSL #ROMDecompAlign_$pt ; a4 = amount to take
Jeffrey Lee's avatar
Jeffrey Lee committed
1408
        MOV     a1, v2, LSL #12 ; set up parameters for MapIn call
1409
        MOV     a2, v6
1410
        MOV     a3, #OSAP_None
1411
        SUB     v7, v7, a4 ; Decrease amount to allocate
Jeffrey Lee's avatar
Jeffrey Lee committed
1412
        ADD     v2, v2, a4, LSR #12 ; Increase physram ptr
1413
        ADD     v6, v6, a4 ; Increase logram ptr
1414
        BL      Init_MapIn_$pt
1415 1416 1417
        CMP     v7, #0
        BNE     %BT26
        Pull    "a1-a2,v1-v2" ; Pull OS header, IMB func ptr, workspace size, decompression code
1418
        MOV     a3, #ROMDecompWSAddr_$pt
1419 1420 1421 1422 1423 1424 1425 1426 1427
        DebugTX "Decompressing ROM"
      [ NoARMv5
        MOV     lr, pc
        MOV     pc, v2
      |
        BLX     v2
      ]
        DebugTX "Decompression complete"
; Before we free the workspace, make sure we zero it
1428
        MOV     a1, #ROMDecompWSAddr_$pt
1429 1430 1431
        MOV     a2, #0
        MOV     a3, v1
        BL      memset
1432 1433 1434
; Flush the workspace from the cache so we can unmap it
; Really we should make the pages uncacheable first, but for simplicity we do a
; full cache+TLB clean+invalidate later on when changing the ROM permissions
1435
        MOV     a1, #ROMDecompWSAddr_$pt
1436 1437
        ADD     a2, a1, v1
        ARMop   Cache_CleanInvalidateRange
1438
; Zero each L1PT entry
1439
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1440 1441 1442
        ; Ensure STRD is used
        MOV     a1, #0
        MOV     a2, #0
1443
        LDR     a3, =LL2PT+(ROMDecompWSAddr_$pt>>18)
Jeffrey Lee's avatar
Jeffrey Lee committed
1444 1445 1446 1447 1448 1449
        MOV     a4, v1, LSR #18
265
        STRD    a1, [a3], #8
        SUBS    a4, a4, #8
        BGE     %BT265
      |
1450
        LDR     a1, =L1PT+(ROMDecompWSAddr_$pt>>18)
1451 1452 1453
        MOV     a2, #0
        MOV     a3, v1, LSR #18
        BL      memset
Jeffrey Lee's avatar
Jeffrey Lee committed
1454
      ]
1455 1456 1457 1458 1459 1460 1461
; Pop our registers and we're done
        Pull    "v1-v2,v5-v7"
        DebugTX "ROM decompression workspace freed"
27
; Now that the ROM is decompressed we need to change the ROM page mapping to
; read-only. The easiest way to do this is to make another call to Init_MapIn.
; But before we can do that we need to work out if the HAL+OS are contiguous in
Jeffrey Lee's avatar
Jeffrey Lee committed
1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
; physical space, so that we remap the correct area.
        LDR     a1, =RISCOS_Header
        BL      RISCOS_LogToPhys
        Push    "a1"
        LDR     a1, =ROM
        BL      RISCOS_LogToPhys
        Pull    "a2"                    ; a1 = HAL phys, a2 = OS phys
        LDR     a3, =ZeroPage
        LDR     a3, [a3, #HAL_Descriptor]
        LDR     a3, [a3, #HALDesc_Size]
        ADD     a3, a3, a1              ; a3 = phys addr of OS if contiguous
        CMP     a2, a3
; Contiguous mapping, remap combined HAL+OS
        MOVEQ   a2, #ROM
        MOVEQ   a4, #OSROM_ImageSize*1024
; Discontiguous mapping, only remap OS
        MOVNE   a1, a2
        LDRNE   a2, =RISCOS_Header
        LDRNE   a4, [a2, #OSHdr_ImageSize]
1481
        MOV     a3, #OSAP_ROM
1482
        BL      Init_MapIn_$pt
1483 1484 1485
; Flush & invalidate cache/TLB to ensure everything respects the new page access
; Putting a flush here also means the decompression code doesn't have to worry
; about IMB'ing the decompressed ROM
Jeffrey Lee's avatar
Jeffrey Lee committed
1486
        ARMop   MMU_Changing ; Perform full clean+invalidate to ensure any lingering cache lines for the decompression workspace are gone
1487 1488
        DebugTX "ROM access changed to read-only"
30
1489 1490
; Allocate the CAM
        LDR     a3, [v8, #SoftCamMapSize]
1491
        LDR     a2, =AreaFlags_CAM
Jeffrey Lee's avatar
Jeffrey Lee committed
1492 1493
        RSB     a1, a3, #CAMTop
        STR     a1, [v8, #CamEntriesPointer]
1494
        BL      Init_MapInRAM_$pt
1495 1496 1497

; Allocate the supervisor stack
        LDR     a1, =SVCStackAddress
1498
        LDR     a2, =AreaFlags_SVCStack
1499
        LDR     a3, =SVCStackSize
1500
        BL      Init_MapInRAM_$pt
1501 1502 1503

; Allocate the interrupt stack
        LDR     a1, =IRQStackAddress
1504
        LDR     a2, =AreaFlags_IRQStack
1505
        LDR     a3, =IRQStackSize
1506
        BL      Init_MapInRAM_$pt
1507 1508 1509

; Allocate the abort stack
        LDR     a1, =ABTStackAddress
1510
        LDR     a2, =AreaFlags_ABTStack
1511
        LDR     a3, =ABTStackSize
1512
        BL      Init_MapInRAM_$pt
1513 1514 1515

; Allocate the undefined stack
        LDR     a1, =UNDStackAddress
1516
        LDR     a2, =AreaFlags_UNDStack
1517
        LDR     a3, =UNDStackSize
1518
        BL      Init_MapInRAM_$pt
1519

1520
; Allocate the system heap (just 32K for now - will grow as needed)
1521
        LDR     a1, =SysHeapAddress
1522
        LDR     a2, =AreaFlags_SysHeap
1523
        LDR     a3, =32*1024
1524
        BL      Init_MapInRAM_Clear_$pt
1525

1526
; Allocate the cursor/system/sound block - first the cached bit
1527
        LDR     a1, =CursorChunkAddress
1528
        LDR     a2, =AreaFlags_CursorChunkCacheable
1529
        LDR     a3, =SoundDMABuffers - CursorChunkAddress
1530
        BL      Init_MapInRAM_DMA_$pt
1531 1532
; then the uncached bit
        LDR     a1, =SoundDMABuffers
1533
        LDR     a2, =AreaFlags_CursorChunk
1534
        LDR     a3, =?SoundDMABuffers
1535
        BL      Init_MapInRAM_DMA_$pt
1536

1537
        LDR     a1, =KbuffsBaseAddress
1538
        LDR     a2, =AreaFlags_Kbuffs
1539
        LDR     a3, =(KbuffsSize + &FFF) :AND: &FFFFF000  ;(round to 4k)
1540
        BL      Init_MapInRAM_Clear_$pt
1541

Jeffrey Lee's avatar
Jeffrey Lee committed
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
; Allocate the RW/ZI data segment
        IMPORT  |Image$$RW$$Base|
        LDR     a1, =|Image$$RW$$Base|
        LDR     a2, =AreaFlags_RWArea
        IMPORT  |Image$$ZI$$Limit|
        LDR     a3, =|Image$$ZI$$Limit|+&FFF
        SUB     a3, a3, a1
        BIC     a3, a3, #&FF
        BIC     a3, a3, #&F00
        BL      Init_MapInRAM_Clear_$pt

Jeffrey Lee's avatar
Jeffrey Lee committed
1553 1554 1555
 [ HiProcVecs
        ; Map in DebuggerSpace
        LDR     a1, =DebuggerSpace
1556
        LDR     a2, =AreaFlags_DebuggerSpace
Jeffrey Lee's avatar
Jeffrey Lee committed
1557
        LDR     a3, =(DebuggerSpace_Size + &FFF) :AND: &FFFFF000
1558
        BL      Init_MapInRAM_Clear_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
1559 1560
 ]

1561
 [ MinorL2PThack
1562 1563 1564 1565 1566 1567
; Allocate backing L2PT for application space
; Note that ranges must be 4M aligned, as AllocateL2PT only does individual
; (1M) sections, rather than 4 at a time, corresponding to a L2PT page. The
; following space is available for dynamic areas, and ChangeDyn.s will get
; upset if it sees only some out of a set of 4 section entries pointing to the
; L2PT page.
1568
        MOV     a1, #0
Kevin Bracey's avatar
Kevin Bracey committed
1569
        MOV     a2, #AplWorkMaxSize             ; Not quite right, but the whole thing's wrong anyway
1570
        ASSERT  AplWorkMaxSize :MOD: (4*1024*1024) = 0
1571
        BL      AllocateL2PT_$pt
1572 1573 1574
; And for the system heap. Sigh
        LDR     a1, =SysHeapAddress
        LDR     a2, =SysHeapMaxSize
1575 1576
        ASSERT  SysHeapAddress :MOD: (4*1024*1024) = 0
        ASSERT  SysHeapMaxSize :MOD: (4*1024*1024) = 0
1577
        BL      AllocateL2PT_$pt
1578 1579
 ]

1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
        STR     v2, [v8, #InitUsedEnd]

        ; Put InitDMABlock back into PhysRamTable
        Push    "v1-v7"
        ASSERT  InitDMAOffset = InitDMABlock+8
        ADD     v1, v8, #InitDMABlock
        LDMIA   v1, {v1-v3}
        ADD     v3, v3, #PhysRamTable
        ADD     v3, v3, v8
        ; Work out whether the block was removed or merely shrunk
        LDMDB   v3, {v4-v5}
1591 1592
        ADD     v6, v1, v2, LSR #12
        ADD     v7, v4, v5, LSR #12
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603
        STMDB   v3, {v1-v2}
        TEQ     v6, v7
        BEQ     %FT40                   ; End addresses match, it was shrunk
35
        LDMIA   v3, {v1-v2}             ; Shuffle following entries down
        STMIA   v3!, {v4-v5}
        MOV     v4, v1
        MOVS    v5, v2
        BNE     %BT35
40
        Pull    "v1-v7"
1604 1605 1606 1607 1608 1609 1610

        MSR     CPSR_c, #F32_bit+I32_bit+IRQ32_mode
        LDR     sp, =IRQSTK
        MSR     CPSR_c, #F32_bit+I32_bit+ABT32_mode
        LDR     sp, =ABTSTK
        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
        LDR     sp, =UNDSTK
1611
        MSR     CPSR_c, #F32_bit+SVC2632
1612 1613 1614 1615 1616 1617 1618
        LDR     sp, =SVCSTK

        BL      ConstructCAMfromPageTables

        MOV     a1, #4096
        STR     a1, [v8, #Page_Size]

1619
        BL      CountPageTablePages_$pt
1620

1621 1622
        BL      Count32bitPages

1623
        B       Continue_after_HALInit
1624 1625 1626

        LTORG

1627
CountPageTablePages_$pt ROUT
1628
        Entry
Jeffrey Lee's avatar
Jeffrey Lee committed
1629
        LDR     a1, =ZeroPage
Jeffrey Lee's avatar
Jeffrey Lee committed
1630
        LDR     a2, [a1, #CamEntriesPointer]
1631
        LDR     a3, [a1, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
1632
      [ ZeroPage <> 0
1633
        MOV     a1, #0
Jeffrey Lee's avatar
Jeffrey Lee committed
1634
      ]
1635
        ADD     a3, a3, #1
1636
        ADD     a4, a2, a3, LSL #CAM_EntrySizeLog2
1637
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1638 1639 1640 1641 1642 1643 1644 1645
        LDR     lr, =LL3PT
10      LDR     ip, [a4, #CAM_LogAddr-CAM_EntrySize]!
        SUB     ip, ip, lr
        CMP     ip, #8:SHL:20
        ADDLO   a1, a1, #4096
        TEQ     a4, a2
        BNE     %BT10
      |
1646
        ASSERT  (L2PT :AND: &3FFFFF) = 0
1647 1648 1649
        LDR     lr, =L2PT :SHR: 22
10      LDR     ip, [a4, #CAM_LogAddr-CAM_EntrySize]!
        TEQ     lr, ip, LSR #22
1650 1651 1652
        ADDEQ   a1, a1, #4096
        TEQ     a4, a2
        BNE     %BT10
Jeffrey Lee's avatar
Jeffrey Lee committed
1653
      ]
Jeffrey Lee's avatar
Jeffrey Lee committed
1654
        LDR     a2, =ZeroPage
Jeffrey Lee's avatar
Jeffrey Lee committed
1655
        STR     a1, [a2, #LxPTUsed]
1656
        EXIT
1657

1658 1659 1660 1661
; Allocate and map in some RAM.
;
; On entry:
;    a1 = logical address
Kevin Bracey's avatar
Kevin Bracey committed
1662
;    a2 = access permissions (see Init_MapIn)
1663
;    a3 = length (4K multiple)
1664
;    v1 -> current entry in PhysRamTable
1665
;    v2 = next physical address (page units)
1666 1667 1668 1669 1670 1671
;    v3 -> L1PT
;
; On exit:
;    a1 -> physical address of start of RAM (deduce the rest from PhysRamTable)
;
; No out of memory check...
1672
Init_MapInRAM_$pt ROUT
1673 1674 1675 1676 1677
        Push    "v4-v8,lr"
        MOV     v8, #-1
        MOV     v5, a3                          ; v5 = amount of memory required
        MOV     v6, a1                          ; v6 = logical address
        MOV     v7, a2                          ; v7 = access permissions
1678 1679
10      LDMIA   v1, {v4, ip}                    ; v4 = addr of bank, ip = len+flags
        MOV     ip, ip, LSR #12
1680
        SUB     v4, v2, v4                      ; v4 = amount of bank used
1681
        RSBS    v4, v4, ip                      ; v4 = amount of bank left (pages)
1682 1683 1684 1685 1686 1687
        LDREQ   v2, [v1, #8]!                   ; move to next bank if 0 left
        BEQ     %BT10

        CMP     v8, #-1                         ; is this the first bank?
        MOVEQ   v8, v2                          ; remember it

1688
        CMP     v4, v5, LSR #12                 ; sufficient in this bank?
1689
        MOVHS   a4, v5
1690
        MOVLO   a4, v4, LSL #12                 ; a4 = amount to take
1691

1692
        MOV     a1, v2, LSL #12                 ; set up parameters for MapIn call
1693 1694
        MOV     a2, v6                          ; then move globals (in case MapIn
        MOV     a3, v7                          ; needs to allocate for L2PT)
1695
        ADD     v2, v2, a4, LSR #12             ; advance physaddr
1696
        SUB     v5, v5, a4                      ; decrease wanted
1697
        ADD     v6, v6, a4                      ; advance log address pointer
1698
        BL      Init_MapIn_$pt                  ; map in the RAM
1699 1700 1701 1702 1703 1704
        TEQ     v5, #0                          ; more memory still required?
        BNE     %BT10

        MOV     a1, v8
        Pull    "v4-v8,pc"

1705
Init_MapInRAM_Clear_$pt ROUT                    ; same as Init_MapInRAM but also
1706
        Push    "a1,a3,v5,lr"                   ; clears the mapped in result
1707
        BL      Init_MapInRAM_$pt
1708 1709 1710 1711 1712 1713 1714
        MOV     v5, a1
        Pull    "a1,a3"
        MOV     a2, #0
        BL      memset
        MOV     a1, v5
        Pull    "v5,pc"

1715 1716 1717 1718 1719 1720 1721
; Allocate and map a physically contigous chunk of some DMAable RAM.
;
; On entry:
;    a1 = logical address
;    a2 = access permissions (see Init_MapIn)
;    a3 = length (4K multiple)
;    v1 -> current entry in PhysRamTable
1722
;    v2 = next physical address (page units)
1723 1724 1725 1726 1727 1728 1729
;    v3 -> L1PT
;
; On exit:
;    a1 -> physical address of start of RAM (deduce the rest from PhysRamTable)
;
; Use this routine with caution - correct total amount of required DMA memory
; must have been calculated beforehand and stashed in InitDMABlock
1730
Init_MapInRAM_DMA_$pt ROUT
1731 1732 1733
        Push    "a1,a3,v4-v5,ip,lr"
        TEQ     v3, #0                          ; MMU on?
        LDREQ   v4, =ZeroPage                   ; get workspace directly
Jeffrey Lee's avatar
Jeffrey Lee committed
1734
        ADDNE   v4, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables ; deduce from L1PT
1735 1736 1737 1738 1739 1740 1741 1742
        LDR     v5, [v4, #InitDMAEnd]
        ADD     lr, v5, a3                      ; claim the RAM
        STR     lr, [v4, #InitDMAEnd]

        MOV     a4, a3
        MOV     a3, a2
        MOV     a2, a1
        MOV     a1, v5
1743
        BL      Init_MapIn_$pt                  ; map it in
1744
        ; DMA regions won't get cleared by ClearWkspRam, so do it manually
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
        ; Could potentially skip this if the HAL says RAM is already clear, but
        ; for now do it anyway (especially since startup flags haven't been set
        ; when we're first called)
        Pull    "a1,a3"
        TEQ     v3, #0
        MOVNE   a1, v5
        MOV     a2, #0
        BL      memset
        MOV     a1, v5
        Pull    "v4-v5,ip,pc"

1756 1757 1758
; Map a range of physical addresses to a range of logical addresses.
;
; On entry:
1759
;    a1 = physical address (32bit)
1760
;    a2 = logical address
1761
;    a3 = DA flags
1762
;    a4 = area size (4K multiple)
1763
;    v1 -> current entry in PhysRamTable
1764
;    v2 = last used physical address (page units)
1765 1766
;    v3 -> L1PT (or 0 if MMU on)

1767
Init_MapIn_$pt ROUT
1768 1769 1770 1771 1772 1773 1774 1775
        Entry   "v4-v7"
        MOV     v4, a1                          ; v4 = physaddr
        MOV     v5, a2                          ; v5 = logaddr
        MOV     v6, a3                          ; v6 = page flags
        MOV     v7, a4                          ; v7 = area size
        ; Set up a2-a4 for the Get*PTE functions
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
Jeffrey Lee's avatar
Jeffrey Lee committed
1776
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables
1777 1778 1779 1780 1781 1782
        MOV     a2, v6
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]

        ORR     lr, v4, v5                      ; OR together, physaddr, logaddr
        ORR     lr, lr, v7                      ; and size.
1783
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1784 1785 1786
        MOVS    ip, lr, LSL #11                 ; If all bottom 21 bits 0
        BEQ     %FT50                           ; it's L2PT block mapped
      |
1787
        MOVS    ip, lr, LSL #12                 ; If all bottom 20 bits 0
1788
        BEQ     %FT50                           ; it's section mapped
Jeffrey Lee's avatar
Jeffrey Lee committed
1789
      ]
1790 1791

        MOV     a1, #0                          ; We don't want the address in the result
1792

Kevin Bracey's avatar
Kevin Bracey committed
1793
        MOVS    ip, lr, LSL #16                 ; If bottom 16 bits not all 0
1794 1795 1796 1797 1798
        BEQ     %FT05
        PTOp    Get4KPTE                        ; then small pages (4K)
        B       %FT10
05
        PTOp    Get64KPTE                       ; else large pages (64K)
Kevin Bracey's avatar
Kevin Bracey committed
1799
10
1800
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1801 1802
        ORR     v6, a1, a2                      ; v6 = high & low attributes
      |
1803
        MOV     v6, a1                          ; v6 = access permissions
Jeffrey Lee's avatar
Jeffrey Lee committed
1804
      ]
1805 1806 1807 1808

20      MOV     a1, v4
        MOV     a2, v5
        MOV     a3, v6
1809
        BL      Init_MapInPage_$pt              ; Loop through mapping in each
1810 1811 1812 1813
        ADD     v4, v4, #4096                   ; page in turn
        ADD     v5, v5, #4096
        SUBS    v7, v7, #4096
        BNE     %BT20
1814
        EXIT
1815

1816
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1817
50
1818
        BL      Get2MPTE_LongDesc
Jeffrey Lee's avatar
Jeffrey Lee committed
1819 1820 1821 1822 1823 1824 1825 1826 1827
        MOVS    ip, v3                          ; is MMU on?
        LDREQ   ip, =LL2PT                      ; then use virtual address
        ADD     a3, ip, v5, LSR #18             ; a2 -> L2PT entry
70      STRD    a1, [a3], #8                    ; And store in L2PT
        ADD     a1, a1, #2*1024*1024            ; Advance two megabytes
        SUBS    v7, v7, #2*1024*1024            ; and loop
        BNE     %BT70
        EXIT
      |
1828
50
1829
        BL      Get1MPTE_ShortDesc
1830 1831
        MOVS    ip, v3                          ; is MMU on?
        LDREQ   ip, =L1PT                       ; then use virtual address
1832
        ADD     a2, ip, v5, LSR #18             ; a2 -> L1PT entry
1833 1834
70      STR     a1, [a2], #4                    ; And store in L1PT
        ADD     a1, a1, #1024*1024              ; Advance one megabyte
1835
        SUBS    v7, v7, #1024*1024              ; and loop
1836
        BNE     %BT70
1837
        EXIT
Jeffrey Lee's avatar
Jeffrey Lee committed
1838
      ]
1839 1840 1841 1842

; Map a logical page to a physical page, allocating L2PT as necessary.
;
; On entry:
1843
;    a1 = physical address (32bit)
1844
;    a2 = logical address
Jeffrey Lee's avatar
Jeffrey Lee committed
1845 1846 1847
 [ LongDesc
;    a3 = high & low page attributes merged into one word
 |
Kevin Bracey's avatar
Kevin Bracey committed
1848
;    a3 = access permissions + C + B bits + size (all non-address bits, of appropriate type)
Jeffrey Lee's avatar
Jeffrey Lee committed
1849
 ]
1850
;    v1 -> current entry in PhysRamTable
1851
;    v2 = last used physical address (page units)
1852 1853 1854 1855 1856
;    v3 -> L1PT (or 0 if MMU on)
; On exit:
;    a1 = logical address
;    a2-a4, ip corrupt
;    v1, v2 updated
Kevin Bracey's avatar
Kevin Bracey committed
1857
;
1858

1859
Init_MapInPage_$pt  ROUT
1860
        Entry   "v4-v6"
1861 1862 1863 1864 1865
        MOV     v4, a1                          ; v4 = physical address
        MOV     v5, a2                          ; v5 = logical address
        MOV     v6, a3                          ; v6 = access permissions
        MOV     a1, v5
        MOV     a2, #4096
1866
        BL      AllocateL2PT_$pt
1867
        TEQ     v3, #0                          ; if MMU on, access L2PT virtually...
1868
      [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
        LDREQ   a1, =LL3PT
        MOVEQ   ip, v5                          ; index using whole address
        BEQ     %FT40
        MOV     ip, v5, LSR #21
        ADD     a1, v3, ip, LSL #3
        LDRD    a1, [a1]                        ; a1 = level two descriptor
        BFC     a1, #0, #LL_LowAddr_Start       ; a1 -> L3PT tables for this section
        MOV     ip, v5, LSL #32-(12+9)
        MOV     ip, ip, LSR #32-(12+9)          ; extract L3 table index bits
40      MOV     a3, v4
        BFI     a3, v6, #0, #LL_LowAddr_Start   ; Add low attributes
        MOV     a4, v6
        BFC     a4, #0, #LL_HighAttr_Start      ; High attributes
        ADD     a1, a1, ip, LSR #9
        STRD    a3, [a1]                        ; update L3PT entry
        MOV     a1, v5
        EXIT
      |
1887 1888 1889 1890 1891 1892 1893 1894
        LDREQ   a1, =L2PT                       ; a1 -> L2PT virtual address
        MOVEQ   ip, v5                          ; index using whole address
        BEQ     %FT40
        MOV     ip, v5, LSR #20
        LDR     a1, [v3, ip, LSL #2]            ; a1 = level one descriptor
        MOV     a1, a1, LSR #10
        MOV     a1, a1, LSL #10                 ; a1 -> L2PT tables for this section
        AND     ip, v5, #&000FF000              ; extract L2 table index bits
Kevin Bracey's avatar
Kevin Bracey committed
1895 1896
40      AND     lr, v6, #3
        TEQ     lr, #L2_LargePage               ; strip out surplus address bits from
1897 1898
        BICEQ   v4, v4, #&0000F000              ; large page descriptors
        ORR     lr, v4, v6                      ; lr = value for L2PT entry
1899 1900
        STR     lr, [a1, ip, LSR #10]           ; update L2PT entry
        MOV     a1, v5
1901
        EXIT
Jeffrey Lee's avatar
Jeffrey Lee committed
1902
      ]
1903 1904 1905 1906 1907 1908 1909



; On entry:
;    a1 = virtual address L2PT required for
;    a2 = number of bytes of virtual space
;    v1 -> current entry in PhysRamTable
1910
;    v2 = last used physical address (page units)
1911 1912 1913 1914
;    v3 -> L1PT (or 0 if MMU on)
; On exit
;    a1-a4,ip corrupt
;    v1, v2 updated
1915 1916
AllocateL2PT_$pt ROUT
 [ pt = "LongDesc"
Jeffrey Lee's avatar
Jeffrey Lee committed
1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
        Entry   "v4-v8"
        MOV     v8, a1, LSR #21                 ; round base address down to 2M
        ADD     lr, a1, a2
        MOV     v7, lr, LSR #21
        TEQ     lr, v7, LSL #21
        ADDNE   v7, v7, #1                      ; round end address up to 2M

        MOVS    v6, v3
        LDREQ   v6, =LL2PT                      ; v6->L2PT (whole routine)

05      ADD     a3, v6, v8, LSL #3              ; L2PT contains 1 entry per 2MB
        LDRD    a1, [a3]
        TEQ     a1, #0                          ; if non-zero, the L3PT has
        BNE     %FT40                           ; already been allocated
        ; With 8 bytes per entry, every 4KB L3PT covers 2MB of RAM, the same
        ; as the single L2PT entry covers. So no need to deal with partially
        ; used pages like the short descriptor case.
        BL      Init_ClaimPhysicalPage          ; Claim a page to put L3PT in
        MOV     v4, a1

; Need to zero the L3PT. Must do it before calling in MapInPage, as that may well
; want to put something in the thing we are clearing. If the MMU is off, no problem,
; but if the MMU is on, then the L3PT isn't accessible until we've called MapInPage.
; Solution is to use the AccessPhysicalAddress call.

        TEQ     v3, #0                          ; MMU on?
        MOVNE   a1, v4                          ; if not, just access v4
        LDREQ   a1, =OSAP_None+DynAreaFlags_NotCacheable ; if so, map in v4
        MOVEQ   a2, v4
        SUBEQ   sp, sp, #4
        MOVEQ   a3, #0
        MOVEQ   a4, sp
1949
        PTOpEQ  AccessPhysicalAddress
Jeffrey Lee's avatar
Jeffrey Lee committed
1950 1951 1952 1953 1954 1955 1956

        MOV     a2, #0
        MOV     a3, #4*1024
        BL      memset

        TEQ     v3, #0
        LDREQ   a1, [sp], #4
1957
        PTOpEQ  ReleasePhysicalAddress
Jeffrey Lee's avatar
Jeffrey Lee committed
1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972

        ; Fill in the L2PT entry
        ORR     a1, v4, #LL12_Table
        MOV     a2, #0
        ADD     a3, v6, v8, LSL #3
        STRD    a1, [a3]

        ; Get the correct page table entry flags for Init_MapInPage
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables
        LDR     a2, [a3, #PageTable_PageFlags]
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]
        MOV     a1, #0
1973
        BL      Get4KPTE_LongDesc
Jeffrey Lee's avatar
Jeffrey Lee committed
1974 1975 1976 1977 1978

        ORR     a3, a1, a2
        MOV     a1, v4                          ; Map in the L3PT page itself
        LDR     a2, =LL3PT                      ; (can't recurse, because L3PT
        ADD     a2, a2, v8, LSL #12             ; backing for L3PT is preallocated)
1979
        BL      Init_MapInPage_$pt
Jeffrey Lee's avatar
Jeffrey Lee committed
1980 1981 1982 1983 1984 1985 1986 1987


40      ADD     v8, v8, #1                      ; go back until all
        CMP     v8, v7                          ; pages allocated
        BLO     %BT05

        EXIT
 |
1988
        Entry   "v4-v8"
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
        MOV     v8, a1, LSR #20                 ; round base address down to 1M
        ADD     lr, a1, a2
        MOV     v7, lr, LSR #20
        TEQ     lr, v7, LSL #20
        ADDNE   v7, v7, #1                      ; round end address up to 1M

        MOVS    v6, v3
        LDREQ   v6, =L1PT                       ; v6->L1PT (whole routine)

05      LDR     v5, [v6, v8, LSL #2]            ; L1PT contains 1 word per M
        TEQ     v5, #0                          ; if non-zero, the L2PT has
                                                ; already been allocated
        BNE     %FT40

        BIC     lr, v8, #3                      ; round down to 4M - each page
        ADD     lr, v6, lr, LSL #2              ; of L2PT maps to 4 sections
        LDMIA   lr, {a3,a4,v5,ip}               ; check if any are page mapped
        ASSERT  L1_Fault = 2_00 :LAND: L1_Page = 2_01 :LAND: L1_Section = 2_10
        TST     a3, #1
        TSTEQ   a4, #1
        TSTEQ   v5, #1
        TSTEQ   ip, #1
        BEQ     %FT20                           ; nothing page mapped - claim a page

        TST     a4, #1                          ; at least one of the sections is page mapped
        SUBNE   a3, a4, #1*1024                 ; find out where it's pointing to and
        TST     v5, #1                          ; derive the corresponding address for our
        SUBNE   a3, v5, #2*1024                 ; section
        TST     ip, #1
        SUBNE   a3, ip, #3*1024

        AND     lr, v8, #3
        ORR     a3, a3, lr, LSL #10
        STR     a3, [v6, v8, LSL #2]            ; fill in the L1PT entry
        B       %FT40                           ; no more to do

20      BL      Init_ClaimPhysicalPage          ; Claim a page to put L2PT in
        MOV     v4, a1

2028 2029 2030 2031 2032 2033 2034
; Need to zero the L2PT. Must do it before calling in MapInPage, as that may well
; want to put something in the thing we are clearing. If the MMU is off, no problem,
; but if the MMU is on, then the L2PT isn't accessible until we've called MapInPage.
; Solution is to use the AccessPhysicalAddress call.

        TEQ     v3, #0                          ; MMU on?
        MOVNE   a1, v4                          ; if not, just access v4
2035
        LDREQ   a1, =OSAP_None+DynAreaFlags_NotCacheable ; if so, map in v4
2036
        MOVEQ   a2, v4
2037
        SUBEQ   sp, sp, #4
2038 2039
        MOVEQ   a3, #0
        MOVEQ   a4, sp
2040
        PTOpEQ  AccessPhysicalAddress
2041 2042 2043 2044

        MOV     a2, #0
        MOV     a3, #4*1024
        BL      memset
2045

2046 2047
        TEQ     v3, #0
        LDREQ   a1, [sp], #4
2048
        PTOpEQ  ReleasePhysicalAddress
2049

Jeffrey Lee's avatar
Jeffrey Lee committed
2050 2051 2052 2053 2054 2055 2056 2057 2058
      [ MEMM_Type = "VMSAv6"
        ORR     a3, v4, #L1_Page
      |
        ORR     a3, v4, #L1_Page + L1_U         ; Set the U bit for ARM6 (assume L2 pages will generally be cacheable)
      ]
        AND     lr, v8, #3
        ORR     a3, a3, lr, LSL #10
        STR     a3, [v6, v8, LSL #2]            ; fill in the L1PT

2059 2060 2061
        ; Get the correct page table entry flags for Init_MapInPage
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
Jeffrey Lee's avatar
Jeffrey Lee committed
2062
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_PageTables
2063
        LDR     a2, [a3, #PageTable_PageFlags]
2064 2065 2066
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]
        MOV     a1, #0
2067
        BL      Get4KPTE_ShortDesc
2068 2069

        MOV     a3, a1
2070
        MOV     a1, v4                          ; Map in the L2PT page itself
2071 2072
        LDR     a2, =L2PT                       ; (can't recurse, because L2PT
        ADD     a2, a2, v8, LSL #10             ; backing for L2PT is preallocated)
2073
        BIC     a2, a2, #&C00
2074
        BL      Init_MapInPage_$pt
2075

2076

2077 2078 2079 2080
40      ADD     v8, v8, #1                      ; go back until all
        CMP     v8, v7                          ; pages allocated
        BLO     %BT05

2081
        EXIT
Jeffrey Lee's avatar
Jeffrey Lee committed
2082
 ]
2083

2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
; Called pre-MMU to set up some (temporary) PCBTrans and PPLTrans pointers,
; and the initial PageTable_PageFlags value
; Also used post-MMU for VMSAv6 case
; In:
;   a1 -> ZeroPage
; Out:
;   a1-a4, ip corrupt
Init_PCBTrans_$pt   ROUT
        LDR     a2, =AreaFlags_PageTablesAccess :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable
        STR     a2, [a1, #PageTable_PageFlags]
 [ MEMM_Type = "VMSAv6"
        ADRL    a2, PPLAccess_$pt
        STR     a2, [a1, #MMU_PPLAccess]
      [ pt = "LongDesc"
        ADRL    a2, XCBTableVMSAv6Long
        STR     a2, [a1, #MMU_PCBTrans]
        ADRL    a4, PPLTrans_LongDesc
        STR     a4, [a1, #MMU_PPLTrans]
      |
        ADRL    a2, XCBTableVMSAv6
        STR     a2, [a1, #MMU_PCBTrans]

        ; Use shareable pages if we're a multicore chip
        ; N.B. it's important that we get this correct - single-core chips may
        ; treat shareable memory as non-cacheable (e.g. ARM11)

        ADRL    a4, PPLTransNonShareable_ShortDesc
        ; Look at the cache type register to work out whether this is ARMv6 or ARMv7+
        MRC     p15, 0, a2, c0, c0, 1   ; Cache type register
        TST     a2, #1<<31              ; EQ = ARMv6, NE = ARMv7+
        MRC     p15, 0, a2, c0, c0, 5   ; MPIDR
        BNE     %FT50
        MRC     p15, 0, a3, c0, c0, 0   ; ARMv6: MPIDR is optional, so compare value against MIDR to see if it's implemented. There's no multiprocessing extensions flag so assume the check against MIDR will be good enough.
        TEQ     a2, a3
        ADDNE   a4, a4, #PPLTransShareable_ShortDesc-PPLTransNonShareable_ShortDesc
        B       %FT90
50
        AND     a2, a2, #&c0000000      ; ARMv7+: MPIDR is mandatory, but multicore not guaranteed. Check if multiprocessing extensions implemented (bit 31 set), and not uniprocessor (bit 30 clear).
        TEQ     a2, #&80000000
        ADDEQ   a4, a4, #PPLTransShareable_ShortDesc-PPLTransNonShareable_ShortDesc
90
        STR     a4, [a1, #MMU_PPLTrans]
      ]
 |
        ; Detecting the right PCBTrans table to use is complex
        ; However we know that, pre-MMU, we only use the default cache policy,
        ; and we don't use CNB memory
        ; So just go for a safe PCBTrans, like SA110, and the non-extended
        ; PPLTrans
        ADRL    a2, XCBTableSA110
        STR     a2, [a1, #MMU_PCBTrans]
        ADRL    a2, PPLTrans_ShortDesc
     [ ARM6support
        ARM_6   a3
        ADDEQ   a2, a2, #PPLTransARM6-PPLTrans_ShortDesc
     ]
        STR     a2, [a1, #MMU_PPLTrans]
 ]
        MOV     pc, lr
2143

2144
      ]
Jeffrey Lee's avatar
Jeffrey Lee committed
2145 2146 2147

        LTORG

2148 2149 2150
ptcounter SETA ptcounter + 1
        WEND
pt      SETS ""
2151

2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
 [ MEMM_Type = "VMSAv6"
HAL_InvalidateCache_ARMvF
        ; Cache invalidation for ARMs with multiple cache levels, used before ARMop initialisation
        ; This function gets called before we have a stack set up, so we've got to preserve as many registers as possible
        ; The only register we can safely change is ip, but we can switch into FIQ mode with interrupts disabled and use the banked registers there
        MRS     ip, CPSR
        MSR     CPSR_c, #F32_bit+I32_bit+FIQ32_mode
        MOV     r9, #0
        MCR     p15, 0, r9, c7, c5, 0           ; invalidate instruction cache
        MCR     p15, 0, r9, c8, c7, 0           ; invalidate TLBs
        MCR     p15, 0, r9, c7, c5, 6           ; invalidate branch target predictor
        myDSB   ,r9,,y                          ; Wait for completion
        myISB   ,r9,,y
        ; Check whether we're ARMv7 (and thus multi-level cache) or ARMv6 (and thus single-level cache)
        MRC     p15, 0, r8, c0, c0, 1
        TST     r8, #&80000000 ; EQ=ARMv6, NE=ARMv7
        BEQ     %FT80
2169

2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
        ; This is basically the same algorithm as the MaintainDataCache_WB_CR7_Lx macro, but tweaked to use less registers and to read from CP15 directly
        MRC     p15, 1, r8, c0, c0, 1           ; Read CLIDR to r8
        TST     r8, #&07000000
        BEQ     %FT50
        MOV     r11, #0 ; Current cache level
10 ; Loop1
        ADD     r10, r11, r11, LSR #1 ; Work out 3 x cachelevel
        MOV     r9, r8, LSR r10 ; bottom 3 bits are the Cache type for this level
        AND     r9, r9, #7 ; get those 3 bits alone
        CMP     r9, #2
        BLT     %FT40 ; no cache or only instruction cache at this level
        MCR     p15, 2, r11, c0, c0, 0 ; write CSSELR from r11
        ISB
        MRC     p15, 1, r9, c0, c0, 0 ; read current CSSIDR to r9
        AND     r10, r9, #CCSIDR_LineSize_mask ; extract the line length field
        ADD     r10, r10, #4 ; add 4 for the line length offset (log2 16 bytes)
        LDR     r8, =CCSIDR_Associativity_mask:SHR:CCSIDR_Associativity_pos
        AND     r8, r8, r9, LSR #CCSIDR_Associativity_pos ; r8 is the max number on the way size (right aligned)
        CLZ     r13, r8 ; r13 is the bit position of the way size increment
        LDR     r12, =CCSIDR_NumSets_mask:SHR:CCSIDR_NumSets_pos
        AND     r12, r12, r9, LSR #CCSIDR_NumSets_pos ; r12 is the max number of the index size (right aligned)
20 ; Loop2
        MOV     r9, r12 ; r9 working copy of the max index size (right aligned)
30 ; Loop3
        ORR     r14, r11, r8, LSL r13 ; factor in the way number and cache number into r14
        ORR     r14, r14, r9, LSL r10 ; factor in the index number
        DCISW   r14 ; Invalidate
        SUBS    r9, r9, #1 ; decrement the index
        BGE     %BT30
        SUBS    r8, r8, #1 ; decrement the way number
        BGE     %BT20
        DSB                ; Cortex-A7 errata 814220: DSB required when changing cache levels when using set/way operations. This also counts as our end-of-maintenance DSB.
        MRC     p15, 1, r8, c0, c0, 1
40 ; Skip
        ADD     r11, r11, #2
        AND     r14, r8, #&07000000
        CMP     r14, r11, LSL #23
        BGT     %BT10
2208

2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
50 ; Finished
        ; Wait for clean to complete
        MOV     r8, #0
        MCR     p15, 0, r8, c7, c5, 0           ; invalidate instruction cache
        MCR     p15, 0, r8, c8, c7, 0           ; invalidate TLBs
        MCR     p15, 0, r8, c7, c5, 6           ; invalidate branch target predictor
        myDSB   ,r8,,y                          ; Wait for completion
        myISB   ,r8,,y
        ; All caches clean; switch back to SVC, then recover the stored PSR from ip (although we can be fairly certain we started in SVC anyway)
        MSR     CPSR_c, #F32_bit+I32_bit+SVC32_mode
        MSR     CPSR_cxsf, ip
        MOV     pc, lr
80 ; ARMv6 case
        MCR     ARM_config_cp,0,r9,ARMv4_cache_reg,C7 ; ARMv3-ARMv6 I+D cache flush
        B       %BT50
 ] ; MEMM_Type = "VMSAv6"

; int PhysAddrToPageNo(uint64_t addr)
2227
;
2228 2229
; Converts a physical address to the page number of the page containing it.
; Returns -1 if address is not in RAM.
2230

2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245
PhysAddrToPageNo
        ; Convert address to 4K addressing
        MOV     a1, a1, LSR #12
        ORR     a1, a1, a2, LSL #20
        MOV     a4, #0
        LDR     ip, =ZeroPage + PhysRamTable
10      LDMIA   ip!, {a2, a3}                   ; get phys addr, size
        MOVS    a3, a3, LSR #12                 ; end of list? (size=0)
        BEQ     %FT90                           ;   then it ain't RAM
        SUB     a2, a1, a2                      ; a2 = amount into this bank
        CMP     a2, a3                          ; if more than size
        ADDHS   a4, a4, a3                      ;   increase counter by size of bank
        BHS     %BT10                           ;   and move to next
        ADD     a1, a4, a2                      ; add offset to counter
        MOV     pc, lr
2246

2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
90      MOV     a1, #-1
        MOV     pc, lr


; A routine to construct the soft CAM from the page tables. This is used
; after a soft reset, and also on a hard reset as it's an easy way of
; clearing up after the recursive page table allocaton.

        ROUT
ConstructCAMfromPageTables
        Push    "v1-v8, lr"
        LDR     a1, =ZeroPage
        LDR     a2, [a1, #MaxCamEntry]
        LDR     v1, [a1, #CamEntriesPointer]    ; v1 -> CAM (for whole routine)
        ADD     a2, a2, #1
        ADD     a2, v1, a2, LSL #CAM_EntrySizeLog2

        LDR     a3, =DuffEntry                  ; Clear the whole CAM, from
        MOV     a4, #AreaFlags_Duff             ; the top down.
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
        ASSERT  CAM_PMP=8
        ASSERT  CAM_PMPIndex=12
        ASSERT  CAM_EntrySize=16
        MOV     v2, #0
        MOV     v3, #-1
10      STMDB   a2!, {a3, a4, v2, v3}
        CMP     a2, v1
        BHI     %BT10
2276

2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
        MOV     v2, #0                          ; v2 = logical address
30      MOV     a1, v2
        PTOp    LoadAndDecodeL1Entry            ; a1,a2 = phys addr, a3 = page flags/type, a4 = page size (bytes)
        CMP     a3, #-2                         ; Only care about page table pointers
        BEQ     %FT39
        ADDS    v2, v2, a4
        BCC     %BT30
        Pull    "v1-v8, pc"

39      ADD     v7, v2, a4
40      MOV     a1, v2
        PTOp    LoadAndDecodeL2Entry            ; a1,a2 = phys addr, a3 = flags (-1 if fault), a4 = page size (bytes)
        CMP     a3, #-1                         ; move to next page if fault
        BEQ     %FT80
        SUBS    a4, a4, #4096                   ; large pages get bits 12-15 from the virtual address
        ANDNE   lr, v2, a4
        ORR     v6, a3, #PageFlags_Unavailable
        ORRNE   a1, a1, lr
        BL      PhysAddrToPageNo                ; -1 if unknown page
        ADDS    a1, v1, a1, LSL #CAM_EntrySizeLog2 ; a1 -> CAM entry
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
        STMCCIA a1, {v2, v6}                    ; store logical address, PPL

80      ADDS    v2, v2, #&00001000              ; always advance in 4K units here
        TEQ     v2, v7
        BNE     %BT40                           ; more to do from this L1 entry
        BCC     %BT30                           ; logical address not wrapped yet

        Pull    "v1-v8, pc"



; Allocate a physical page from DRAM
2311
;
2312 2313 2314 2315 2316 2317
; On entry:
;    v1 -> current entry in PhysRamTable
;    v2 -> end of last used physical page (page units)
; On exit:
;    a1 -> next free page (assumed 32bit address)
;    v1, v2 updated
2318
;
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333
; No out of memory check...

Init_ClaimPhysicalPage
        MOV     a1, v2
        LDMIA   v1, {a2, a3}
        ADD     a2, a2, a3, LSR #12             ; a2 = end of this bank
        CMP     v2, a2                          ; advance v2 to next bank if
        LDRHS   a1, [v1, #8]!                   ; this bank is fully used
        ADD     v2, a1, #1
        MOV     a1, a1, LSL #12                 ; Convert to byte address
        MOV     pc, lr

Count32bitPages ROUT
        LDR     a1, =ZeroPage
        LDR     a2, [a1, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
2334
      [ LongDesc
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352
        ; ~64bit RAM addresses supported, examine PhysRamTable to determine
        ; the last page number with a 32bit address
        Entry
        MOV     a3, #-1
        ADD     a4, a1, #PhysRamTable
10
        LDMIA   a4!, {ip, lr}
        CMP     ip, #1:SHL:20                   ; Address below 4G?
        ADDLO   a3, a3, lr, LSR #12             ; Count it up
        CMPLO   a3, a2                          ; Don't overrun the table
        BLO     %BT10
        STR     a3, [a1, #MaxCamEntry32]
        ; Update ProcessorFlags
        CMP     a2, a3
        LDRNE   a2, [a1, #ProcessorFlags]
        ORRNE   a2, a2, #CPUFlag_HighRAM
        STRNE   a2, [a1, #ProcessorFlags]
        EXIT
Jeffrey Lee's avatar
Jeffrey Lee committed
2353
      |
2354 2355 2356
        ; No 64bit support, so all pages must have 32bit addresses
        STR     a2, [a1, #MaxCamEntry32]
        MOV     pc, lr
Jeffrey Lee's avatar
Jeffrey Lee committed
2357
      ]
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372

        ; in:  ip = ZeroPage
        ; out: v3 = PhysIllegalMask
DeterminePhysIllegalMask
        Push    "lr"
        MOV     v3, #&FFFFFFFF         ; By default any upper bits are illegal
        ARM_read_ID lr
        AND     lr, lr, #&F :SHL: 16
        CMP     lr, #ARMvF :SHL: 16    ; Check that feature registers are implemented
        BNE     %FT01                  ; Some ARMv5 chips supported supersections, but let's not worry about them
        MRC     p15, 0, lr, c0, c1, 7  ; ID_MMFR3
        TST     lr, #&F :SHL: 28
        MOVEQ   v3, #&FFFFFF00
01      STR     v3, [ip, #PhysIllegalMask]
        Pull    "pc"
2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386


; void Init_PageTablesChanged(void)
;
; A TLB+cache invalidation that works on all known ARMs. Invalidate all I+D TLB is the _only_ TLB
; op that works on ARM720T, ARM920T and SA110. Ditto invalidate all I+D cache.
;
; DOES NOT CLEAN THE DATA CACHE. This is a helpful simplification, but requires that don't use
; this routine after we've started using normal RAM.
;
Init_PageTablesChanged
        MOV     a3, lr
        BL      Init_ARMarch
        MOV     ip, #0
Ben Avison's avatar
Ben Avison committed
2387
        BNE     %FT01
2388
        MCREQ   ARM_config_cp,0,ip,ARMv3_TLBflush_reg,C0
Ben Avison's avatar
Ben Avison committed
2389 2390 2391
        B       %FT02
01      MCRNE   ARM_config_cp,0,ip,ARMv4_TLB_reg,C7
02
2392
 [ MEMM_Type = "VMSAv6"
2393
        CMP     a1, #ARMvF
Ben Avison's avatar
Ben Avison committed
2394 2395
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
2396
        MCRNE   ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
Ben Avison's avatar
Ben Avison committed
2397
01
2398 2399 2400
 |
        MCR     ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
 ]
2401 2402 2403 2404 2405
        MOV     pc, a3


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
2406
;       ClearWkspRAM - Routine to clear "all" workspace
2407
;
2408
; We have to avoid anything between InitUsedStart and InitUsedEnd - i.e.
2409 2410 2411 2412 2413
; the page tables, HAL workspace, etc.
;
; Note that zero page workspace isn't included in InitUsedStart/InitUsedEnd.
; Sensitive areas of it (e.g. PhysRamTable, IRQ vector) are skipped via the
; help of RamSkipTable
2414 2415
;
; The bulk of RAM is cleared during the keyboard scan (ClearFreePoolSection).
2416 2417

;
2418
; out:  r4-r11, r13 preserved
2419 2420
;

2421
ClearWkspRAM ROUT
2422
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; get some extra registers
2423 2424 2425 2426 2427 2428 2429
        MOV     r8, #0
        MOV     r9, #0
        MOV     r10, #0
        MOV     r11, #0
        MOV     r12, #0
        MOV     r13, #0
        MOV     r14, #0
2430
        MSR     CPSR_c, #F32_bit+SVC32_mode
2431

2432
        LDR     r0,=ZeroPage+InitClearRamWs             ;we can preserve r4-r11,lr in one of the skipped regions
2433
        STMIA   r0,{r4-r11,lr}
2434

2435
        DebugTX "ClearWkspRAM"
2436

2437 2438 2439 2440 2441
        ; Start off by clearing zero page + scratch space, as these:
        ; (a) are already mapped in and
        ; (b) may require the use of the skip table
        LDR     r0, =ZeroPage
        ADD     r1, r0, #16*1024
2442
        ADR     r6, RamSkipTable
2443 2444
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; switch to our bank o'zeros
        LDR     r5, [r6], #4                            ; load first skip addr
2445
10
2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
        TEQ     r0, r1
        TEQNE   r0, r5
        STMNEIA r0!, {r8-r11}
        BNE     %BT10
        TEQ     r0, r1
        BEQ     %FT20
        LDR     r5, [r6], #4                            ; load skip amount
        ADD     r0, r0, r5                              ; and skip it
        LDR     r5, [r6], #4                            ; load next skip addr
        B       %BT10
20
        LDR     r0, =ScratchSpace
        ADD     r1, r0, #ScratchSpaceSize
30
        TEQ     r0, r1
        STMNEIA r0!, {r8-r11}
        STMNEIA r0!, {r8-r11}
        BNE     %BT30
2464

2465
        MSR     CPSR_c, #F32_bit+SVC32_mode
2466

Jeffrey Lee's avatar
Jeffrey Lee committed
2467
        LDR     r0, =ZeroPage+InitClearRamWs
2468
        LDMIA   r0, {r4-r11,r14}                        ;restore
2469

2470
      [ {FALSE} ; NewReset sets this later
Jeffrey Lee's avatar
Jeffrey Lee committed
2471
        LDR     r0, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
2472 2473
        MOV     r1, #&80
        STRB    r1, [r0]                                ; flag the fact that RAM cleared
2474
      ]
2475 2476 2477 2478 2479 2480

        MOV     pc, lr

        LTORG

        MACRO
2481
        MakeSkipTable $addr, $size
2482 2483 2484
        ASSERT  ($addr :AND: 15) = 0
        ASSERT  ($size :AND: 15) = 0
        ASSERT  ($addr-ZeroPage) < 16*1024
2485
        &       $addr, $size
2486 2487 2488 2489 2490 2491 2492 2493
        MEND

        MACRO
        EndSkipTables
        &       -1
        MEND

RamSkipTable
2494 2495
        MakeSkipTable   ZeroPage, InitWsEnd
        MakeSkipTable   ZeroPage+SkippedTables, SkippedTablesEnd-SkippedTables
2496 2497
        EndSkipTables

2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ClearFreePoolSection - Routine to clear a section of the free pool
;
; During keyboard scanning we soak up slack time clearing the bulk of RAM
; by picking a section of the free pool, mapping it in, clearing & flushing.

;
; In:   r0 = CAM entry to continue from
; Out:  r0 = updated
;

ClearFreePoolSection ROUT
        Push    "r1-r3, lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
2512 2513
        LDR     r3, =ZeroPage
        LDR     r1, [r3, #MaxCamEntry]
2514 2515 2516 2517
        LDR     r2, =ZeroPage+FreePoolDANode
        CMP     r0, r1
        BHI     %FT30

Jeffrey Lee's avatar
Jeffrey Lee committed
2518
        LDR     r3, [r3, #CamEntriesPointer]
2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542
        ADD     r1, r3, r1, LSL #CAM_EntrySizeLog2      ; top entry (inc)
        ADD     r3, r3, r0, LSL #CAM_EntrySizeLog2      ; starting entry
10
        LDR     r14, [r3, #CAM_PageFlags]
        TST     r14, #DynAreaFlags_PMP
        BEQ     %FT20

        LDR     r14, [r3, #CAM_PMP]
        TEQ     r14, r2
        BEQ     %FT40
20
        ADD     r3, r3, #CAM_EntrySize                  ; next
        CMP     r3, r1
        BLS     %BT10
30
        MOV     r0, #-1
        Pull    "r1-r3, pc"
40
        Push    "r0-r12"

        ; This is a PMP entry in the free pool
        LDR     r14, [r3, #CAM_PMPIndex]                ; list index
        LDR     r9, [r2, #DANode_PMP]                   ; PMP list base
        LDR     r3, [r9, r14, LSL #2]                   ; ppn
2543
        BL      ppn_to_physical                         ; => r8,r9 = PA
2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554

      [ MEMM_Type = "ARM600"
        ; Map in this section, cacheable + bufferable to ensure burst writes
        ; are performed (StrongARM will only perform burst writes to CB areas)
        MOV     a1, #OSAP_None
      |
        ; Map in this section with default NCB cache policy. Making it cacheable
        ; is liable to slow things down significantly on some platforms (e.g.
        ; PL310 L2 cache)
        LDR     a1, =OSAP_None + DynAreaFlags_NotCacheable
      ]
2555 2556
        MOV     a2, r8
        MOV     a3, r9
2557
        MOV     a4, #0
2558
        PTOp    AccessPhysicalAddress
2559

2560 2561 2562
        MOV     r5, r8, LSR #20
        ORR     r5, r5, r9, LSL #12                     ; r5 = physical MB

2563 2564 2565 2566 2567
        MOV     r4, #0                                  ; clear to this value
        MOV     r6, r4
        MOV     r7, r4
        MOV     r12, r4
45
2568
        MOV     r8, r4
2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580
        MOV     r9, r4
        MOV     r10, r4
        MOV     r11, r4

        ; Fill that page
        ADD     r2, r0, #4096
50
        STMIA   r0!, {r4,r6-r12}
        STMIA   r0!, {r4,r6-r12}
        TEQ     r0, r2
        BNE     %BT50

2581 2582
        MOV     r10, r5                                 ; previous phys MB

2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
        ; Step the CAM until there are no more pages in that section
        LDR     r1, [sp, #1*4]
        LDR     r2, [sp, #2*4]
        LDR     r11, [sp, #3*4]
        B       %FT65
60
        LDR     r14, [r11, #CAM_PageFlags]
        TST     r14, #DynAreaFlags_PMP
        BEQ     %FT65

        LDR     r14, [r11, #CAM_PMP]
        TEQ     r14, r2
        BEQ     %FT70
65
        ADD     r11, r11, #CAM_EntrySize                ; next
        CMP     r11, r1
        BLS     %BT60

        MOV     r14, #-1                                ; CAM top, no more
        B       %FT80
70

        ; Next PMP entry in the free pool
        LDR     r14, [r11, #CAM_PMPIndex]               ; list index
        LDR     r9, [r2, #DANode_PMP]                   ; PMP list base
        LDR     r3, [r9, r14, LSL #2]                   ; ppn
2609
        BL      ppn_to_physical                         ; => r8,r9 = PA
2610

2611 2612 2613
        MOV     r5, r8, LSR #20
        ORR     r5, r5, r9, LSL #12
        TEQ     r10, r5                                 ; same MB as previous?
Jeffrey Lee's avatar
Jeffrey Lee committed
2614 2615
        LDRNE   r14, =ZeroPage
        LDRNE   r14, [r14, #CamEntriesPointer]
2616 2617
        SUBNE   r14, r11, r14
        MOVNE   r14, r14, LSR #CAM_EntrySizeLog2        ; no, so compute continuation point
2618 2619 2620 2621 2622 2623 2624 2625
        SUBEQ   r0, r0, #4                              ; wind back to make sure we stay in the correct megabyte of PhysicalAccess
      [ NoARMT2
        MOVEQ   r0, r0, LSR #20
        ORREQ   r0, r0, r8, LSL #12
        MOVEQ   r0, r0, ROR #12
      |
        BFIEQ   r0, r8, #0, #20
      ]
2626 2627 2628 2629 2630 2631 2632 2633 2634
        STREQ   r11, [sp, #3*4]
        BEQ     %BT45                                   ; yes, so clear it
80
        STR     r14, [sp, #0*4]                         ; return value for continuation

 [ MEMM_Type = "ARM600" ; VMSAv6 maps as non-cacheable, so no flush required
        ; Make page uncacheable so the following is safe
        MOV     r4, r0

2635
        LDR     r0, =OSAP_None+DynAreaFlags_NotCacheable
2636 2637
        MOV     r1, r10, LSL #20
        MOV     r2, r10, LSR #12
2638
        MOV     r3, #0
2639
        PTOp    AccessPhysicalAddress
2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663

        MOV     r0, r4

        ; Clean & invalidate the cache before the 1MB window closes
      [ CacheCleanerHack
        ; StrongARM requires special clean code, because we haven't mapped in
        ; DCacheCleanAddress yet. Cheat and only perform a clean, not full
        ; clean + invalidate (should be safe as we've only been writing)
        ARM_read_ID r2
        AND     r2, r2, #&F000
        CMP     r2, #&A000
        BNE     %FT90
85
        SUB     r0, r0, #32                             ; rewind 1 cache line
        ARMA_clean_DCentry r0
        MOVS    r1, r0, LSL #12                         ; start of the MB?
        BNE     %BT85
        B       %FT91
90
      ]
        ARMop Cache_CleanInvalidateAll
 ]
91
        MOV     a1, #L1_Fault
2664
        PTOp    ReleasePhysicalAddress                  ; reset to default
2665 2666 2667 2668

        Pull    "r0-r12"

        Pull    "r1-r3, pc"
2669 2670 2671 2672 2673 2674 2675 2676

InitProcVecs
        BKPT    &C000                                   ; Reset
        BKPT    &C004                                   ; Undefined Instruction
        BKPT    &C008                                   ; SWI
        BKPT    &C00C                                   ; Prefetch Abort
        SUBS    pc, lr, #4                              ; ignore data aborts
        BKPT    &C014                                   ; Address Exception
Kevin Bracey's avatar
Kevin Bracey committed
2677
        LDR     pc, InitProcVecs + InitIRQHandler       ; IRQ
2678 2679 2680 2681 2682
        BKPT    &C01C                                   ; FIQ
InitProcVec_FIQ
        DCD     0
InitProcVecsEnd

2683
; RISCOS_MapInIO flags
2684 2685
MapInFlag_DoublyMapped * 1:SHL:20
MapInFlag_APSpecified * 1:SHL:21
Kevin Bracey's avatar
Kevin Bracey committed
2686

2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705
      [ LongDesc :LAND: ShortDesc
; Dispatch for pagetable-specific MapInIO / MapInIO64 (mainly to handle calls
; from HAL via the OS header table)
RISCOS_MapInIO
        PTWhich  ip
        BNE      RISCOS_MapInIO_LongDesc
        B        RISCOS_MapInIO_ShortDesc

RISCOS_MapInIO64
        PTWhich  ip
        BNE      RISCOS_MapInIO64_LongDesc
        B        RISCOS_MapInIO64_ShortDesc
      ELIF LongDesc
RISCOS_MapInIO * RISCOS_MapInIO_LongDesc
RISCOS_MapInIO64 * RISCOS_MapInIO64_LongDesc
      |
RISCOS_MapInIO * RISCOS_MapInIO_ShortDesc
RISCOS_MapInIO64 * RISCOS_MapInIO64_ShortDesc
      ]
2706

Ben Avison's avatar
Ben Avison committed
2707 2708 2709 2710 2711
; void RISCOS_AddDevice(unsigned int flags, struct device *d)
RISCOS_AddDevice
        ADDS    a1, a2, #0      ; also clears V
        B       HardwareDeviceAdd_Common

2712
; uint64_t RISCOS_LogToPhys(const void *log)
2713
; Returns -1 for invalid addresses
Jeffrey Lee's avatar
Jeffrey Lee committed
2714 2715 2716
; Also returns page flags in r2 (for AbortTrap) and mapping size/alignment
; in r3 (for OS_Memory 65)
        EXPORT  RISCOS_LogToPhys
2717
RISCOS_LogToPhys ROUT
2718 2719
        Push    "lr"
        MOV     r12, a1
2720 2721
        MOV     r0, a1, LSR #20
        MOV     r0, r0, LSL #20
2722
        PTOp    LoadAndDecodeL1Entry
2723
        CMP     r2, #-2
2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
        BNE     %FT50
        ; L2 page table pointer. Because we've already checked L1PT, there
        ; shouldn't be any need for us to check if the relevant logical mapping
        ; of L2PT exists (like logical_to_physical does).
        MOV     r0, r12, LSR #12
        MOV     r0, r0, LSL #12
      [ AMB_LazyMapIn
        BL      AMB_MakeHonestLA
      ]
        PTOp    LoadAndDecodeL2Entry
        CMP     r2, #-2
50
        MOVHI   r0, #-1                ; Translation fault
        MOVHI   r1, #-1
        Pull    "pc",HI
        ; Valid mapping, add in the low address bits
Jeffrey Lee's avatar
Jeffrey Lee committed
2740 2741
        SUB     lr, r3, #1
        AND     r12, r12, lr
2742 2743
        ORR     r0, r0, r12
        Pull    "pc"
2744

Robert Sprowson's avatar
Robert Sprowson committed
2745 2746
; int RISCOS_IICOpV(IICDesc *descs, uint32_t ndesc_and_bus)
RISCOS_IICOpV ROUT
2747 2748
        Push    "lr"
        BL      IIC_OpV
Robert Sprowson's avatar
Robert Sprowson committed
2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
        MOVVC   a1, #IICStatus_Completed
        Pull    "pc", VC
        ; Map from RISC OS error numbers to abstract IICStatus return values
        LDR     a1, [a1]
        LDR     lr, =ErrorNumber_IIC_NoAcknowledge
        SUB     a1, a1, lr              ; 0/1/2 = NoAck/Error/Busy
        CMP     a1, #3
        MOVCS   a1, #3                  ; 3+ => unknown, either way it's an Error
        ADR     lr, %FT10
        LDRB    a1, [lr, a1]
2759
        Pull    "pc"
Robert Sprowson's avatar
Robert Sprowson committed
2760 2761 2762 2763 2764
10
        ASSERT    (ErrorNumber_IIC_Error - ErrorNumber_IIC_NoAcknowledge) = 1
        ASSERT    (ErrorNumber_IIC_Busy - ErrorNumber_IIC_NoAcknowledge) = 2
        DCB       IICStatus_NoACK, IICStatus_Error, IICStatus_Busy, IICStatus_Error
        ALIGN
Ben Avison's avatar
Ben Avison committed
2765

2766 2767 2768 2769 2770 2771 2772 2773
SetUpHALEntryTable ROUT
        LDR     a1, =ZeroPage
        LDR     a2, [a1, #HAL_Descriptor]
        LDR     a3, [a1, #HAL_Workspace]
        LDR     a4, [a2, #HALDesc_Entries]
        LDR     ip, [a2, #HALDesc_NumEntries]
        ADD     a4, a2, a4                              ; a4 -> entry table
        MOV     a2, a4                                  ; a2 -> entry table (increments)
2774 2775
10      SUBS    ip, ip, #1                              ; decrement counter
        LDRCS   a1, [a2], #4
2776
        BCC     %FT20
Kevin Bracey's avatar
Kevin Bracey committed
2777 2778 2779
        TEQ     a1, #0
        ADREQ   a1, NullHALEntry
        ADDNE   a1, a4, a1                              ; convert offset to absolute
2780
        STR     a1, [a3, #-4]!                          ; store backwards below HAL workspace
2781
        B       %BT10
2782 2783 2784 2785 2786 2787 2788 2789
20      LDR     a1, =ZeroPage                           ; pad table with NullHALEntries
        LDR     a4, =HALWorkspace                       ; in case where HAL didn't supply enough
        ADR     a1, NullHALEntry
30      CMP     a3, a4
        STRHI   a1, [a3, #-4]!
        BHI     %BT30
        MOV     pc, lr

2790

Kevin Bracey's avatar
Kevin Bracey committed
2791 2792 2793 2794 2795 2796
NullHALEntry
        MOV     pc, lr

; Can freely corrupt r10-r12 (v7,v8,ip).
HardwareSWI
        AND     ip, v5, #&FF
2797 2798 2799 2800 2801 2802 2803 2804

        CMP     ip, #OSHW_LookupRoutine
        ASSERT  OSHW_CallHAL < OSHW_LookupRoutine
        BLO     HardwareCallHAL
        BEQ     HardwareLookupRoutine

        CMP     ip, #OSHW_DeviceRemove
        ASSERT  OSHW_DeviceAdd < OSHW_DeviceRemove
Ben Avison's avatar
Ben Avison committed
2805 2806
        BLO     HardwareDeviceAdd
        BEQ     HardwareDeviceRemove
2807

Ben Avison's avatar
Ben Avison committed
2808 2809 2810
        CMP     ip, #OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerate < OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerateChrono < OSHW_MaxSubreason
Ben Avison's avatar
Ben Avison committed
2811
        BLO     HardwareDeviceEnumerate
Ben Avison's avatar
Ben Avison committed
2812 2813
        BEQ     HardwareDeviceEnumerateChrono
        BHI     HardwareBadReason
Kevin Bracey's avatar
Kevin Bracey committed
2814

2815
HardwareCallHAL
Kevin Bracey's avatar
Kevin Bracey committed
2816 2817
        Push    "v1-v4,sb,lr"
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2818
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2819 2820
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip                                   ; sb set up
2821
        LDR     v7, [v7, #HALDesc_NumEntries]           ; v7 = number of entries
Kevin Bracey's avatar
Kevin Bracey committed
2822
        CMP     v8, v7                                  ; entryno + 1 must be <= number of entries
2823
        BHI     HardwareBadEntry2
Kevin Bracey's avatar
Kevin Bracey committed
2824 2825 2826
        LDR     ip, [sb, -v8, LSL #2]
        ADR     v7, NullHALEntry
        TEQ     ip, v7
2827
        BEQ     HardwareBadEntry2
2828
      [ NoARMv5
Kevin Bracey's avatar
Kevin Bracey committed
2829 2830
        MOV     lr, pc
        MOV     pc, ip
2831 2832 2833
      |
        BLX     ip
      ]
Kevin Bracey's avatar
Kevin Bracey committed
2834 2835 2836 2837
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
        ExitSWIHandler

2838
HardwareLookupRoutine
Kevin Bracey's avatar
Kevin Bracey committed
2839
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2840
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2841 2842
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip
2843
        LDR     v7, [v7, #HALDesc_NumEntries]
Kevin Bracey's avatar
Kevin Bracey committed
2844 2845 2846 2847 2848 2849 2850 2851 2852
        CMP     v8, v7                                  ; entryno + 1 must be <= number of entries
        BHI     HardwareBadEntry
        LDR     a1, [sb, -v8, LSL #2]
        ADR     v7, NullHALEntry
        TEQ     a1, v7
        BEQ     HardwareBadEntry
        MOV     a2, sb
        ExitSWIHandler

Ben Avison's avatar
Ben Avison committed
2853
HardwareDeviceAdd
2854
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2855
        BL      HardwareDeviceAdd_Common
2856
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2857 2858 2859
        B       SLVK_TestV

HardwareDeviceRemove
2860
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2861
        BL      HardwareDeviceRemove_Common
2862
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2863 2864 2865
        B       SLVK_TestV

HardwareDeviceAdd_Common
2866
        Entry
Ben Avison's avatar
Ben Avison committed
2867 2868
        BL      HardwareDeviceRemove_Common             ; first try to remove any device already at the same address
        EXIT    VS
Jeffrey Lee's avatar
Jeffrey Lee committed
2869
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2870 2871 2872 2873
        LDR     r1, [lr, #DeviceCount]
        LDR     r2, [lr, #DeviceTable]
        TEQ     r2, #0
        BEQ     %FT80
2874 2875
        ADD     r1, r1, #1                              ; increment DeviceCount
        LDR     lr, [r2, #-4]                           ; word before heap block is length including length word
Ben Avison's avatar
Ben Avison committed
2876 2877
        TEQ     r1, lr, LSR #2                          ; block already full?
        BEQ     %FT81
Jeffrey Lee's avatar
Jeffrey Lee committed
2878
        LDR     lr, =ZeroPage
2879 2880 2881
10      STR     r1, [lr, #DeviceCount]
        ADD     lr, r2, r1, LSL #2
        SUB     lr, lr, #4
Ben Avison's avatar
Ben Avison committed
2882 2883 2884 2885 2886 2887
11      LDR     r1, [lr, #-4]!                          ; copy existing devices up, so new ones get enumerated first
        STR     r1, [lr, #4]
        CMP     lr, r2
        BHI     %BT11
        STR     r0, [r2]
        MOV     r2, r0
2888
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2889 2890 2891 2892 2893 2894
        MOV     r0, #0
        BL      Issue_Service
        ADDS    r0, r2, #0                              ; exit with V clear
        EXIT

80      ; Claim a system heap block for the device table
2895
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2896 2897
        MOV     r3, #16
        BL      ClaimSysHeapNode
2898
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2899
        EXIT    VS
2900
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2901
        LDR     lr, =ZeroPage
2902 2903
        MOV     r1, #1
        STR     r2, [lr, #DeviceTable]
Ben Avison's avatar
Ben Avison committed
2904 2905 2906
        B       %BT10

81      ; Extend the system heap block
2907
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2908 2909 2910
        MOV     r0, #HeapReason_ExtendBlock
        MOV     r3, #16
        BL      DoSysHeapOpWithExtension
2911
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2912
        EXIT    VS
2913
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2914
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2915 2916
        LDR     r1, [lr, #DeviceCount]
        STR     r2, [lr, #DeviceTable]
2917
        ADD     r1, r1, #1
Ben Avison's avatar
Ben Avison committed
2918 2919
        B       %BT10

2920
HardwareDeviceRemove_Common ROUT
2921
        Entry   "r4"
Jeffrey Lee's avatar
Jeffrey Lee committed
2922
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2923 2924 2925 2926
        LDR     r3, [lr, #DeviceCount]
        LDR     r4, [lr, #DeviceTable]
        TEQ     r3, #0
        EXIT    EQ                                      ; no devices registered
2927
10      LDR     r2, [r4], #4
2928 2929
        SUBS    r3, r3, #1
        TEQNE   r2, r0
2930
        BNE     %BT10
Ben Avison's avatar
Ben Avison committed
2931 2932 2933
        TEQ     r2, r0
        EXIT    NE                                      ; this device not registered
        MOV     r0, #1
2934
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2935 2936
        BL      Issue_Service
        CMP     r1, #0                                  ; if service call claimed
2937
        CMPEQ   r1, #1:SHL:31                           ; then set V (r0 already points to error block)
Ben Avison's avatar
Ben Avison committed
2938
        EXIT    VS                                      ; and exit
2939
        ; Search for device again - we may have been re-entered
Ben Avison's avatar
Ben Avison committed
2940
        MOV     r0, r2
2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
        LDR     lr, =ZeroPage
        LDR     r3, [lr, #DeviceCount]
        LDR     r4, [lr, #DeviceTable]
        TEQ     r3, #0
        EXIT    EQ                                      ; no devices registered
20      LDR     r2, [r4], #4
        SUBS    r3, r3, #1
        TEQNE   r2, r0
        BNE     %BT20
        TEQ     r2, r0
        EXIT    NE                                      ; this device not registered
Ben Avison's avatar
Ben Avison committed
2952
        SUBS    r3, r3, #1
2953
30      LDRCS   r2, [r4], #4                            ; copy down remaining devices
2954 2955
        STRCS   r2, [r4, #-8]
        SUBCSS  r3, r3, #1
2956
        BCS     %BT30
Jeffrey Lee's avatar
Jeffrey Lee committed
2957
        LDR     lr, =ZeroPage
2958 2959 2960
        LDR     r3, [lr, #DeviceCount]
        SUB     r3, r3, #1
        STR     r3, [lr, #DeviceCount]
Ben Avison's avatar
Ben Avison committed
2961 2962 2963 2964
        EXIT

HardwareDeviceEnumerate
        Push    "r3-r4,lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
2965
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2966 2967 2968 2969 2970 2971 2972 2973
        LDR     r2, [lr, #DeviceCount]
        LDR     r3, [lr, #DeviceTable]
        SUBS    r4, r2, r1
        MOVLS   r1, #-1
        BLS     %FT90                                   ; if r1 is out of range then exit
        ADD     r3, r3, r1, LSL #2
10      ADD     r1, r1, #1
        LDR     r2, [r3], #4
2974 2975 2976
        LDR     lr, [r2, #HALDevice_Type]
        EOR     lr, lr, r0
        MOVS    lr, lr, LSL #16                         ; EQ if types match
Ben Avison's avatar
Ben Avison committed
2977 2978
        SUBNES  r4, r4, #1
        BNE     %BT10
2979
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
2980
        MOVNE   r1, #-1
2981 2982 2983 2984
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
2985 2986
        BLS     %FT90
        SUBS    r4, r4, #1
2987
        BHI     %BT10
2988
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
2989 2990 2991 2992
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Ben Avison's avatar
Ben Avison committed
2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
HardwareDeviceEnumerateChrono
        Push    "r3-r4,lr"
        LDR     lr, =ZeroPage
        LDR     r2, [lr, #DeviceCount]
        LDR     r3, [lr, #DeviceTable]
        SUBS    r4, r2, r1
        MOVLS   r1, #-1
        BLS     %FT90                                   ; if r1 is out of range then exit
        ADD     r3, r3, r4, LSL #2
10      ADD     r1, r1, #1
        LDR     r2, [r3, #-4]!
        LDR     lr, [r2, #HALDevice_Type]
        EOR     lr, lr, r0
3006
        MOVS    lr, lr, LSL #16                         ; EQ if types match
Ben Avison's avatar
Ben Avison committed
3007 3008
        SUBNES  r4, r4, #1
        BNE     %BT10
3009
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
3010
        MOVNE   r1, #-1
3011 3012 3013 3014
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
3015 3016
        BLS     %FT90
        SUBS    r4, r4, #1
3017
        BHI     %BT10
3018
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
3019 3020 3021 3022
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Kevin Bracey's avatar
Kevin Bracey committed
3023 3024 3025 3026 3027 3028 3029 3030 3031
HardwareBadReason
        ADR     r0, ErrorBlock_HardwareBadReason
 [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
 ]
        B       SLVK_SetV

3032 3033 3034
HardwareBadEntry2
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
Kevin Bracey's avatar
Kevin Bracey committed
3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046
HardwareBadEntry
        ADR     r0, ErrorBlock_HardwareBadEntry
 [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
 ]
        B       SLVK_SetV

        MakeErrorBlock HardwareBadReason
        MakeErrorBlock HardwareBadEntry

Kevin Bracey's avatar
Kevin Bracey committed
3047 3048 3049 3050 3051
 [ DebugTerminal
DebugTerminal_Rdch
        Push    "a2-a4,sb,ip"
        MOV     sb, ip
20
John Ballance's avatar
John Ballance committed
3052
        WritePSRc SVC_mode, r1
Kevin Bracey's avatar
Kevin Bracey committed
3053 3054 3055
        CallHAL HAL_DebugRX
        CMP     a1, #27
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
3056
        LDR     a2, =ZeroPage + OsbyteVars + :INDEX: RS423mode
Kevin Bracey's avatar
Kevin Bracey committed
3057 3058 3059
        LDRB    a2, [a2]
        TEQ     a2, #0                  ; is RS423 raw data,or keyb emulator?
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
3060
        LDR     a2, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
3061 3062 3063 3064 3065 3066 3067 3068 3069
        LDRB    a1, [a2, #ESC_Status]
        ORR     a1, a1, #&40
        STRB    a1, [a2, #ESC_Status]   ; mark escape flag
        MOV     a1, #27
        SEC                             ; tell caller to look carefully at R0
        Pull    "a2-a4,sb,ip,pc"
25
        CMP     a1, #-1
        Pull    "a2-a4,sb,ip,pc",NE     ; claim it
Jeffrey Lee's avatar
Jeffrey Lee committed
3070
        LDR     R0, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
3071 3072
        LDRB    R14, [R0, #CallBack_Flag]
        TST     R14, #CBack_VectorReq
John Ballance's avatar
John Ballance committed
3073
        BLNE    process_callbacks_disableIRQ
Kevin Bracey's avatar
Kevin Bracey committed
3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086
        B       %BT20


DebugTerminal_Wrch
        Push    "a1-a4,sb,ip,lr"
        MOV     sb, ip
        CallHAL HAL_DebugTX
        Pull    "a1-a4,sb,ip,pc"        ; don't claim it
 ]


Reset_IRQ_Handler
        SUB     lr, lr, #4
3087
        Push    "a1-a4,v1-v2,sb,ip,lr"
3088 3089 3090 3091 3092
        MRS     a1, SPSR
        MRS     a2, CPSR
        ORR     a3, a2, #SVC32_mode
        MSR     CPSR_c, a3
        Push    "a1-a2,lr"
3093 3094

        ; If it's not an IIC interrupt, mute it
Jeffrey Lee's avatar
Jeffrey Lee committed
3095
        LDR     v2, =ZeroPage
3096
        AddressHAL v2
Jeffrey Lee's avatar
Jeffrey Lee committed
3097
        CallHAL HAL_IRQSource
Jeffrey Lee's avatar
Jeffrey Lee committed
3098
        ADD     v1, v2, #IICBus_Base
Jeffrey Lee's avatar
Jeffrey Lee committed
3099
        MOV     ip, #0
3100 3101
10
        LDR     a2, [v1, #IICBus_Type]
Kevin Bracey's avatar
Kevin Bracey committed
3102
        TST     a2, #IICFlag_Background
Jeffrey Lee's avatar
Jeffrey Lee committed
3103 3104 3105 3106 3107 3108 3109
        BEQ     %FT20
        LDR     a2, [v1, #IICBus_Device]
        CMP     a2, a1
        ADREQ   lr, Reset_IRQ_Exit
        BEQ     IICIRQ
20
        ADD     ip, ip, #1
3110
        ADD     v1, v1, #IICBus_Size
Jeffrey Lee's avatar
Jeffrey Lee committed
3111
        CMP     ip, #IICBus_Count
3112
        BNE     %BT10
3113 3114 3115

        CallHAL HAL_IRQDisable ; Stop the rogue device from killing us completely

Jeffrey Lee's avatar
Jeffrey Lee committed
3116
Reset_IRQ_Exit
3117
        MyCLREX a1, a2
3118 3119 3120
        Pull    "a1-a2,lr"
        MSR     CPSR_c, a2
        MSR     SPSR_cxsf, a1
3121
        Pull    "a1-a4,v1-v2,sb,ip,pc",,^
Kevin Bracey's avatar
Kevin Bracey committed
3122

3123 3124
 [ DebugHALTX
DebugHALPrint
3125 3126
        Push    "a1-a4,v1,v2,sb,ip"
        MRS     v2, CPSR
3127 3128 3129 3130 3131 3132 3133 3134
        AddressHAL
        MOV     v1, lr
10      LDRB    a1, [v1], #1
        TEQ     a1, #0
        BEQ     %FT20
        CallHAL HAL_DebugTX
        B       %BT10
20      MOV     a1, #13
3135
;        CallHAL HAL_DebugTX
3136
        MOV     a1, #10
3137
;        CallHAL HAL_DebugTX
3138 3139
        ADD     v1, v1, #3
        BIC     lr, v1, #3
3140 3141
        MSR     CPSR_sf, v2
        Pull    "a1-a4,v1,v2,sb,ip"
3142 3143 3144 3145 3146
        MOV     pc, lr
 ]


 [ DebugHALTX
3147 3148
DebugHALPrintReg ; Output number on top of stack to the serial port
        Push    "a1-a4,v1-v4,sb,ip,lr"   ; this is 11 regs
3149
        MRS     v1, CPSR
3150 3151 3152 3153
        LDR     v2, [sp,#11*4]           ; find TOS value on stack
        ADR     v3, hextab
        MOV     v4, #8
05
3154
       AddressHAL
3155
10      LDRB    a1, [v3, v2, LSR #28]
3156
       CallHAL  HAL_DebugTX
3157 3158 3159 3160
        MOV     v2, v2, LSL #4
        SUBS    v4, v4, #1
        BNE     %BT10
        MOV     a1, #13
3161
       CallHAL  HAL_DebugTX
3162
        MOV     a1, #10
3163 3164
       CallHAL  HAL_DebugTX

3165
        MSR     CPSR_sf, v1
3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183
        Pull    "a1-a4,v1-v4,sb,ip,lr"
        ADD     sp, sp, #4
        MOV     pc, lr

hextab  DCB "0123456789abcdef"


 ]
;
;
; [ DebugHALTX
;HALDebugHexTX
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
;       b        jbdt1
;HALDebugHexTX2
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
3184
;       mov      r0,r0,lsl #16
3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217
;       b        jbdt2
;HALDebugHexTX4
;       stmfd    r13!, {r0-r3,sb,ip,lr}
;       AddressHAL
;       mov      r0,r0,ror #24          ; hi byte
;       bl       jbdtxh
;       mov      r0,r0,ror #24
;       bl       jbdtxh
;jbdt2
;       mov      r0,r0,ror #24
;       bl       jbdtxh
;       mov      r0,r0,ror #24
;jbdt1
;       bl       jbdtxh
;       mov      r0,#' '
;       CallHAL  HAL_DebugTX
;       ldmfd    r13!, {r0-r3,sb,ip,pc}
;
;jbdtxh stmfd    r13!,{a1,v1,lr}        ; print byte as hex. corrupts a2-a4, ip, assumes sb already AddressHAL'd
;       and      v1,a1,#&f              ; get low nibble
;       and      a1,a1,#&f0             ; get hi nibble
;       mov      a1,a1,lsr #4           ; shift to low nibble
;       cmp      a1,#&9                 ; 9?
;       addle    a1,a1,#&30
;       addgt    a1,a1,#&37             ; convert letter if needed
;       CallHAL  HAL_DebugTX
;       cmp      v1,#9
;       addle    a1,v1,#&30
;       addgt    a1,v1,#&37
;       CallHAL  HAL_DebugTX
;       ldmfd    r13!,{a1,v1,pc}
; ]
;
3218 3219
        END