HAL 104 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 24 25 26

; Fixed page allocation is as follows

                        ^       0
DRAMOffset_FirstFixed   #       0
DRAMOffset_ScratchSpace #       16*1024
DRAMOffset_PageZero     #       16*1024
DRAMOffset_L1PT         #       16*1024         ; L1PT must be 16K-aligned
DRAMOffset_LastFixed    #       0

27 28
;        IMPORT  Init_ARMarch
;        IMPORT  ARM_Analyse
29

30
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
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)
        DCD     MMUC_SW+MMUC_U+MMUC_XP
                ; 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
56
 ]
57 58 59 60 61 62 63

; 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
64 65
        MOVEQ   a3, #0
        ARM_read_control a3, NE
66
 [ MEMM_Type = "VMSAv6"
Jeffrey Lee's avatar
Jeffrey Lee committed
67 68 69 70 71
        CMP     a1, #ARMv6
        CMPNE   a1, #ARMvF
        ADREQ   a2, mmuc_init_new
        ADRNE   a2, mmuc_init_old
        LDMIA   a2, {a2, lr}
72
        ORR     a3, a3, a2
Jeffrey Lee's avatar
Jeffrey Lee committed
73
        BIC     a3, a3, lr
74
 |
75 76 77 78 79 80
        ; 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.
81
        ORR     a3, a3, #MMUC_F+MMUC_L+MMUC_D+MMUC_P
82
        ; All of these bits should be off already, but just in case...
83 84
        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
85
 ]
86 87

        ; Off we go.
88
        ARM_write_control a3
89
        MOV     a2, #0
90
 [ MEMM_Type = "VMSAv6"
91
        myISB   ,a2,,y ; Ensure the update went through
92
 ]
93 94

        ; In case it wasn't a hard reset
95
 [ MEMM_Type = "VMSAv6"
96 97
        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
98 99
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
100
        MCRNE   ARM_config_cp,0,a2,ARMv4_cache_reg,C7           ; invalidate I+D caches
Ben Avison's avatar
Ben Avison committed
101
01
102
 ]
103
        CMP     a1, #ARMv3
Ben Avison's avatar
Ben Avison committed
104
        BNE     %FT01
105
        MCREQ   ARM_config_cp,0,a2,ARMv3_TLBflush_reg,C0        ; flush TLBs
Ben Avison's avatar
Ben Avison committed
106 107 108
        B       %FT02
01      MCRNE   ARM_config_cp,0,a2,ARMv4_TLB_reg,C7             ; flush TLBs
02
109
 [ MEMM_Type = "VMSAv6"
110 111
        myDSB   ,a2,,y
        myISB   ,a2,,y
112
 ]
113

114 115
        ; We assume that ARMs with an I cache can have it enabled while the MMU is off.
        [ :LNOT:CacheOff
116 117
        ORRNE   a3, a3, #MMUC_I
        ARM_write_control a3, NE                                ; whoosh
118
 [ MEMM_Type = "VMSAv6"
119
        myISB   ,a2,,y ; Ensure the update went through
120
 ]
121 122
        ]

123 124
        ; Check if we are in a 26-bit mode.
        MRS     a2, CPSR
125 126
        ; Keep a soft copy of the CR in a banked register (R13_und)
        MSR     CPSR_c, #F32_bit+I32_bit+UND32_mode
127
        MOV     sp, a3
128 129 130 131 132 133 134 135 136 137 138 139
        ; 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


; void *RISCOS_AddRAM(unsigned int flags, void *start, void *end, uintptr_t sigbits, void *ref)
;   Entry:
;     flags   bit 0: video memory (currently only one block permitted)
Kevin Bracey's avatar
Kevin Bracey committed
140
;             bit 1: video memory is not suitable for general use
141
;             bit 2: memory can't be used for DMA (sound, video, or other)
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
;             bits 8-11: speed indicator (arbitrary, higher => faster)
;             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)

; A table is built up at the head of the first block of memory.
; The table consists of (addr, len, flags) pairs, terminated by a count of those pairs; ref points to that
; counter.
; Twelve bits of flags are stored at the bottom of the length word.

        ROUT
RISCOS_AddRAM
        Push    "v1,v2,v3,v4,lr"
157
        LDR     v4, [sp, #5*4]          ; Get ref
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

        ; 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.
        ;
        ADD     a2, a2, #4096           ; round start address up
        SUB     a2, a2, #1
        MOV     a2, a2, LSR #12
        MOV     a2, a2, LSL #12
        MOV     a3, a3, LSR #12         ; round end address down
        MOV     a3, a3, LSL #12

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

        CMP     v4, #0
        BEQ     %FT20

        ; 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
        MOV     v3, v2, LSL #20         ; Isolate flags
        BIC     v2, v2, v3, LSR #20     ; And strip from length
        ADD     v2, v1, v2              ; Get the end address
        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.
        SUB     v2, v2, v1              ; Calculate the previous block length.
        SUB     a3, a3, a2              ; Find the length of the new block.
        ; a3 = length of block
        ADD     v2, v2, a3              ; Add it to the previous length.
        ORR     v2, v2, v3, LSR #20     ; And put the flags back in.
        STR     v2, [v4, #-4]           ; Update the block size in memory.
        MOV     a1,v4
        Pull    "v1,v2,v3,v4,pc"

        ; 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 ...
        SUB     a3, a3, #1              ; ... with the address of the last byte in this block ...
        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.
        LDR     v1, [v4, #-8]           ; Get the previous block start again.

        SUB     a3, a3, a2              ; Calculate the current block size.
        SUB     v1, v1, a3              ; Subtract from the previous block start address.
        SUB     v2, v2, v1              ; Calculate the new length=end-start
        ORR     v2, v2, v3, LSR #20     ; And put the flags back in.
        STMDB   v4, {v1, v2}            ; Update the block info in memory.
        MOV     a1,v4
        Pull    "v1,v2,v3,v4,pc"

        ; 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
        MOV     a1, a1, LSL #20
        ORR     a3, a3, a1, LSR #20     ; Put the flags at the bottom
        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...
        MOVEQ   v4, a2                  ; ... use this block.
        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
        Pull    "v1,v2,v3,v4,pc"        ; We've done with this block now.



Kevin Bracey's avatar
Kevin Bracey committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
; 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
        MOV     v1, v1, LSR #12
        MOV     v1, v1, LSL #12         ; round base down
        ADD     v2, v2, #4096
        SUB     v2, v2, #1
        MOV     v2, v2, LSR #12
        MOV     v2, v2, LSL #12         ; round end up

        LDR     v5, [a4]
        SUB     v8, a4, v5, LSL #3
10      TEQ     v8, a4
        MOVEQ   pc, lr
        LDMIA   v8!, {v3, v4}
        MOV     v6, v4, LSR #12
        ADD     v6, v3, v6, LSL #12     ; v6 = end of RAM block
        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
        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
290 291 292 293 294 295
        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
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
        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
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v6}            ; store original base and new size
        B       %BT10

split_block
314 315
        MOV     v7, a4
30      TEQ     v7, v8                  ; shuffle up subsequent blocks in table
Robert Sprowson's avatar
Robert Sprowson committed
316
        LDMDB   v7, {v3, v4}
317 318
        STMNEIA v7, {v3, v4}
        SUBNE   v7, v7, #8
Kevin Bracey's avatar
Kevin Bracey committed
319 320 321 322 323
        BNE     %BT30
        ADD     v5, v5, #1
        ADD     a4, a4, #8
        STR     v5, [a4]

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

Kevin Bracey's avatar
Kevin Bracey committed
326 327 328 329 330 331 332 333
        SUB     v7, v1, v3              ; v7 = size of first half
        SUB     v6, v6, v2              ; v6 = size of second half
        ORR     v7, v7, v4, LSR #20
        ORR     v6, v6, v4, LSR #20     ; + flags
        STMDB   v8, {v3, v7}
        STMIA   v8!, {v2, v6}
        B       %BT10

334 335 336 337 338 339 340 341 342 343 344 345 346

;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
347 348 349 350 351 352 353 354 355
        ; 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

356 357 358 359 360
        LDR     v5, [a4]                        ; v5 = the number of RAM blocks
        SUB     v8, a4, v5, LSL #3              ; Jump back to the start of the list.

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

366
        ; Extract some pseudo-VRAM from first DMA-capable RAM block
367
        SUB     v8, a4, v5, LSL #3              ; Rewind again.
368 369 370 371
06      LDMIA   v8!, {v1, v2}
        TEQ     v8, a4                          ; End of list?
        TSTNE   v2, #OSAddRAM_NoDMA             ; DMA capable?
        BNE     %BT06
372 373
        MOV     v2, v2, LSR #12                 ; Remove flags
        MOV     v2, v2, LSL #12
374 375 376 377 378 379 380 381 382 383 384 385 386
        ; 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
387
        MOV     v6, v2
388 389
        BEQ     %FT09
        SUBS    v6, v6, #16*1024*1024           ; Leave 16M if it was the only DMA-capable block
390
        MOVLS   v6, v2, LSR #1                  ; If that overflowed, take half the bank.
391
09
Kevin Bracey's avatar
Kevin Bracey committed
392 393
        CMP     v6, #32*1024*1024
        MOVHS   v6, #32*1024*1024               ; Limit allocation to 32M (arbitrary)
394 395 396

        ADD     v1, v1, v6                      ; Adjust the RAM block base...
        SUBS    v2, v2, v6                      ; ... and the size
397 398 399 400 401 402 403
        BEQ     %FT22                           ; pack array tighter if this block is all gone
        STR     v1, [v8, #-8]                   ; update base
        LDR     v1, [v8, #-4]
        MOV     v1, v1, LSL #20
        ORR     v1, v1, v2, LSR #12
        MOV     v1, v1, ROR #20                 ; merge flags back into size
        STR     v1, [v8, #-4]                   ; update size
404 405 406 407 408 409 410 411 412 413 414 415 416
        B       %FT30

        ; Note real VRAM parameters
20      MOV     v6, v2                          ; Remember the size and address
        MOV     v4, v1                          ; of the VRAM
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

417
30      SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
        ; Scan forwards to find the fastest block of non-DMAable memory which is at least DRAMOffset_LastFixed size
        LDMIA   v8!, {v1, v2}
31
        TEQ     v8, a4
        BEQ     %FT32
        LDMIA   v8!, {v7, ip}
        CMP     ip, #DRAMOffset_LastFixed
        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
        ; Fill in the Kernel's permanent memory table, sorting by speed and DMA ability
        ; 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)
        ADD     ip, v1, #DRAMOffset_PageZero
439 440 441 442 443

        ADD     sp, v1, #DRAMOffset_ScratchSpace + ScratchSpaceSize

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

444
        SUB     v8, a4, v5, LSL #3              ; Rewind to start of list
445 446 447
        CMP     v5, #DRAMPhysTableSize          ; Don't overflow our table
        ADDHI   a4, v8, #DRAMPhysTableSize*8 - 8

448 449 450
        ; First put the VRAM information in to free up some regs
        ADD     v7, ip, #VideoPhysAddr
        STMIA   v7!, {v4, v6}
451

452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
        ; Now fill in the rest
        ASSERT  DRAMPhysAddrA = VideoPhysAddr+8
        STMIA   v7!, {v1, v2}                   ; workspace block must be first
33
        TEQ     v8, a4
        BEQ     %FT39
        LDMIA   v8!, {v1, v2}
        CMP     v2, #4096                       ; skip zero-length sections
        BLO     %BT33
        ; Perform insertion sort
        ; a1-a3, v3-v6, ip, lr free
        ADD     a1, ip, #DRAMPhysAddrA
        LDMIA   a1!, {a2, a3}
        TEQ     v1, a2
        BEQ     %BT33                           ; don't duplicate the initial block
        AND     v3, v2, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        ASSERT  OSAddRAM_Speed = 1:SHL:8
        ASSERT  OSAddRAM_NoDMA < OSAddRAM_Speed
        MOV     v3, v3, ROR #8                  ; Give NoDMA flag priority over speed when sorting
34
        AND     v4, a3, #&F*OSAddRAM_Speed+OSAddRAM_NoDMA
        CMP     v3, v4, ROR #8
        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
492 493
        ; Now we have to work out the total RAM size
        MOV     a2, #0
494 495
        ADD     v6, ip, #PhysRamTable
        MOV     a3, v6
496 497
40
        LDMIA   v6!, {v1, v2}                   ; get address, size
498
        ADD     a2, a2, v2, LSR #12             ; add on size
499 500
        TEQ     v6, v7
        BNE     %BT40
501
        MOV     a2, a2, LSL #12
502

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
        ; 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?
        LDRNE   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + 32*1024 + DRAMOffset_LastFixed
        LDREQ   a1, =SoundDMABuffers-CursorChunkAddress + ?SoundDMABuffers + DRAMOffset_LastFixed
        ; 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
        ADD     lr, v1, #DRAMOffset_LastFixed
        STR     lr, [ip, #InitDMAEnd]
        B       %FT43
41
        ; Go on to check the rest of PhysRamTable
        SUB     a1, a1, #DRAMOffset_LastFixed
42
        LDMIA   a4!, {v1, v2}
        TST     v2, #OSAddRAM_NoDMA
        BNE     %BT42
        CMP     v2, a1
        BLO     %BT42
        ; Make a note of this block
        STR     v1, [ip, #InitDMAEnd]
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
        ADD     v1, v1, a1
        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
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572

; a2 = Total memory size (bytes)
; a3 = PhysRamTable
; v7 = After last used entry in PhysRamTable

; 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

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

573 574
        LDR     a4, =DRAMOffset_L1PT+16*1024-(PhysRamTable+DRAMOffset_PageZero) ; offset from a3 to L1PT end
        ADD     a3, a3, a4
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
        MOV     a4, #16*1024
        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

        ADD     v1, a3, #DRAMOffset_PageZero - DRAMOffset_L1PT
590
        ADD     v2, a3, #DRAMOffset_LastFixed - DRAMOffset_L1PT
591 592 593 594
        STR     a2, [v1, #RAMLIMIT]                     ; remember the RAM size
        MOV     lr, a2, LSR #12
        SUB     lr, lr, #1
        STR     lr, [v1, #MaxCamEntry]
595 596
        MOV     lr, a2, LSR #12-CAM_EntrySizeLog2+12
        CMP     a2, lr, LSL #12-CAM_EntrySizeLog2+12
597 598 599 600 601 602 603 604
        ADDNE   lr, lr, #1
        MOV     lr, lr, LSL #12
        STR     lr, [v1, #SoftCamMapSize]
        STR     a3, [v1, #InitUsedStart]                ; store start of L1PT

        ADD     v1, v1, #DRAMPhysAddrA
        MOV     v3, a3

605 606 607 608 609 610 611
        ; 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]
        ADD     lr, a1, #DRAMOffset_LastFixed
        TEQ     lr, v2
        MOVNE   v2, a1

612 613 614 615 616
; For the next batch of allocation routines, v1-v3 are treated as globals.
; v1 -> current entry in PhysRamTable
; v2 -> next address to allocate in v1 (may point at end of v1)
; v3 -> L1PT (or 0 if MMU on - not yet)

617 618 619 620
; Set up some temporary PCBTrans and PPLTrans pointers
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        BL      Init_PCBTrans

621 622 623
; Allocate the L2PT backing store for the logical L2PT space, to
; prevent recursion.
        LDR     a1, =L2PT
Kevin Bracey's avatar
Kevin Bracey committed
624
        MOV     a2, #&00400000
625 626
        BL      AllocateL2PT

627 628
; Allocate workspace for the HAL

629 630 631
        ADD     a4, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        LDR     a3, [sp, #8]                            ; recover pushed HAL header
        LDR     a1, =HALWorkspace
632
        LDR     a2, =AreaFlags_HALWorkspace
633 634
        LDR     lr, [a3, #HALDesc_Workspace]            ; their workspace
        LDR     ip, [a3, #HALDesc_NumEntries]           ; plus 1 word per entry
635 636
        CMP     ip, #KnownHALEntries
        MOVLO   ip, #KnownHALEntries
637
        ADD     lr, lr, ip, LSL #2
638 639 640 641
        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
642 643 644
        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
645 646
        BL      Init_MapInRAM

647 648 649 650
        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?
651
        LDRNE   a2, =AreaFlags_HALWorkspaceNCNB
652
        LDRNE   a3, =32*1024
653
        BLNE    Init_MapInRAM_DMA
654

655 656 657 658 659 660 661 662
; 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
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
Jeffrey Lee's avatar
Jeffrey Lee committed
663
        LDR     a2, =ZeroPage
664
        LDR     a3, =AreaFlags_ZeroPage
665 666 667 668 669 670
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in scratch space
        ADD     a1, v3, #DRAMOffset_ScratchSpace - DRAMOffset_L1PT
        MOV     a2, #ScratchSpace
671
        LDR     a3, =AreaFlags_ScratchSpace
672 673 674 675 676 677
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in L1PT
        MOV     a1, v3
        LDR     a2, =L1PT
678
        LDR     a3, =AreaFlags_L1PT
679 680 681 682 683 684 685
        MOV     a4, #16*1024
        BL      Init_MapIn

        ; Map in L1PT again in PhysicalAccess (see below)
        MOV     a1, v3, LSR #20
        MOV     a1, a1, LSL #20                 ; megabyte containing L1PT
        LDR     a2, =PhysicalAccess
686
        LDR     a3, =AreaFlags_L1PT
687 688 689
        MOV     a4, #1024*1024
        BL      Init_MapIn

690

691 692 693 694 695 696 697
        ; 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

698
        LDR     v7, [v5, #OSHdr_ImageSize]
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
        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}
714 715
        LDR     a3, [v5, #OSHdr_DecompressHdr]  ; check if ROM is compressed, and if so, make writeable
        CMP     a3, #0
716 717
        MOVNE   a3, #OSAP_None
        MOVEQ   a3, #OSAP_ROM
718 719
        SUB     a4, v7, v6
        BL      Init_MapIn
720
        MOV     a3, v6
721 722 723
        B       %FT75

70
724 725
        ; HAL is separate. (We should cope with larger images)
        LDR     a2, =ROM
726 727 728 729 730 731
        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
732
        MOV     a3, #OSAP_ROM
733 734 735 736 737 738 739 740 741 742
        BL      Init_MapIn

        ; 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
743 744
        LDR     a3, [v5, #OSHdr_DecompressHdr]
        CMP     a3, #0
745 746
        MOVNE   a3, #0
        MOVEQ   a3, #OSAP_ROM
747
        BL      Init_MapIn
748
        MOV     a3, v5
749 750 751 752
75
        ; We've now allocated all the pages we're going to before the MMU comes on.
        ; Note the end address (for RAM clear)
        ADD     a1, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
753
        STR     v1, [a1, #InitUsedBlock]
754
        STR     v2, [a1, #InitUsedEnd]
755
        STR     a3, [a1, #ROMPhysAddr]
756

757 758
        ; Note the HAL flags passed in.
        LDR     a2, [sp, #0]
759
        STR     a2, [a1, #HAL_StartFlags]
760

Kevin Bracey's avatar
Kevin Bracey committed
761 762 763
        ; Set up a reset IRQ handler (used during RAM clear for keyboard
        ; scan, and later for IIC CMOS access)
        MSR     CPSR_c, #IRQ32_mode + I32_bit + F32_bit
764
        LDR     sp_irq, =ScratchSpace + 1024    ; 1K is plenty since Reset_IRQ_Handler now runs in SVC mode
Kevin Bracey's avatar
Kevin Bracey committed
765 766 767 768
        MSR     CPSR_c, #SVC32_mode + I32_bit + F32_bit
        LDR     a2, =Reset_IRQ_Handler
        STR     a2, [a1, #InitIRQHandler]

769 770 771 772 773 774 775 776 777 778
        ; 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

Kevin Bracey's avatar
Kevin Bracey committed
779
MMU_activation_zone
780 781 782 783 784 785 786 787 788
; 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.
;
; Also note, no RAM access until we've finished the operation, as we don't know it's
; available, and we might lose it due to lack of cache cleaning.
;
Kevin Bracey's avatar
Kevin Bracey committed
789 790
        MOV     a1, #4_3333333333333333         ; All domain manager - in case MMU already on
        ARM_MMU_domain a1                       ; (who knows what domains/permissions they are using)
791

Kevin Bracey's avatar
Kevin Bracey committed
792
        ADR     a1, MMU_activation_zone
793 794 795
        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
796 797 798
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
799 800 801 802 803
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
804
 ]
805 806 807 808
        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}

809 810
        MOV     a4, a1
        BL      Init_ARMarch                    ; corrupts a1 and ip
811
        MOV     ip, a1 ; Remember architecture for later
Kevin Bracey's avatar
Kevin Bracey committed
812

813 814
        MOV     a1, a4
        MSREQ   CPSR_c, #F32_bit+I32_bit+UND32_mode ; Recover the soft copy of the CR
815
        MOVEQ   v5, sp
816
        ARM_read_control v5, NE
817
  [ CacheOff
818
        ORR     v5, v5, #MMUC_M                 ; MMU on
819 820
        ORR     v5, v5, #MMUC_R                 ; ROM mode enable
  |
821
        ORR     v5, v5, #MMUC_W+MMUC_C+MMUC_M   ; Write buffer, data cache, MMU on
822
        ORR     v5, v5, #MMUC_R+MMUC_Z          ; ROM mode enable, branch predict enable
823 824 825 826 827 828 829 830
  ]
  [ MEMM_Type = "VMSAv6"
        ; If we're using shareable pages, set the appropriate flag in the TTBR to let the CPU know the page tables themselves are shareable
        ADD     lr, v3, #DRAMOffset_PageZero - DRAMOffset_L1PT
        LDR     lr, [lr, #MMU_PPLTrans]
        LDRH    lr, [lr]
        TST     lr, #L2_S
        ORRNE   v3, v3, #2
831
  ]
Kevin Bracey's avatar
Kevin Bracey committed
832
        ARM_MMU_transbase v3                    ; Always useful to tell it where L1PT is...
833 834 835 836
  [ MEMM_Type = "VMSAv6"
        BIC     v3, v3, #2                      ; (clear flags, the address in v3 is needed later on)
        CMP     ip, #0
  ]
Kevin Bracey's avatar
Kevin Bracey committed
837

838
        MOV     lr, #0
Ben Avison's avatar
Ben Avison committed
839
        BNE     %FT01
840
        MCREQ   p15, 0, lr, c5, c0              ; MMU may already be on (but flat mapped)
Ben Avison's avatar
Ben Avison committed
841 842 843
        B       %FT02
01      MCRNE   p15, 0, lr, c8, c7              ; if HAL needed it (eg XScale with ECC)
02                                              ; so flush TLBs now
844
  [ MEMM_Type = "VMSAv6"
845 846 847 848 849 850 851 852 853
        MCR     p15, 0, lr, c2, c0, 2           ; TTBCR: Ensure only TTBR0 is used
        ; Check if security extensions are supported
        CMP     ip, #ARMvF
        BNE     %FT01
        MRC     p15, 0, lr, c0, c1, 1           ; ID_PFR1
        TST     lr, #15<<4
        MOV     lr, #0
        BEQ     %FT01
        MCR     p15, 0, lr, c12, c0, 0          ; VBAR: Ensure exception vector base is 0 (security extensions)
Ben Avison's avatar
Ben Avison committed
854
01
855
        myISB   ,lr,,y
856 857 858
        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
859 860
        CMP     ip, #0
  ]
861 862 863
  [ NoUnaligned
        ORR     v5, v5, #MMUC_A ; Alignment exceptions on
  ]
Jeffrey Lee's avatar
Jeffrey Lee committed
864 865 866
  [ HiProcVecs
        ORR     v5, v5, #MMUC_V ; High processor vectors enabled
  ]
867 868
MMUon_instr
        ARM_write_control v5
869
  [ MEMM_Type = "VMSAv6"
870 871
        MOV     lr, #0
        myISB   ,lr,,y ; Just in case
872
  ]
873
        MOVEQ   sp, v5
874 875
        MSREQ   CPSR_c, #F32_bit+I32_bit+SVC32_mode

876
  [ MEMM_Type = "VMSAv6"
877
        CMP     ip, #ARMvF
Ben Avison's avatar
Ben Avison committed
878
        BEQ     %FT01
879
        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
880 881
        B       %FT02
01      MCREQ   p15, 0, lr, c7, c5, 0           ; invalidate instruction cache
882
        MCREQ   p15, 0, lr, c8, c7, 0           ; invalidate TLBs
883
        MCREQ   p15, 0, lr, c7, c5, 6           ; invalidate branch predictor
884
        myISB   ,lr,,y ; Ensure below branch works
885
        BLEQ    HAL_InvalidateCache_ARMvF       ; invalidate data cache (and instruction+TLBs again!)
Ben Avison's avatar
Ben Avison committed
886
02
887 888 889 890
  |
        MOV     lr, #0                                          ; junk MMU-off contents of I-cache
        MCR     ARM_config_cp,0,lr,ARMv4_cache_reg,C7           ; (works on ARMv3)
  ]
891

892 893
        MOV     ip, #4_0000000000000001                         ; domain 0 client only
        ARM_MMU_domain ip
Kevin Bracey's avatar
Kevin Bracey committed
894

895 896 897 898 899 900 901
; 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
Kevin Bracey's avatar
Kevin Bracey committed
902
        ADR     a4, MMU_activation_zone
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
        MOV     a4, a4, LSR #20
        MOV     a4, a4, LSL #20                 ; a4 = base of scrambled region
        ADD     v4, a4, #2*1024*1024            ; v4 = top of scrambled region
        SUB     v4, v4, #1                      ;      (inclusive, in case wrapped to 0)
        ADR     v5, MMUon_resume
        ADD     v5, v5, ip                      ; v5 = virtual address of MMUon_resume
        CMP     v5, a4
        BLO     MMUon_nooverlap
        CMP     v5, v4
        BHI     MMUon_nooverlap

        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
918 919 920
 [ MEMM_Type = "VMSAv6"
        LDR     ip, =(AP_ROM * L1_APMult) + L1_Section
 |
921 922 923 924 925
  [ ARM6support
        LDR     ip, =(AP_None * L1_APMult) + L1_U + L1_Section
  |
        LDR     ip, =(AP_ROM * L1_APMult) + L1_U + L1_Section
  ]
926
 ]
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
        ORR     v6, a4, ip
        ADD     ip, v6, #1024*1024
        LDMIB   lr, {v7, v8}                    ; sections 1 and 2
        STMIB   lr, {v6, ip}
        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

MMUon_nooverlap
        ADRL    lr, RISCOS_Header
        LDR     ip, =RISCOS_Header
        SUB     ip, ip, lr
        ADD     pc, pc, ip
        NOP
MMUon_resume
; What if the logical address of the page tables is at the physical address of the code?
; Then we have to access it via PhysicalAccess instead.
        LDR     lr, =L1PT
        CMP     lr, a4
        BLO     MMUon_nol1ptoverlap
        CMP     lr, v4
        BHI     MMUon_nol1ptoverlap
; PhysicalAccess points to the megabyte containing the L1PT. Find the L1PT within it.
        LDR     lr, =PhysicalAccess
        MOV     v6, v3, LSL #12
        ORR     lr, lr, v6, LSR #12
MMUon_nol1ptoverlap
        ADD     lr, lr, a1, LSL #2
        STMIA   lr, {a2, a3}
        BL      Init_PageTablesChanged

; The MMU is now on. Wahey. Let's get allocating.

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

970 971
        LDR     a1, =ZeroPage

972 973
        ADD     lr, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT   ; lr = PhysAddr of zero page
        SUB     v1, v1, lr
974 975 976 977 978 979 980
        ADD     v1, v1, a1                              ; turn v1 from PhysAddr to LogAddr

        LDR     a2, [a1, #InitUsedBlock]                ; turn this from Phys to Log too
        SUB     a2, a2, lr
        ADD     a2, a2, a1
        STR     a2, [a1, #InitUsedBlock]

981

982 983 984 985
; Store the logical address of the HAL descriptor
        LDR     a2, [sp, #8]
        STR     a2, [a1, #HAL_Descriptor]

986 987 988 989
        MOV     v3, #0                                  ; "MMU is on" signal

        BL      ARM_Analyse

Kevin Bracey's avatar
Kevin Bracey committed
990 991
        ChangedProcVecs a1

992 993 994 995
        MOV     a1, #L1_Fault
        BL      RISCOS_ReleasePhysicalAddress

        LDR     a1, =HALWorkspace
Jeffrey Lee's avatar
Jeffrey Lee committed
996
        LDR     a2, =ZeroPage
997
        LDR     a3, [a2, #HAL_WsSize]
Jeffrey Lee's avatar
Jeffrey Lee committed
998 999 1000
      [ ZeroPage <> 0
        MOV     a2, #0
      ]
1001 1002
        BL      memset

Jeffrey Lee's avatar
Jeffrey Lee committed
1003
        LDR     a2, =ZeroPage
1004 1005 1006
        LDR     a1, =IOLimit
        STR     a1, [a2, #IOAllocLimit]
        LDR     a1, =IO
1007 1008 1009 1010
        STR     a1, [a2, #IOAllocPtr]

        BL      SetUpHALEntryTable

1011 1012 1013
; 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
1014
        LDR     a1, =ZeroPage
1015 1016 1017
        STR     v1, [a1, #InitUsedBlock]
        STR     v2, [a1, #InitUsedEnd]

1018
        LDR     a1, =RISCOS_Header
1019
        LDR     a2, =HALWorkspaceNCNB
1020 1021 1022
        AddressHAL
        CallHAL HAL_Init

1023
        DebugTX "HAL initialised"
1024

1025 1026 1027 1028 1029 1030 1031 1032 1033
        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]
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
; 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
1046

1047 1048
        DebugTX "IICInit"

1049 1050
        BL      IICInit

Jeffrey Lee's avatar
Jeffrey Lee committed
1051
        LDR     a1, =ZeroPage+InitIRQWs
1052 1053 1054
        MOV     a2, #1
        STRB    a2, [a1, #KbdScanActive]

1055 1056
        DebugTX "HAL_KbdScanSetup"

1057 1058 1059 1060
        CallHAL HAL_KbdScanSetup

        MSR     CPSR_c, #F32_bit+SVC32_mode             ; enable IRQs for scan

1061
; Remember some stuff that's about to get zapped
1062 1063 1064 1065 1066
        LDR     ip, =ZeroPage
        LDR     v4, [ip, #ROMPhysAddr]
        LDR     v5, [ip, #RAMLIMIT]
        LDR     v7, [ip, #MaxCamEntry]
        LDR     v8, [ip, #IRQMax]
1067

1068
        LDR     a1, [ip, #HAL_StartFlags]
Kevin Bracey's avatar
Kevin Bracey committed
1069
        TST     a1, #OSStartFlag_RAMCleared
1070
        BLEQ    ClearPhysRAM            ; Only clear the memory if the HAL didn't
1071

1072
; Put it back
1073 1074 1075 1076 1077
        LDR     ip, =ZeroPage
        STR     v4, [ip, #ROMPhysAddr]
        STR     v5, [ip, #RAMLIMIT]
        STR     v7, [ip, #MaxCamEntry]
        STR     v8, [ip, #IRQMax]
1078

1079 1080 1081
; Calculate CPU feature flags (if moving this to before ClearPhysRAM, ensure the workspace also gets moved into the skipped region)
        BL      ReadCPUFeatures

1082
        MOV     v8, ip
Kevin Bracey's avatar
Kevin Bracey committed
1083

1084 1085
        DebugTX "HAL_CleanerSpace"

1086
; Set up the data cache cleaner space if necessary (eg. for StrongARM core)
Kevin Bracey's avatar
Kevin Bracey committed
1087
        MOV     a1, #-1
1088 1089 1090 1091
        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
1092
        LDR     a3, =AreaFlags_DCacheClean
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104
        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}
        BL      Init_MapIn
        LDMIA   sp, {a1-a4, ip}
        SUBS    ip, ip, #1
        ADD     a2, a2, #&10000
        BNE     %BT10
        ADD     sp, sp, #5*4
1105

1106
20
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
; 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
1145
ROMDecompWSAddr * 4<<20
1146 1147 1148 1149 1150
        DebugTX "Allocating decompression workspace"
        LDR     v5, =(1<<20)-1
        ADD     v7, a3, v5
        BIC     v7, v7, v5 ; MB-aligned size
        STR     v7, [sp, #8] ; Overwrite stacked WS size
1151
        MOV     v6, #ROMDecompWSAddr ; Current log addr
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
26
        ADD     v2, v2, v5
        BIC     v2, v2, v5 ; MB-aligned physram
        LDMIA   v1, {a2, a3}
        SUB     a2, v2, a2 ; Amount of bank used
        SUB     a2, a3, a2 ; Amount of bank remaining
        MOVS    a2, a2, ASR #20 ; Round down to nearest MB
        LDRLE   v2, [v1, #8]! ; Move to next bank if 0MB left
        BLE     %BT26
        CMP     a2, v7, LSR #20
        MOVHS   a4, v7
        MOVLO   a4, a2, LSL #20 ; a4 = amount to take
        MOV     a1, v2 ; set up parameters for MapIn call
        MOV     a2, v6
1166
        MOV     a3, #OSAP_None
1167 1168 1169 1170 1171 1172 1173
        SUB     v7, v7, a4 ; Decrease amount to allocate
        ADD     v2, v2, a4 ; Increase physram ptr
        ADD     v6, v6, a4 ; Increase logram ptr
        BL      Init_MapIn
        CMP     v7, #0
        BNE     %BT26
        Pull    "a1-a2,v1-v2" ; Pull OS header, IMB func ptr, workspace size, decompression code
1174
        MOV     a3, #ROMDecompWSAddr
1175 1176 1177 1178 1179 1180 1181 1182 1183
        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
1184
        MOV     a1, #ROMDecompWSAddr
1185 1186 1187 1188
        MOV     a2, #0
        MOV     a3, v1
        BL      memset
; Flush the workspace from the cache & TLB so we can unmap it
Jeffrey Lee's avatar
Jeffrey Lee committed
1189 1190
; Really we should make the pages uncacheable first, but for simplicity we just
; do a full cache clean+invalidate later on when changing the ROM permissions
1191
        MOV     a1, #ROMDecompWSAddr
1192 1193 1194
        MOV     a2, v1, LSR #12
        ARMop   MMU_ChangingEntries
; Zero each L1PT entry
1195
        LDR     a1, =L1PT+(ROMDecompWSAddr>>18)
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
        MOV     a2, #0
        MOV     a3, v1, LSR #18
        BL      memset
; 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
; physical space. To do this we can just check if the L1PT entry for the OS is a
; section mapping.
        LDR     a1, =L1PT+(ROM>>18)
        LDR     a1, [a1]
        ASSERT  L1_Section = 2
        ASSERT  L1_Page = 1
        TST     a1, #2
; Section mapped, get address from L1PT
        MOVNE   a1, a1, LSR #20
        MOVNE   a1, a1, LSL #20
        MOVNE   a2, #ROM
        MOVNE   a4, #OSROM_ImageSize*1024
        BNE     %FT29
; Page/large page mapped, get address from L2PT
        LDR     a2, =RISCOS_Header
        LDR     a1, =L2PT
        LDR     a1, [a1, a2, LSR #10]
        LDR     a4, [a2, #OSHdr_ImageSize]
        MOV     a1, a1, LSR #12
        MOV     a1, a1, LSL #12
29
1227
        MOV     a3, #OSAP_ROM
1228 1229 1230 1231
        BL      Init_MapIn
; 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
1232
        ARMop   MMU_Changing ; Perform full clean+invalidate to ensure any lingering cache lines for the decompression workspace are gone
1233 1234
        DebugTX "ROM access changed to read-only"
30
1235 1236
; Allocate the CAM
        LDR     a3, [v8, #SoftCamMapSize]
1237
        LDR     a2, =AreaFlags_CAM
1238 1239 1240 1241 1242
        LDR     a1, =CAM
        BL      Init_MapInRAM

; Allocate the supervisor stack
        LDR     a1, =SVCStackAddress
1243
        LDR     a2, =AreaFlags_SVCStack
1244 1245 1246 1247 1248
        LDR     a3, =SVCStackSize
        BL      Init_MapInRAM

; Allocate the interrupt stack
        LDR     a1, =IRQStackAddress
1249
        LDR     a2, =AreaFlags_IRQStack
1250 1251 1252 1253 1254
        LDR     a3, =IRQStackSize
        BL      Init_MapInRAM

; Allocate the abort stack
        LDR     a1, =ABTStackAddress
1255
        LDR     a2, =AreaFlags_ABTStack
1256 1257 1258 1259 1260
        LDR     a3, =ABTStackSize
        BL      Init_MapInRAM

; Allocate the undefined stack
        LDR     a1, =UNDStackAddress
1261
        LDR     a2, =AreaFlags_UNDStack
1262 1263 1264
        LDR     a3, =UNDStackSize
        BL      Init_MapInRAM

1265
; Allocate the system heap (just 32K for now - will grow as needed)
1266
        LDR     a1, =SysHeapAddress
1267
        LDR     a2, =AreaFlags_SysHeap
1268 1269 1270
        LDR     a3, =32*1024
        BL      Init_MapInRAM

1271
; Allocate the cursor/system/sound block - first the cached bit
1272
        LDR     a1, =CursorChunkAddress
1273
        LDR     a2, =AreaFlags_CursorChunkCacheable
1274
        LDR     a3, =SoundDMABuffers - CursorChunkAddress
1275
        BL      Init_MapInRAM_DMA
1276 1277
; then the uncached bit
        LDR     a1, =SoundDMABuffers
1278
        LDR     a2, =AreaFlags_CursorChunk
1279
        LDR     a3, =?SoundDMABuffers
1280
        BL      Init_MapInRAM_DMA
1281

1282
        LDR     a1, =KbuffsBaseAddress
1283
        LDR     a2, =AreaFlags_Kbuffs
1284 1285 1286
        LDR     a3, =(KbuffsSize + &FFF) :AND: &FFFFF000  ;(round to 4k)
        BL      Init_MapInRAM

Jeffrey Lee's avatar
Jeffrey Lee committed
1287 1288 1289
 [ HiProcVecs
        ; Map in DebuggerSpace
        LDR     a1, =DebuggerSpace
1290
        LDR     a2, =AreaFlags_DebuggerSpace
Jeffrey Lee's avatar
Jeffrey Lee committed
1291 1292 1293 1294
        LDR     a3, =(DebuggerSpace_Size + &FFF) :AND: &FFFFF000
        BL      Init_MapInRAM
 ]

1295
 [ MinorL2PThack
1296 1297 1298 1299 1300 1301
; 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.
1302
        MOV     a1, #0
Kevin Bracey's avatar
Kevin Bracey committed
1303
        MOV     a2, #AplWorkMaxSize             ; Not quite right, but the whole thing's wrong anyway
1304
        ASSERT  AplWorkMaxSize :MOD: (4*1024*1024) = 0
1305 1306 1307 1308
        BL      AllocateL2PT
; And for the system heap. Sigh
        LDR     a1, =SysHeapAddress
        LDR     a2, =SysHeapMaxSize
1309 1310
        ASSERT  SysHeapAddress :MOD: (4*1024*1024) = 0
        ASSERT  SysHeapMaxSize :MOD: (4*1024*1024) = 0
1311 1312 1313
        BL      AllocateL2PT
 ]

1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
        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}
        ADD     v6, v1, v2
        ADD     v7, v4, v5
        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"
1338 1339 1340 1341 1342 1343 1344

        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
1345
        MSR     CPSR_c, #F32_bit+SVC2632
1346 1347
        LDR     sp, =SVCSTK

1348
        LDR     ip, =CAM
1349
        STR     ip, [v8, #CamEntriesPointer]
1350

1351 1352 1353 1354 1355
        BL      ConstructCAMfromPageTables

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

1356 1357
        BL      CountPageTablePages

1358
 [ {FALSE}
Kevin Bracey's avatar
Kevin Bracey committed
1359
        MOV     a1, #InitIRQWs
1360 1361 1362 1363
        MOV     a2, #0
        MOV     a3, #0
        STMIA   a1!, {a2,a3}
        STMIA   a1!, {a2,a3}
1364
 ]
1365

1366
        B       Continue_after_HALInit
1367 1368 1369

        LTORG

1370
 [ MEMM_Type = "VMSAv6"
1371 1372 1373 1374 1375 1376
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
Jeffrey Lee's avatar
Jeffrey Lee committed
1377 1378 1379 1380 1381 1382
        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
Jeffrey Lee's avatar
Jeffrey Lee committed
1383
        ; Check whether we're ARMv7 (and thus multi-level cache) or ARMv6 (and thus single-level cache)
Jeffrey Lee's avatar
Jeffrey Lee committed
1384 1385
        MRC     p15, 0, r8, c0, c0, 1
        TST     r8, #&80000000 ; EQ=ARMv6, NE=ARMv7
Ben Avison's avatar
Ben Avison committed
1386
        BEQ     %FT80
Jeffrey Lee's avatar
Jeffrey Lee committed
1387 1388

        ; 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
Ben Avison's avatar
Ben Avison committed
1389
        MRC     p15, 1, r8, c0, c0, 1           ; Read CLIDR to r8
Jeffrey Lee's avatar
Jeffrey Lee committed
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
        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
        myISB   ,r9
        MRC     p15, 1, r9, c0, c0, 0 ; read current CSSIDR to r9
1402
        AND     r10, r9, #CCSIDR_LineSize_mask ; extract the line length field
Jeffrey Lee's avatar
Jeffrey Lee committed
1403
        ADD     r10, r10, #4 ; add 4 for the line length offset (log2 16 bytes)
1404 1405
        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)
Jeffrey Lee's avatar
Jeffrey Lee committed
1406
        CLZ     r13, r8 ; r13 is the bit position of the way size increment
1407 1408
        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)
Jeffrey Lee's avatar
Jeffrey Lee committed
1409 1410 1411 1412 1413
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
1414
        MCR     p15, 0, r14, c7, c6, 2 ; Invalidate
Jeffrey Lee's avatar
Jeffrey Lee committed
1415 1416 1417 1418
        SUBS    r9, r9, #1 ; decrement the index
        BGE     %BT30
        SUBS    r8, r8, #1 ; decrement the way number
        BGE     %BT20
1419
        myDSB   ,r8        ; Cortex-A7 errata 814220: DSB required when changing cache levels when using set/way operations. This also counts as our end-of-maintenance DSB.
Ben Avison's avatar
Ben Avison committed
1420
        MRC     p15, 1, r8, c0, c0, 1
Jeffrey Lee's avatar
Jeffrey Lee committed
1421 1422 1423 1424 1425 1426 1427
40 ; Skip
        ADD     r11, r11, #2
        AND     r14, r8, #&07000000
        CMP     r14, r11, LSL #23
        BGT     %BT10

50 ; Finished
1428 1429 1430 1431 1432
        ; 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
1433 1434
        myDSB   ,r8,,y                          ; Wait for completion
        myISB   ,r8,,y
1435 1436 1437 1438
        ; 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
Ben Avison's avatar
Ben Avison committed
1439 1440 1441
80 ; ARMv6 case
        MCR     ARM_config_cp,0,r9,ARMv4_cache_reg,C7 ; ARMv3-ARMv6 I+D cache flush
        B       %BT50
1442
 ] ; MEMM_Type = "VMSAv6"
1443

1444
CountPageTablePages ROUT
1445
        Entry
Jeffrey Lee's avatar
Jeffrey Lee committed
1446
        LDR     a1, =ZeroPage
1447 1448
        LDR     a2, =CAM
        LDR     a3, [a1, #MaxCamEntry]
Jeffrey Lee's avatar
Jeffrey Lee committed
1449
      [ ZeroPage <> 0
1450
        MOV     a1, #0
Jeffrey Lee's avatar
Jeffrey Lee committed
1451
      ]
1452
        ADD     a3, a3, #1
1453
        ADD     a4, a2, a3, LSL #CAM_EntrySizeLog2
1454
        ASSERT  (L2PT :AND: &3FFFFF) = 0
1455 1456 1457
        LDR     lr, =L2PT :SHR: 22
10      LDR     ip, [a4, #CAM_LogAddr-CAM_EntrySize]!
        TEQ     lr, ip, LSR #22
1458 1459 1460
        ADDEQ   a1, a1, #4096
        TEQ     a4, a2
        BNE     %BT10
Jeffrey Lee's avatar
Jeffrey Lee committed
1461
        LDR     a2, =ZeroPage
1462
        STR     a1, [a2, #L2PTUsed]
1463
        EXIT
1464

1465 1466 1467 1468 1469 1470 1471 1472 1473
; int PhysAddrToPageNo(void *addr)
;
; Converts a physical address to the page number of the page containing it.
; Returns -1 if address is not in RAM.

PhysAddrToPageNo
        MOV     a4, #0
        LDR     ip, =ZeroPage + PhysRamTable
10      LDMIA   ip!, {a2, a3}                   ; get phys addr, size
1474
        MOVS    a3, a3, LSR #12                 ; end of list? (size=0)
1475 1476
        BEQ     %FT90                           ;   then it ain't RAM
        SUB     a2, a1, a2                      ; a2 = amount into this bank
1477 1478
        CMP     a2, a3, LSL #12                 ; if more than size
        ADDHS   a4, a4, a3, LSL #12             ;   increase counter by size of bank
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
        BHS     %BT10                           ;   and move to next
        ADD     a4, a4, a2                      ; add offset to counter
        MOV     a1, a4, LSR #12                 ; convert counter to a page number
        MOV     pc, lr

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"
Jeffrey Lee's avatar
Jeffrey Lee committed
1495
        LDR     a1, =ZeroPage
1496 1497 1498
        LDR     a2, [a1, #MaxCamEntry]
        LDR     v1, =CAM                        ; v1 -> CAM (for whole routine)
        ADD     a2, a2, #1
1499
        ADD     a2, v1, a2, LSL #CAM_EntrySizeLog2
1500 1501

        LDR     a3, =DuffEntry                  ; Clear the whole CAM, from
1502
        MOV     a4, #AreaFlags_Duff             ; the top down.
1503 1504 1505 1506 1507 1508 1509 1510
        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}
1511 1512 1513 1514 1515 1516
        CMP     a2, v1
        BHI     %BT10

        MOV     v2, #0                          ; v2 = logical address
        LDR     v3, =L1PT                       ; v3 -> L1PT (not used much)
        LDR     v4, =L2PT                       ; v4 -> L2PT
1517 1518 1519 1520
30      LDR     a1, [v3, v2, LSR #18]           ; a1 = first level descriptor
        BL      DecodeL1Entry                   ; a1 = phys addr, a2 = page flags/type
        CMP     a2, #-2                         ; Only care about page table pointers
        BEQ     %FT40
1521 1522 1523 1524
        ADDS    v2, v2, #&00100000
        BCC     %BT30
        Pull    "v1-v8, pc"

1525 1526 1527
40      LDR     a1, [v4, v2, LSR #10]           ; a1 = second level descriptor
        BL      DecodeL2Entry                   ; a1 = phys addr, a2 = flags (-1 if fault), a3 = page size (bytes)
        CMP     a2, #-1                         ; move to next page if fault
1528
        BEQ     %FT80
1529 1530 1531 1532 1533 1534
        SUBS    a3, a3, #4096                   ; large pages get bits 12-15 from the virtual address
        ANDNE   lr, v2, a3
        ORR     v6, a2, #PageFlags_Unavailable
        ORRNE   a1, a1, lr
        BL      PhysAddrToPageNo                ; -1 if unknown page
        ADDS    a1, v1, a1, LSL #CAM_EntrySizeLog2 ; a1 -> CAM entry
1535 1536
        ASSERT  CAM_LogAddr=0
        ASSERT  CAM_PageFlags=4
1537
        STMCCIA a1, {v2, v6}                    ; store logical address, PPL
1538

1539
80      ADD     v2, v2, #&00001000
1540 1541
        TST     v2, #&000FF000
        BNE     %BT40
1542 1543
        TEQ     v2, #0                          ; yuck (could use C from ADDS but TST corrupts C
        BNE     %BT30                           ; because of big constant)
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561

        Pull    "v1-v8, pc"



; Allocate a physical page from DRAM
;
; On entry:
;    v1 -> current entry in PhysRamTable
;    v2 -> end of last used physical page
; On exit:
;    a1 -> next free page
;    v1, v2 updated
;
; No out of memory check...

Init_ClaimPhysicalPage
        MOV     a1, v2
1562
        LDMIA   v1, {a2, a3}
1563 1564
        MOV     a3, a3, LSR #12
        ADD     a2, a2, a3, LSL #12             ; ip = end of this bank
1565
        CMP     v2, a2                          ; advance v2 to next bank if
1566 1567
        LDRHS   a1, [v1, #8]!                   ; this bank is fully used
        ADD     v2, a1, #4096
1568
        MOV     pc, lr
1569 1570 1571 1572 1573

; Allocate and map in some RAM.
;
; On entry:
;    a1 = logical address
Kevin Bracey's avatar
Kevin Bracey committed
1574
;    a2 = access permissions (see Init_MapIn)
1575
;    a3 = length (4K multiple)
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
;    v1 -> current entry in PhysRamTable
;    v2 = next physical address
;    v3 -> L1PT
;
; On exit:
;    a1 -> physical address of start of RAM (deduce the rest from PhysRamTable)
;
; No out of memory check...
Init_MapInRAM ROUT
        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
1590 1591
10      LDMIA   v1, {v4, ip}                    ; v4 = addr of bank, ip = len+flags
        MOV     ip, ip, LSR #12
1592
        SUB     v4, v2, v4                      ; v4 = amount of bank used
1593
        RSBS    v4, v4, ip, LSL #12             ; v4 = amount of bank left
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
        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

        CMP     v4, v5                          ; sufficient in this bank?
        MOVHS   a4, v5
        MOVLO   a4, v4                          ; a4 = amount to take

        MOV     a1, v2                          ; set up parameters for MapIn call
        MOV     a2, v6                          ; then move globals (in case MapIn
        MOV     a3, v7                          ; needs to allocate for L2PT)
        ADD     v2, v2, a4                      ; advance physaddr
        SUB     v5, v5, a4                      ; decrease wanted
        ADD     v6, v6, a4                      ; advance address pointer
        BL      Init_MapIn                      ; map in the RAM
        TEQ     v5, #0                          ; more memory still required?
        BNE     %BT10

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

1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
; 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
;    v2 = next physical address
;    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
Init_MapInRAM_DMA ROUT
        Push    "a1,a3,v4-v5,ip,lr"
        TEQ     v3, #0                          ; MMU on?
        LDREQ   v4, =ZeroPage                   ; get workspace directly
        ADDNE   v4, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT ; deduce from L1PT
        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
        BL      Init_MapIn                      ; map it in
        ; DMA regions won't get cleared by ClearPhysRam, so do it manually
        ; 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"

1658 1659 1660 1661 1662
; Map a range of physical addresses to a range of logical addresses.
;
; On entry:
;    a1 = physical address
;    a2 = logical address
1663
;    a3 = DA flags
1664
;    a4 = area size (4K multiple)
1665 1666 1667 1668 1669
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    v3 -> L1PT (or 0 if MMU on)

Init_MapIn ROUT
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
        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
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT
        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.
1685
        MOVS    ip, lr, LSL #12                 ; If all bottom 20 bits 0
1686 1687 1688
        BEQ     %FT50                           ; it's section mapped

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

Kevin Bracey's avatar
Kevin Bracey committed
1690
        MOVS    ip, lr, LSL #16                 ; If bottom 16 bits not all 0
1691 1692
        ADR     lr, %FT10
        BNE     Get4KPTE                        ; then small pages (4K)
Kevin Bracey's avatar
Kevin Bracey committed
1693

1694
        BL      Get64KPTE                       ; else large pages (64K)
Kevin Bracey's avatar
Kevin Bracey committed
1695
10
1696
        MOV     v6, a1                          ; v6 = access permissions
1697 1698 1699 1700 1701 1702 1703 1704 1705

20      MOV     a1, v4
        MOV     a2, v5
        MOV     a3, v6
        BL      Init_MapInPage                  ; Loop through mapping in each
        ADD     v4, v4, #4096                   ; page in turn
        ADD     v5, v5, #4096
        SUBS    v7, v7, #4096
        BNE     %BT20
1706
        EXIT
1707

1708 1709
50
        BL      Get1MPTE
1710 1711
        MOVS    ip, v3                          ; is MMU on?
        LDREQ   ip, =L1PT                       ; then use virtual address
1712
        ADD     a2, ip, v5, LSR #18             ; a2 -> L1PT entry
1713 1714
70      STR     a1, [a2], #4                    ; And store in L1PT
        ADD     a1, a1, #1024*1024              ; Advance one megabyte
1715
        SUBS    v7, v7, #1024*1024              ; and loop
1716
        BNE     %BT70
1717
        EXIT
1718 1719 1720 1721 1722 1723

; Map a logical page to a physical page, allocating L2PT as necessary.
;
; On entry:
;    a1 = physical address
;    a2 = logical address
Kevin Bracey's avatar
Kevin Bracey committed
1724
;    a3 = access permissions + C + B bits + size (all non-address bits, of appropriate type)
1725 1726 1727 1728 1729 1730 1731
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    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
1732
;
1733

1734 1735
Init_MapInPage  ROUT
        Entry   "v4-v6"
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
        MOV     v4, a1                          ; v4 = physical address
        MOV     v5, a2                          ; v5 = logical address
        MOV     v6, a3                          ; v6 = access permissions
        MOV     a1, v5
        MOV     a2, #4096
        BL      AllocateL2PT
        TEQ     v3, #0                          ; if MMU on, access L2PT virtually...
        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
1751 1752
40      AND     lr, v6, #3
        TEQ     lr, #L2_LargePage               ; strip out surplus address bits from
1753 1754
        BICEQ   v4, v4, #&0000F000              ; large page descriptors
        ORR     lr, v4, v6                      ; lr = value for L2PT entry
1755 1756
        STR     lr, [a1, ip, LSR #10]           ; update L2PT entry
        MOV     a1, v5
1757
        EXIT
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769



; On entry:
;    a1 = virtual address L2PT required for
;    a2 = number of bytes of virtual space
;    v1 -> current entry in PhysRamTable
;    v2 = last used physical address
;    v3 -> L1PT (or 0 if MMU on)
; On exit
;    a1-a4,ip corrupt
;    v1, v2 updated
1770 1771
AllocateL2PT ROUT
        Entry   "v4-v8"
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810
        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

1811
      [ MEMM_Type = "VMSAv6"
1812
        ORR     a3, a1, #L1_Page
1813 1814 1815
      |
        ORR     a3, a1, #L1_Page + L1_U         ; Set the U bit for ARM6 (assume L2 pages will generally be cacheable)
      ]
1816
        AND     lr, v8, #3
1817 1818
        ORR     a3, a3, lr, LSL #10
        STR     a3, [v6, v8, LSL #2]            ; fill in the L1PT
1819

1820 1821 1822 1823 1824 1825 1826 1827 1828
; 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
        MOVEQ   a1, #L1_B                       ; if so, map in v4
        MOVEQ   a2, v4
1829 1830
        SUBEQ   sp, sp, #4
        MOVEQ   a3, sp
1831 1832 1833 1834 1835
        BLEQ    RISCOS_AccessPhysicalAddress

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

1837 1838 1839 1840
        TEQ     v3, #0
        LDREQ   a1, [sp], #4
        BLEQ    RISCOS_ReleasePhysicalAddress

1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
        ; Get the correct page table entry flags for Init_MapInPage
        TEQ     v3, #0
        LDREQ   a3, =ZeroPage
        ADDNE   a3, v3, #DRAMOffset_PageZero-DRAMOffset_L1PT
        LDR     a4, [a3, #MMU_PCBTrans]
        LDR     a3, [a3, #MMU_PPLTrans]
        MOV     a1, #0
        LDR     a2, =AreaFlags_L2PT
        BL      Get4KPTE

        MOV     a3, a1
1852
        MOV     a1, v4                          ; Map in the L2PT page itself
1853 1854
        LDR     a2, =L2PT                       ; (can't recurse, because L2PT
        ADD     a2, a2, v8, LSL #10             ; backing for L2PT is preallocated)
1855 1856 1857
        BIC     a2, a2, #&C00
        BL      Init_MapInPage

1858

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

1863
        EXIT
1864 1865 1866


; void *RISCOS_AccessPhysicalAddress(unsigned int flags, void *addr, void **oldp)
1867
RISCOS_AccessPhysicalAddress ROUT
1868 1869 1870 1871 1872 1873
        ; Only flag user can ask for is bufferable
        ; Convert to appropriate DA flags
        ; (n.b. since this is an internal routine we should really change it to pass in DA flags directly)
        TST     a1, #L1_B
        LDR     a1, =OSAP_None + DynAreaFlags_NotCacheable ; SVC RW, USR none
        ORREQ   a1, a1, #DynAreaFlags_NotBufferable
1874
RISCOS_AccessPhysicalAddressUnchecked                   ; well OK then, I trust you know what you're doing
1875
        LDR     ip, =L1PT + (PhysicalAccess:SHR:18)     ; ip -> L1PT entry
1876 1877 1878
        MOV     a4, a2, LSR #20                         ; rounded to section
        MOV     a4, a4, LSL #20
        GetPTE  a1, 1M, a4, a1                          ; a1 = complete descriptor
1879
 [ MEMM_Type = "VMSAv6"
1880
        ORR     a1, a1, #L1_XN                          ; force non-executable to prevent speculative instruction fetches
Kevin Bracey's avatar
Kevin Bracey committed
1881
 ]
1882 1883 1884 1885 1886
        TEQ     a3, #0
        LDRNE   a4, [ip]                                ; read old value (if necessary)
        STR     a1, [ip]                                ; store new one
        STRNE   a4, [a3]                                ; put old one in [oldp]

1887 1888 1889 1890
        LDR     a1, =PhysicalAccess
        MOV     a3, a2, LSL #12                         ; take bottom 20 bits of address
        ORR     a3, a1, a3, LSR #12                     ; and make an offset within PhysicalAccess
        Push    "a3,lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
1891
        ARMop   MMU_ChangingUncached                    ; sufficient, cause not cacheable
1892
        Pull    "a1,pc"
1893 1894 1895 1896 1897 1898

; void RISCOS_ReleasePhysicalAddress(void *old)
RISCOS_ReleasePhysicalAddress
        LDR     ip, =L1PT + (PhysicalAccess:SHR:18)     ; ip -> L1PT entry
        STR     a1, [ip]
        LDR     a1, =PhysicalAccess
Jeffrey Lee's avatar
Jeffrey Lee committed
1899
        ARMop   MMU_ChangingUncached,,tailcall          ; sufficient, cause not cacheable
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913


; 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
1914
        BNE     %FT01
1915
        MCREQ   ARM_config_cp,0,ip,ARMv3_TLBflush_reg,C0
Ben Avison's avatar
Ben Avison committed
1916 1917 1918
        B       %FT02
01      MCRNE   ARM_config_cp,0,ip,ARMv4_TLB_reg,C7
02
1919
 [ MEMM_Type = "VMSAv6"
1920
        CMP     a1, #ARMvF
Ben Avison's avatar
Ben Avison committed
1921 1922
        ADREQ   lr, %FT01
        BEQ     HAL_InvalidateCache_ARMvF
1923
        MCRNE   ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
Ben Avison's avatar
Ben Avison committed
1924
01
1925 1926 1927
 |
        MCR     ARM_config_cp,0,ip,ARMv4_cache_reg,C7           ; works on ARMv3
 ]
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
        MOV     pc, a3




;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ClearPhysRAM - Routine to clear "all" memory
;
; While this routine is running, keyboard IRQs may happen. For this reason
; it avoids the base of logical RAM (hardware IRQ vector and workspace).
;
1940 1941 1942 1943 1944 1945
; We also have to avoid anything between InitUsedStart and InitUsedEnd - i.e.
; 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
1946

1947 1948 1949 1950
; We don't have to worry about trampling on the ROM image as it's already been
; excluded from PhysRamTable. We also don't have to worry about skipping the
; special DMA block, because at this point in time that won't be listed in
; PhysRamTable either.
1951 1952

;
1953
; out:  r4-r11, r13 preserved
1954 1955 1956
;

ClearPhysRAM ROUT
1957
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; get some extra registers
1958 1959 1960 1961 1962 1963 1964
        MOV     r8, #0
        MOV     r9, #0
        MOV     r10, #0
        MOV     r11, #0
        MOV     r12, #0
        MOV     r13, #0
        MOV     r14, #0
1965
        MSR     CPSR_c, #F32_bit+SVC32_mode
1966 1967

;now let us do the clear
1968
        LDR     r0,=ZeroPage+InitClearRamWs             ;we can preserve r4-r11,lr in one of the skipped regions
1969
        STMIA   r0,{r4-r11,lr}
1970

1971 1972
        DebugTX "ClearPhysRAM"

1973 1974 1975 1976 1977
        ; 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
1978
        ADR     r6, RamSkipTable
1979 1980
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; switch to our bank o'zeros
        LDR     r5, [r6], #4                            ; load first skip addr
1981
10
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
        TEQ     r0, r1
        TEQNE   r0, r5
        STMNEIA r0!, {r8-r11}
        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
2001

2002 2003 2004 2005 2006 2007
        ; Now walk PhysRamTable and clear everything else, except for the stuff
        ; between InitUsedStart and InitUsedEnd.
        ;
        ; To skip these areas properly, we convert their addresses to physical
        ; page numbers. This is because PhysRamTable isn't guaranteed to be in
        ; ascending address order.
2008

2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
        MSR     CPSR_c, #F32_bit+SVC32_mode
        LDR     r9, =ZeroPage
        LDR     r5, [r9, #InitUsedStart]
        SUB     r0, r5, #DRAMOffset_L1PT                ; Scratch space + zero page are already cleared, so add them to InitUsedStart..InitUsedEnd
        BL      PhysAddrToPageNo
        ; If the DMA region was taken from the first RAM block, we won't be able to look up the page number
        ; Instead, let's use the first DRAM page for InitUsedStart - as this will correspond to the first page that isn't hidden inside the DMA region
        CMP     r0, #-1
        LDREQ   r0, [r9, #DRAMPhysAddrA]
        BLEQ    PhysAddrToPageNo
        MOV     r5, r0
        LDR     r0, [r9, #InitUsedEnd]
        BL      PhysAddrToPageNo
        SUB     r6, r0, #1
        ADD     r9, r9, #PhysRamTable
        MOV     r4, #0                                  ; current page no
        LDMIA   r9!, {r10, r11}
        MOV     r11, r11, LSR #12                       ; get rid of flags
50
Jeffrey Lee's avatar
Jeffrey Lee committed
2028 2029 2030 2031
        ; Map in this area, cacheable + bufferable to ensure burst writes are
        ; performed. We're careful to not partially overwrite any pages which
        ; are being used, so this shouldn't cause any issues due to being
        ; cachable + potentially doubly mapped.
2032
        MOV     r0, #0
2033
        MOV     r1, r10
2034
        MOV     r2, #0
2035 2036
        BL      RISCOS_AccessPhysicalAddressUnchecked

2037 2038
        ; Inner loop will process one page at a time to keep things simple
        MOV     r3, r11
2039
        MSR     CPSR_c, #F32_bit+FIQ32_mode             ; switch to our bank o'zeros
Jeffrey Lee's avatar
Jeffrey Lee committed
2040
        MOV     r2, #0
2041 2042 2043
60
        CMP     r4, r5
        CMPHS   r6, r4
Jeffrey Lee's avatar
Jeffrey Lee committed
2044
        ADD     r1, r0, #4096
2045 2046 2047
        BHS     %FT80
        ; Clear this page
70
Jeffrey Lee's avatar
Jeffrey Lee committed
2048 2049
        STMIA   r0!, {r2,r8-r14}
        STMIA   r0!, {r2,r8-r14}
2050
        TEQ     r0, r1
2051 2052
        BNE     %BT70
80
Jeffrey Lee's avatar
Jeffrey Lee committed
2053
        MOV     r0, r1                                  ; increment log addr
2054 2055 2056 2057
        ADD     r4, r4, #1                              ; increment page no
        SUBS    r3, r3, #1                              ; decrement length
        MOVNES  r1, r0, LSL #12                         ; check for MB limit
        BNE     %BT60
2058

2059 2060
        MSR     CPSR_c, #F32_bit+SVC32_mode

Jeffrey Lee's avatar
Jeffrey Lee committed
2061 2062 2063 2064 2065 2066 2067 2068
        ; Make page uncacheable so the following is safe
        Push    "r0-r3"
        MOV     r0, #L1_B
        MOV     r1, r10
        MOV     r2, #0
        BL      RISCOS_AccessPhysicalAddress
        Pull    "r0-r3"

Jeffrey Lee's avatar
Jeffrey Lee committed
2069
        ; Clean & invalidate the cache before the 1MB window closes
Jeffrey Lee's avatar
Jeffrey Lee committed
2070
      [ CacheCleanerHack
Jeffrey Lee's avatar
Jeffrey Lee committed
2071 2072 2073
        ; 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)
2074 2075 2076 2077 2078 2079 2080 2081 2082
        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
Jeffrey Lee's avatar
Jeffrey Lee committed
2083
        B       %FT91
2084 2085
90
      ]
Jeffrey Lee's avatar
Jeffrey Lee committed
2086 2087 2088
        ARMop Cache_CleanInvalidateAll
91

2089 2090 2091 2092 2093 2094
        ADD     r10, r10, r11, LSL #12                  ; r10+(r11-r3) = next MB
        MOVS    r11, r3                                 ; next block needed? also resets r11 ready for next pass
        SUBNE   r10, r10, r3, LSL #12
        LDMEQIA r9!, {r10, r11}                         ; grab next block if necessary
        MOVEQS  r11, r11, LSR #12                       ; anything left to do?
        BNE     %BT50
2095

2096 2097 2098
        MOV     a1, #L1_Fault
        BL      RISCOS_ReleasePhysicalAddress           ; reset to default

Jeffrey Lee's avatar
Jeffrey Lee committed
2099
        LDR     r0, =ZeroPage+InitClearRamWs
2100
        LDMIA   r0, {r4-r11,r14}                        ;restore
2101 2102 2103

CPR_skipped

Jeffrey Lee's avatar
Jeffrey Lee committed
2104
        LDR     r0, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
2105 2106 2107 2108

        MOV     r1, #&80
        STRB    r1, [r0]                                ; flag the fact that RAM cleared

2109
        MSR     CPSR_c, #F32_bit + UND32_mode           ; retrieve the MMU control register
Jeffrey Lee's avatar
Jeffrey Lee committed
2110
        LDR     r0, =ZeroPage                           ; soft copy
2111
        STR     sp, [r0, #MMUControlSoftCopy]
2112 2113 2114 2115 2116 2117 2118
        MSR     CPSR_c, #F32_bit + SVC32_mode

        MOV     pc, lr

        LTORG

        MACRO
2119
        MakeSkipTable $addr, $size
Jeffrey Lee's avatar
Jeffrey Lee committed
2120 2121
        ASSERT  ($addr :AND: 31) = 0
        ASSERT  ($size :AND: 31) = 0
2122
        &       $addr, $size
2123 2124 2125 2126 2127 2128 2129 2130 2131
        MEND

        MACRO
        EndSkipTables
        &       -1
        MEND


RamSkipTable
2132 2133
        MakeSkipTable   ZeroPage, InitWsEnd
        MakeSkipTable   ZeroPage+SkippedTables, SkippedTablesEnd-SkippedTables
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
        EndSkipTables


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
2144
        LDR     pc, InitProcVecs + InitIRQHandler       ; IRQ
2145 2146 2147 2148 2149
        BKPT    &C01C                                   ; FIQ
InitProcVec_FIQ
        DCD     0
InitProcVecsEnd

2150
;
2151 2152 2153
; In:  a1 = flags  (L1_B,L1_C,L1_TEX)
;           bit 20 set if doubly mapped
;           bit 21 set if L1_AP specified (else default to AP_None)
2154 2155 2156 2157 2158 2159 2160
;      a2 = physical address
;      a3 = size
; Out: a1 = assigned logical address, or 0 if failed (no room)
;
; Will detect and return I/O space already mapped appropriately, or map and return new space
; For simplicity and speed of search, works on a section (1Mb) granularity
;
Kevin Bracey's avatar
Kevin Bracey committed
2161 2162

        ASSERT  L1_B = 1:SHL:2
2163
        ASSERT  L1_C = 1:SHL:3
2164 2165
 [ MEMM_Type = "VMSAv6"
        ASSERT  L1_AP = 2_100011 :SHL: 10
2166
        ASSERT  L1_TEX = 2_111 :SHL: 12
2167
 |
2168
        ASSERT  L1_AP = 3:SHL:10
2169
        ASSERT  L1_TEX = 2_1111 :SHL: 12
2170
 ]
2171 2172
MapInFlag_DoublyMapped * 1:SHL:20
MapInFlag_APSpecified * 1:SHL:21
Kevin Bracey's avatar
Kevin Bracey committed
2173

2174
RISCOS_MapInIO ROUT
2175
        TST     a1, #MapInFlag_APSpecified
2176
        BICEQ   a1, a1, #L1_AP
2177
        ; For VMSAv6, assume HAL knows what it's doing and requests correct settings for AP_ROM
2178
        ORREQ   a1, a1, #L1_APMult * AP_None
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
        BIC     a1, a1, #3
 [ MEMM_Type = "VMSAv6"
        ORR     a1, a1, #L1_Section+L1_XN               ; force non-executable to prevent speculative instruction fetches
 |
        ORR     a1, a1, #L1_Section
 ]
RISCOS_MapInIO_PTE ; a1 bits 0-19 = L1 section entry flags, bits 20+ = our extra flags
        Entry   "v1-v5,v7"
        LDR     v7, =(1:SHL:20)-1
        AND     v4, a2, v7                              ; v4 = offset of original within section-aligned area
        ADD     a3, a2, a3                              ; a3 -> end (exclusive)
        BIC     a2, a2, v7                              ; round a2 down to a section boundary
        ADD     a3, a3, v7
        BIC     a3, a3, v7                              ; round a3 up to a section boundary
2193

2194
        ANDS    v5, a1, #MapInFlag_DoublyMapped
Kevin Bracey's avatar
Kevin Bracey committed
2195 2196
        SUBNE   v5, a3, a2                              ; v5 = offset of second mapping or 0

2197 2198
        LDR     ip, =ZeroPage
        LDR     a4, =L1PT
2199
        AND     a1, a1, v7                              ; mask out our extra flags
2200 2201
        LDR     v2, =IO                                 ; logical end (exclusive) of currently mapped IO
        LDR     v1, [ip, #IOAllocPtr]                   ; logical start (inclusive)
2202

2203 2204 2205 2206 2207 2208 2209 2210 2211
        SUB     v1, v1, #&100000
10
        ADD     v1, v1, #&100000                        ; next mapped IO section
        CMP     v1, v2
        BHS     %FT32                                   ; no more currently mapped IO
        LDR     v3, [a4, v1, LSR #(20-2)]               ; L1PT entry (must be for mapped IO)
        MOV     lr, v3, LSR #20                         ; physical address bits
        CMP     lr, a2, LSR #20
        BNE     %BT10                                   ; no address match
2212
        AND     lr, v3, v7
2213 2214
        TEQ     lr, a1
        BNE     %BT10                                   ; no flags match
Kevin Bracey's avatar
Kevin Bracey committed
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225

        TEQ     v5, #0                                  ; doubly mapped?
        BEQ     %FT19

        ADD     lr, v1, v5                              ; address of second copy
        CMP     lr, v2
        BHS     %FT32
        LDR     v3, [a4, lr, LSR #(20-2)]
        MOV     lr, v3, LSR #20                         ; physical address bits
        CMP     lr, a2, LSR #20
        BNE     %BT10                                   ; no address match
2226
        AND     lr, v3, v7
Kevin Bracey's avatar
Kevin Bracey committed
2227 2228 2229 2230
        TEQ     lr, a1
        BNE     %BT10                                   ; no flags match

19
2231
;
2232
; alright, found start of requested IO already mapped, and with required flags
2233 2234 2235 2236 2237 2238 2239 2240 2241
;
        Push    "a2, v1"
20
        ADD     a2, a2, #&100000
        CMP     a2, a3
        Pull    "a2, v1", HS
        BHS     %FT40                                  ; its all there already!
        ADD     v1, v1, #&100000                       ; next mapped IO section
        CMP     v1, v2
Kevin Bracey's avatar
Kevin Bracey committed
2242
        BHS     %FT30                                  ; no more currently mapped IO
2243 2244 2245
        LDR     v3, [a4, v1, LSR #(20-2)]              ; L1PT entry
        MOV     lr, v3, LSR #20                        ; physical address bits
        CMP     lr, a2, LSR #20
Kevin Bracey's avatar
Kevin Bracey committed
2246
        BNE     %FT29                                  ; address match failed
2247
        AND     lr, v3, v7
2248
        TEQ     lr, a1
Kevin Bracey's avatar
Kevin Bracey committed
2249
        TEQEQ   v5, #0                                 ; doubly mapped?
2250
        BEQ     %BT20                                  ; address and flags match so far
Kevin Bracey's avatar
Kevin Bracey committed
2251 2252 2253 2254 2255 2256 2257
        ADD     lr, v1, v5                             ; where duplicate should be
        CMP     lr, v2
        BHS     %FT30                                  ; no more currently mapped IO
        LDR     v3, [a4, lr, LSR #(20-2)]
        MOV     lr, v3, LSR #20                        ; physical address bits
        CMP     lr, a2, LSR #20
        BNE     %FT29                                  ; address match failed
2258
        AND     lr, v3, v7
Kevin Bracey's avatar
Kevin Bracey committed
2259 2260 2261 2262 2263
        TEQ     lr, a1
        BEQ     %BT20
29
        Pull    "a2, v1"
        B       %BT10
2264 2265 2266
30
        Pull    "a2, v1"
;
2267
; request not currently mapped, only partially mapped, or mapped with wrong flags
2268 2269
;
32
Jeffrey Lee's avatar
Jeffrey Lee committed
2270
        LDR     ip, =ZeroPage
2271 2272 2273
        LDR     v2, [ip, #IOAllocPtr]
        ADD     v1, v2, a2
        SUB     v1, v1, a3                              ; attempt to allocate size of a3-a2
Kevin Bracey's avatar
Kevin Bracey committed
2274
        SUB     v1, v1, v5                              ; double if necessary
2275 2276 2277 2278 2279
        LDR     v3, [ip, #IOAllocLimit]                 ; can't extend down below limit
        CMP     v1, v3
        MOVLS   a1, #0
        BLS     %FT90
        STR     v1, [ip, #IOAllocPtr]
2280
        ORR     a2, a2, a1                              ; first L1PT value
2281 2282
34
        STR     a2, [a4, v1, LSR #(20-2)]
Kevin Bracey's avatar
Kevin Bracey committed
2283 2284 2285
        TEQ     v5, #0
        ADDNE   v2, v1, v5
        STRNE   a2, [a4, v2, LSR #(20-2)]
2286 2287 2288 2289
        ADD     a2, a2, #&100000
        ADD     v1, v1, #&100000                        ; next section
        CMP     a2, a3
        BLO     %BT34
Jeffrey Lee's avatar
Jeffrey Lee committed
2290 2291 2292 2293 2294 2295
      [ MEMM_Type = "VMSAv6"
        ; DSB + ISB required to ensure effect of page table write is fully
        ; visible (after overwriting a faulting entry)
        myDSB   ,a1
        myISB   ,a1,,y
      ]
2296 2297 2298 2299 2300
        LDR     v1, [ip, #IOAllocPtr]
40
        ADD     a1, v1, v4                              ; logical address for request
90
        EXIT
2301 2302


Ben Avison's avatar
Ben Avison committed
2303 2304 2305 2306 2307
; void RISCOS_AddDevice(unsigned int flags, struct device *d)
RISCOS_AddDevice
        ADDS    a1, a2, #0      ; also clears V
        B       HardwareDeviceAdd_Common

2308
; uint32_t RISCOS_LogToPhys(const void *log)
2309
RISCOS_LogToPhys ROUT
2310 2311 2312 2313 2314
        Push    "r4,r5,r8,r9,lr"
        MOV     r4, a1
        LDR     r8, =L2PT
        BL      logical_to_physical
        MOVCC   a1, r5
2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335
        BCC     %FT10
        ; Try checking L1PT for any section mappings (logical_to_physical only
        ; deals with regular 4K page mappings)
        ; TODO - Add large page support
        LDR     r9, =L1PT
        MOV     r5, r4, LSR #20
        LDR     a1, [r9, r5, LSL #2]
        ASSERT  L1_Section = 2
        EOR     a1, a1, #2
        TST     a1, #3
        MOVNE   a1, #-1
        BNE     %FT10
        ; Apply offset from bits 0-19 of logical addr
      [ NoARMT2
        MOV     a1, a1, LSR #20
        ORR     a1, a1, r4, LSL #12
        MOV     a1, a1, ROR #12
      |
        BFI     a1, r4, #0, #20
      ]
10
2336 2337
        Pull    "r4,r5,r8,r9,pc"

Robert Sprowson's avatar
Robert Sprowson committed
2338 2339
; int RISCOS_IICOpV(IICDesc *descs, uint32_t ndesc_and_bus)
RISCOS_IICOpV ROUT
2340 2341
        Push    "lr"
        BL      IIC_OpV
Robert Sprowson's avatar
Robert Sprowson committed
2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
        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]
2352
        Pull    "pc"
Robert Sprowson's avatar
Robert Sprowson committed
2353 2354 2355 2356 2357
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
2358

2359 2360 2361 2362 2363 2364 2365 2366
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)
2367 2368
10      SUBS    ip, ip, #1                              ; decrement counter
        LDRCS   a1, [a2], #4
2369
        BCC     %FT20
Kevin Bracey's avatar
Kevin Bracey committed
2370 2371 2372
        TEQ     a1, #0
        ADREQ   a1, NullHALEntry
        ADDNE   a1, a4, a1                              ; convert offset to absolute
2373
        STR     a1, [a3, #-4]!                          ; store backwards below HAL workspace
2374
        B       %BT10
2375 2376 2377 2378 2379 2380 2381 2382
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

2383

Kevin Bracey's avatar
Kevin Bracey committed
2384 2385 2386 2387 2388 2389
NullHALEntry
        MOV     pc, lr

; Can freely corrupt r10-r12 (v7,v8,ip).
HardwareSWI
        AND     ip, v5, #&FF
2390 2391 2392 2393 2394 2395 2396 2397

        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
2398 2399
        BLO     HardwareDeviceAdd
        BEQ     HardwareDeviceRemove
2400

Ben Avison's avatar
Ben Avison committed
2401 2402 2403
        CMP     ip, #OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerate < OSHW_DeviceEnumerateChrono
        ASSERT  OSHW_DeviceEnumerateChrono < OSHW_MaxSubreason
Ben Avison's avatar
Ben Avison committed
2404
        BLO     HardwareDeviceEnumerate
Ben Avison's avatar
Ben Avison committed
2405 2406
        BEQ     HardwareDeviceEnumerateChrono
        BHI     HardwareBadReason
Kevin Bracey's avatar
Kevin Bracey committed
2407

2408
HardwareCallHAL
Kevin Bracey's avatar
Kevin Bracey committed
2409 2410
        Push    "v1-v4,sb,lr"
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2411
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2412 2413
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip                                   ; sb set up
2414
        LDR     v7, [v7, #HALDesc_NumEntries]           ; v7 = number of entries
Kevin Bracey's avatar
Kevin Bracey committed
2415
        CMP     v8, v7                                  ; entryno + 1 must be <= number of entries
2416
        BHI     HardwareBadEntry2
Kevin Bracey's avatar
Kevin Bracey committed
2417 2418 2419
        LDR     ip, [sb, -v8, LSL #2]
        ADR     v7, NullHALEntry
        TEQ     ip, v7
2420
        BEQ     HardwareBadEntry2
2421
      [ NoARMv5
Kevin Bracey's avatar
Kevin Bracey committed
2422 2423
        MOV     lr, pc
        MOV     pc, ip
2424 2425 2426
      |
        BLX     ip
      ]
Kevin Bracey's avatar
Kevin Bracey committed
2427 2428 2429 2430
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
        ExitSWIHandler

2431
HardwareLookupRoutine
Kevin Bracey's avatar
Kevin Bracey committed
2432
        ADD     v8, sb, #1                              ; v8 = entry no + 1
Jeffrey Lee's avatar
Jeffrey Lee committed
2433
        LDR     ip, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2434 2435
        LDR     v7, [ip, #HAL_Descriptor]
        AddressHAL ip
2436
        LDR     v7, [v7, #HALDesc_NumEntries]
Kevin Bracey's avatar
Kevin Bracey committed
2437 2438 2439 2440 2441 2442 2443 2444 2445
        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
2446
HardwareDeviceAdd
2447
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2448
        BL      HardwareDeviceAdd_Common
2449
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2450 2451 2452
        B       SLVK_TestV

HardwareDeviceRemove
2453
        Push    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2454
        BL      HardwareDeviceRemove_Common
2455
        Pull    "r1-r3,lr"
Ben Avison's avatar
Ben Avison committed
2456 2457 2458
        B       SLVK_TestV

HardwareDeviceAdd_Common
2459
        Entry
Ben Avison's avatar
Ben Avison committed
2460 2461
        BL      HardwareDeviceRemove_Common             ; first try to remove any device already at the same address
        EXIT    VS
Jeffrey Lee's avatar
Jeffrey Lee committed
2462
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2463 2464 2465 2466
        LDR     r1, [lr, #DeviceCount]
        LDR     r2, [lr, #DeviceTable]
        TEQ     r2, #0
        BEQ     %FT80
2467 2468
        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
2469 2470
        TEQ     r1, lr, LSR #2                          ; block already full?
        BEQ     %FT81
Jeffrey Lee's avatar
Jeffrey Lee committed
2471
        LDR     lr, =ZeroPage
2472 2473 2474
10      STR     r1, [lr, #DeviceCount]
        ADD     lr, r2, r1, LSL #2
        SUB     lr, lr, #4
Ben Avison's avatar
Ben Avison committed
2475 2476 2477 2478 2479 2480
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
2481
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2482 2483 2484 2485 2486 2487
        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
2488
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2489 2490
        MOV     r3, #16
        BL      ClaimSysHeapNode
2491
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2492
        EXIT    VS
2493
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2494
        LDR     lr, =ZeroPage
2495 2496
        MOV     r1, #1
        STR     r2, [lr, #DeviceTable]
Ben Avison's avatar
Ben Avison committed
2497 2498 2499
        B       %BT10

81      ; Extend the system heap block
2500
        Push    "r0"
Ben Avison's avatar
Ben Avison committed
2501 2502 2503
        MOV     r0, #HeapReason_ExtendBlock
        MOV     r3, #16
        BL      DoSysHeapOpWithExtension
2504
        ADDVS   sp, sp, #4
Ben Avison's avatar
Ben Avison committed
2505
        EXIT    VS
2506
        Pull    "r0"
Jeffrey Lee's avatar
Jeffrey Lee committed
2507
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2508 2509
        LDR     r1, [lr, #DeviceCount]
        STR     r2, [lr, #DeviceTable]
2510
        ADD     r1, r1, #1
Ben Avison's avatar
Ben Avison committed
2511 2512 2513
        B       %BT10

HardwareDeviceRemove_Common
2514
        Entry   "r4"
Jeffrey Lee's avatar
Jeffrey Lee committed
2515
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2516 2517 2518 2519 2520
        LDR     r3, [lr, #DeviceCount]
        LDR     r4, [lr, #DeviceTable]
        TEQ     r3, #0
        EXIT    EQ                                      ; no devices registered
01      LDR     r2, [r4], #4
2521 2522
        SUBS    r3, r3, #1
        TEQNE   r2, r0
Ben Avison's avatar
Ben Avison committed
2523 2524 2525 2526
        BNE     %BT01
        TEQ     r2, r0
        EXIT    NE                                      ; this device not registered
        MOV     r0, #1
2527
        MOV     r1, #Service_Hardware
Ben Avison's avatar
Ben Avison committed
2528 2529
        BL      Issue_Service
        CMP     r1, #0                                  ; if service call claimed
2530
        CMPEQ   r1, #1:SHL:31                           ; then set V (r0 already points to error block)
Ben Avison's avatar
Ben Avison committed
2531 2532 2533
        EXIT    VS                                      ; and exit
        MOV     r0, r2
        SUBS    r3, r3, #1
2534 2535 2536 2537
02      LDRCS   r2, [r4], #4                            ; copy down remaining devices
        STRCS   r2, [r4, #-8]
        SUBCSS  r3, r3, #1
        BCS     %BT02
Jeffrey Lee's avatar
Jeffrey Lee committed
2538
        LDR     lr, =ZeroPage
2539 2540 2541
        LDR     r3, [lr, #DeviceCount]
        SUB     r3, r3, #1
        STR     r3, [lr, #DeviceCount]
Ben Avison's avatar
Ben Avison committed
2542 2543 2544 2545
        EXIT

HardwareDeviceEnumerate
        Push    "r3-r4,lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
2546
        LDR     lr, =ZeroPage
Ben Avison's avatar
Ben Avison committed
2547 2548 2549 2550 2551 2552 2553 2554
        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
2555 2556 2557
        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
2558 2559
        SUBNES  r4, r4, #1
        BNE     %BT10
2560
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
2561
        MOVNE   r1, #-1
2562 2563 2564 2565
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
2566 2567
        BLS     %FT90
        SUBS    r4, r4, #1
2568
        BHI     %BT10
2569
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
2570 2571 2572 2573
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Ben Avison's avatar
Ben Avison committed
2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586
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
2587
        MOVS    lr, lr, LSL #16                         ; EQ if types match
Ben Avison's avatar
Ben Avison committed
2588 2589
        SUBNES  r4, r4, #1
        BNE     %BT10
2590
        TEQ     lr, #0
Ben Avison's avatar
Ben Avison committed
2591
        MOVNE   r1, #-1
2592 2593 2594 2595
        BNE     %FT90
        LDR     lr, [r2, #HALDevice_Version]
        MOV     lr, lr, LSR #16
        CMP     lr, r0, LSR #16                         ; newer than our client understands?
2596 2597
        BLS     %FT90
        SUBS    r4, r4, #1
2598
        BHI     %BT10
2599
        MOV     r1, #-1
Ben Avison's avatar
Ben Avison committed
2600 2601 2602 2603
90
        Pull    "r3-r4,lr"
        ExitSWIHandler

Kevin Bracey's avatar
Kevin Bracey committed
2604 2605 2606 2607 2608 2609 2610 2611 2612
HardwareBadReason
        ADR     r0, ErrorBlock_HardwareBadReason
 [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
 ]
        B       SLVK_SetV

2613 2614 2615
HardwareBadEntry2
        ADD     sp, sp, #4*4
        Pull    "sb,lr"
Kevin Bracey's avatar
Kevin Bracey committed
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627
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
2628 2629 2630 2631 2632 2633 2634 2635 2636
 [ DebugTerminal
DebugTerminal_Rdch
        Push    "a2-a4,sb,ip"
        WritePSRc SVC_mode, r1
        MOV     sb, ip
20
        CallHAL HAL_DebugRX
        CMP     a1, #27
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
2637
        LDR     a2, =ZeroPage + OsbyteVars + :INDEX: RS423mode
Kevin Bracey's avatar
Kevin Bracey committed
2638 2639 2640
        LDRB    a2, [a2]
        TEQ     a2, #0                  ; is RS423 raw data,or keyb emulator?
        BNE     %FT25
Jeffrey Lee's avatar
Jeffrey Lee committed
2641
        LDR     a2, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2642 2643 2644 2645 2646 2647 2648 2649 2650
        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
2651
        LDR     R0, =ZeroPage
Kevin Bracey's avatar
Kevin Bracey committed
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667
        LDRB    R14, [R0, #CallBack_Flag]
        TST     R14, #CBack_VectorReq
        BLNE    process_callback_chain
        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
2668
        Push    "a1-a4,v1-v2,sb,ip,lr"
2669 2670 2671 2672 2673
        MRS     a1, SPSR
        MRS     a2, CPSR
        ORR     a3, a2, #SVC32_mode
        MSR     CPSR_c, a3
        Push    "a1-a2,lr"
Jeffrey Lee's avatar
Jeffrey Lee committed
2674
        ; If it's not an IIC interrupt, pass it on to the keyboard scan code
Jeffrey Lee's avatar
Jeffrey Lee committed
2675
        LDR     v2, =ZeroPage
2676
        AddressHAL v2
Jeffrey Lee's avatar
Jeffrey Lee committed
2677
        CallHAL HAL_IRQSource
Jeffrey Lee's avatar
Jeffrey Lee committed
2678
        ADD     v1, v2, #IICBus_Base
Jeffrey Lee's avatar
Jeffrey Lee committed
2679
        MOV     ip, #0
2680 2681
10
        LDR     a2, [v1, #IICBus_Type]
Kevin Bracey's avatar
Kevin Bracey committed
2682
        TST     a2, #IICFlag_Background
Jeffrey Lee's avatar
Jeffrey Lee committed
2683 2684 2685 2686 2687 2688 2689
        BEQ     %FT20
        LDR     a2, [v1, #IICBus_Device]
        CMP     a2, a1
        ADREQ   lr, Reset_IRQ_Exit
        BEQ     IICIRQ
20
        ADD     ip, ip, #1
2690
        ADD     v1, v1, #IICBus_Size
Jeffrey Lee's avatar
Jeffrey Lee committed
2691
        CMP     ip, #IICBus_Count
2692
        BNE     %BT10
Jeffrey Lee's avatar
Jeffrey Lee committed
2693 2694
        LDRB    a2, [v2, #InitIRQWs+KbdScanActive]
        TEQ     a2, #0
2695
        CallHAL HAL_KbdScanInterrupt,NE
Jeffrey Lee's avatar
Jeffrey Lee committed
2696 2697 2698 2699 2700 2701
        ; Keyboard scan code will have return -1 if it handled the IRQ
        ; If it didn't handle it, or keyboard scanning is inactive, something
        ; bad has happened
        CMP     a1, #-1
        CallHAL HAL_IRQDisable,NE ; Stop the rogue device from killing us completely
Reset_IRQ_Exit
2702
        MyCLREX a1, a2
2703 2704 2705
        Pull    "a1-a2,lr"
        MSR     CPSR_c, a2
        MSR     SPSR_cxsf, a1
2706
        Pull    "a1-a4,v1-v2,sb,ip,pc",,^
Kevin Bracey's avatar
Kevin Bracey committed
2707

2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718
 [ DebugHALTX
DebugHALPrint
        Push    "a1-a4,v1,sb,ip"
        AddressHAL
        MOV     v1, lr
10      LDRB    a1, [v1], #1
        TEQ     a1, #0
        BEQ     %FT20
        CallHAL HAL_DebugTX
        B       %BT10
20      MOV     a1, #13
2719
;        CallHAL HAL_DebugTX
2720
        MOV     a1, #10
2721
;        CallHAL HAL_DebugTX
2722 2723 2724 2725 2726 2727 2728 2729
        ADD     v1, v1, #3
        BIC     lr, v1, #3
        Pull    "a1-a4,v1,sb,ip"
        MOV     pc, lr
 ]


 [ DebugHALTX
2730 2731 2732 2733 2734 2735
DebugHALPrintReg ; Output number on top of stack to the serial port
        Push    "a1-a4,v1-v4,sb,ip,lr"   ; this is 11 regs
        LDR     v2, [sp,#11*4]           ; find TOS value on stack
        ADR     v3, hextab
        MOV     v4, #8
05
2736
       AddressHAL
2737
10      LDRB    a1, [v3, v2, LSR #28]
2738
       CallHAL  HAL_DebugTX
2739 2740 2741 2742
        MOV     v2, v2, LSL #4
        SUBS    v4, v4, #1
        BNE     %BT10
        MOV     a1, #13
2743
       CallHAL  HAL_DebugTX
2744
        MOV     a1, #10
2745 2746
       CallHAL  HAL_DebugTX

2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797
        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
;       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}
; ]
;
2798 2799
        END