Commit b51b5540 authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL
Browse files

Initial long descriptor support

This adds initial support for the "long descriptor" MMU page table
format, which allows the CPU to (flexibly) use a 40-bit physical address
space.

There are still some features that need fixing (e.g. RISCOS_MapInIO
flags), and the OS doesn't yet support RAM above the 32bit limit, but
this set of changes is enough to allow for working ROMs to be produced.

Also, move MMUControlSoftCopy initialisation out of ClearWkspRAM, since
it's unrelated to whether the HAL has cleared the RAM or not.
parent cf51151a
......@@ -298,8 +298,14 @@ UNDStackAddress ASpace UNDStackSize, &100000
DCacheCleanAddress ASpace &00040000, &10000 ; eg. for StrongARM, 256k of space
KbuffsBaseAddress ASpace KbuffsMaxSize ; kernel buffers for long command lines
HALWorkspaceNCNB ASpace &00008000 ; 32K of uncacheable HAL workspace (if requested)
[ LongDesc
LL3PT ASpace &00800000, &100000 ; 8MB of L3PT
LL2PT ASpace &00004000 ; 16KB of L2PT
LL1PT ASpace &00001000 ; 32 bytes of L1PT
|
L2PT ASpace &00400000, &400000
L1PT ASpace &00004000
]
ASSERT &FAFF0000-@ < &80000000
# &FAFF0000-@ ; padding to ensure SoundWorkSpace export is correct (in CursorChunkAddress)
CursorChunkAddress ASpace &00008000
......@@ -1156,7 +1162,7 @@ DRAMPhysTableSize * (PhysRamTableEnd-DRAMPhysAddrA) / 8
! 0, "VideoPhysAddr held at ":CC::STR:(VideoPhysAddr)
]
L2PTUsed # 4 ; Amount of memory used for L2PT
LxPTUsed # 4 ; Amount of memory used for L2PT (short desc) or L3PT (long desc)
SoftCamMapSize # 4 ; Amount of memory (in bytes) used for soft CAM map
; (whole number of pages)
......
......@@ -180,6 +180,11 @@ PMPParanoid SETL {FALSE} ; Validate PMPs after most ops
PMPRAMFS SETL {TRUE} ; Whether RAMFS DA is a PMP (requires compatible RAMFS module)
PMPRAMFS_Size * 256 ; Number of logical pages (physical size is unlimited)
[ :LNOT: :DEF: LongDesc
GBLL LongDesc
LongDesc SETL {FALSE} :LAND: MEMM_Type = "VMSAv6" ; Use long descriptor page table format?
]
GBLL CacheablePageTables
CacheablePageTables SETL {TRUE} ; Use cacheable page tables where possible
......
......@@ -209,7 +209,11 @@ AMB_SetMemMapEntries_MapOut_Lazy ROUT
GetTempUncache r12, r0, r11, lr ;r12 = temp uncache L2PT flags
MOV r4,r1 ;r4 = current index
[ LongDesc
LDR r11,=LL3PT+(ApplicationStart:SHR:(Log2PageSize-3));r11 -> L3PT, offset by appspace start
|
LDR r11,=L2PT+(ApplicationStart:SHR:(Log2PageSize-2));r11 -> L2PT, offset by appspace start
]
CMP r9,#1
BNE %FT32
B %FT31
......@@ -228,11 +232,20 @@ AMB_SetMemMapEntries_MapOut_Lazy ROUT
TST r8,r9
BEQ %FT34
; Mapped in page found, make uncacheable
[ LongDesc
ADD lr,r11,r4,LSL #3
LDRD r0,[lr] ;Get current L3PT entry
CMP r6,#0
BIC r0,r0,#TempUncache_L3PTMask
ORR r0,r0,r12
STRD r0,[lr] ;Update L2PT
|
LDR r0,[r11,r4,LSL #2] ;Get current L2PT entry
CMP r6,#0
BIC r0,r0,#TempUncache_L2PTMask
ORR r0,r0,r12
STR r0,[r11,r4,LSL #2] ;Update L2PT
]
BGE %FT33
; Do cache/TLB maintenance
MOV r1,r4,LSL #Log2PageSize
......@@ -299,12 +312,20 @@ AMB_SetMemMapEntries_MapOut_Lazy ROUT
TST r8,r9
BEQ %FT54
; Mapped in page found, unmap it
MOV lr,#0
LDR r0,[r10,r4,LSL #2] ;Get page number
STR lr,[r11,r4,LSL #2] ;Zero L2PT
[ LongDesc
MOV r0,#0
MOV r1,#0
ADD lr,r11,r4,LSL #3
STRD r0,[lr] ;Zero L3PT
LDR lr,[r10,r4,LSL #2] ;Get page number
|
MOV r0,#0
LDR lr,[r10,r4,LSL #2] ;Get page number
STR r0,[r11,r4,LSL #2] ;Zero L2PT
]
BIC r8,r8,r9
ASSERT CAM_LogAddr=0
STR r12,[r3,r0,LSL #CAM_EntrySizeLog2] ;Update CAM
STR r12,[r3,lr,LSL #CAM_EntrySizeLog2] ;Update CAM
CMP r6,#0
BGE %FT53
; Do TLB maintenance
......@@ -447,22 +468,26 @@ AMB_LazyFixUp ROUT
CMP r6,r5
SUBHS r6,r6,r5
BHS %BT10
[ {FALSE}
LDR r1,AMBPageFlags
ADD r4,r4,r6,LSL #12
ORR r4,r4,r1
MOV r1,#0 ;0 = AP for ordinary page
|
ADD r4,r4,r6,LSL #12
MOV r1,#DynAreaFlags_PMP
GetPTE r4,4K,r4,r1
]
;
;here, r0 = page index into appslot, r1 = PPL, r3 = page number of page involved, r4 = new L2PT entry value to map in page
;here, r0 = page index into appslot, r1 = PPL, r3 = page number of page involved
[ LongDesc
; r4,r5 = new L3PT entry value to map in page
|
; r4 = new L2PT entry value to map in page
]
;
ADD r0,r0,#ApplicationStart:SHR:Log2PageSize ;address now in terms of pages from 0
[ LongDesc
LDR r12,=LL3PT
ADD r12,r12,r0,LSL #3
STRD r4,[r12] ;update L3PT
|
LDR r5,=L2PT
STR r4,[r5,r0,LSL #2] ;update L2PT
]
;
LDR r5,=ZeroPage
LDR r5,[r5,#CamEntriesPointer]
......
......@@ -533,4 +533,6 @@ GetPageFlagsForCacheablePageTables ROUT
MOV pc, lr
]
GET s.ShortDesc
END
......@@ -70,6 +70,12 @@ Init_PCBTrans ROUT
LDR a2, =AreaFlags_PageTablesAccess :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable
STR a2, [a1, #PageTable_PageFlags]
[ MEMM_Type = "VMSAv6"
[ LongDesc
ADRL a2, XCBTableVMSAv6Long
STR a2, [a1, #MMU_PCBTrans]
ADRL a4, PPLTrans
STR a4, [a1, #MMU_PPLTrans]
|
ADRL a2, XCBTableVMSAv6
STR a2, [a1, #MMU_PCBTrans]
......@@ -93,6 +99,7 @@ Init_PCBTrans ROUT
ADDEQ a4, a4, #PPLTransShareable-PPLTransNonShareable
90
STR a4, [a1, #MMU_PPLTrans]
]
|
; Detecting the right PCBTrans table to use is complex
; However we know that, pre-MMU, we only use the default cache policy,
......@@ -4406,6 +4413,7 @@ XCBTableXScaleNoExt ; C+B CNB NCB N
[ MEMM_Type = "VMSAv6"
[ :LNOT: LongDesc
; VMSAv6/v7 L2 memory attributes (short descriptor format, TEX remap disabled)
L2_SO_S * 0 ; Strongly-ordered, shareable
......@@ -4477,6 +4485,52 @@ XCBTableVMSAv6 ; C+B CNB NCB
DCW L2_Nrm_NC, L2_SO_S, L2_Nrm_NC, L2_SO_S ; X, X, X, X
DCW L2_Nrm_NC, L2_SO_S, L2_Nrm_NC, L2_SO_S ; X, X, X, X
|
; Attributes for long-descriptor page table format
; This gives the AttrIndx field of the low attributes
; Our arbitrary AttrIndx mapping
LLAttr_Nrm_NC * 0:SHL:LL_Page_LowAttr_AttrIndx0_bit
LLAttr_Nrm_WBWA * 1:SHL:LL_Page_LowAttr_AttrIndx0_bit
LLAttr_Nrm_WBRA * 2:SHL:LL_Page_LowAttr_AttrIndx0_bit
LLAttr_Nrm_WT * 3:SHL:LL_Page_LowAttr_AttrIndx0_bit
LLAttr_SO * 4:SHL:LL_Page_LowAttr_AttrIndx0_bit
LLAttr_Dev * 5:SHL:LL_Page_LowAttr_AttrIndx0_bit
ASSERT LL_Page_LowAttr_AttrIndx2_bit < 8
; Reverse mapping table (directly before the forwards-mapping table)
DCD DynAreaFlags_NotCacheable ; LLAttr_Nrm_NC
DCD 0 ; LLAttr_Nrm_WBWA
DCD 2:SHL:DynAreaFlags_CPShift ; LLAttr_Nrm_WBRA
DCD 1:SHL:DynAreaFlags_CPShift ; LLAttr_Nrm_WT
DCD DynAreaFlags_NotCacheable+DynAreaFlags_NotBufferable ; LLAttr_SO
DCD DynAreaFlags_NotCacheable+1:SHL:DynAreaFlags_CPShift ; LLAttr_Dev
; Pad out the rest; MAIR Attr field value of 0 corresponds to strongly-ordered memory
DCD DynAreaFlags_NotCacheable+DynAreaFlags_NotBufferable ; LLAttr_SO
DCD DynAreaFlags_NotCacheable+DynAreaFlags_NotBufferable ; LLAttr_SO
XCBTableVMSAv6Long ; C+B CNB NCB NCNB
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; Default
DCB LLAttr_Nrm_WT, LLAttr_SO, LLAttr_Dev, LLAttr_SO ; WT, WT, Non-merging, X
DCB LLAttr_Nrm_WBRA, LLAttr_SO, LLAttr_Dev, LLAttr_SO ; WB/RA, WB, Merging, X
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; WB/WA, X, Idempotent, X
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; Alt DCache, X, X, X
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
DCB LLAttr_Nrm_WBWA, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
; This second set of entries deals with when pages are made
; temporarily uncacheable - we need to change the cacheability without
; changing the memory type.
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; Default
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Dev, LLAttr_SO ; WT, WT, Non-merging, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Dev, LLAttr_SO ; WB/RA, WB, Merging, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; WB/WA, X, Idempotent, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; Alt DCache, X, X, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
DCB LLAttr_Nrm_NC, LLAttr_SO, LLAttr_Nrm_NC, LLAttr_SO ; X, X, X, X
]
] ; MEMM_Type = "VMSAv6"
END
......@@ -1909,6 +1909,39 @@ DynArea_SparseChange ; common entry point for claim and relea
BNE %BT10
ADD r3,r2,r3 ;stop address
;
[ LongDesc
LDR r5,=LL3PT
ADD r5,r5,r2,LSR #9 ;r5 -> L3PT for base (assumes 4k page)
MOV r8,r2 ;start address
;
;look for next fragment of region that needs to have mapping change
20
CMP r8,r3
BHS %FT50 ;done
LDRD r6,[r5],#8 ;pick-up next L3PT entry
CMP r4,#0 ;if operation is a release...
CMPEQ r6,#0 ;...and L3PT entry is 0 (not mapped)...
ADDEQ r8,r8,#&1000 ;...then skip page (is ok)
BEQ %BT20
CMP r4,#0 ;if operation is a claim (not 0)...
CMPNE r6,#0 ;...and L3PT entry is non-0 (mapped)...
ADDNE r8,r8,#&1000 ;...then skip page (is ok)
BNE %BT20
MOV r1,#&1000 ;else we need to do a change (1 page so far)
30
ADD r9,r8,r1
CMP r9,r3
BHS %FT40
LDRD r6,[r5],#8 ;pick-up next L3PT entry
CMP r4,#1 ;if operation is a release (not 1)...
CMPNE r6,#0 ;...and L3PT entry is non-0 (mapped)...
ADDNE r1,r1,#&1000 ;...then count page as needing change
BNE %BT30
CMP r4,#1 ;if operation is a claim...
CMPEQ r6,#0 ;...and L3PT entry is 0 (not mapped)...
ADDEQ r1,r1,#&1000 ;...then count page as needing change
BEQ %BT30
|
LDR r5,=L2PT
ADD r5,r5,r2,LSR #10 ;r5 -> L2PT for base (assumes 4k page)
MOV r8,r2 ;start address
......@@ -1940,6 +1973,7 @@ DynArea_SparseChange ; common entry point for claim and relea
CMPEQ r6,#0 ;...and L2PT entry is 0 (not mapped)...
ADDEQ r1,r1,#&1000 ;...then count page as needing change
BEQ %BT30
]
;set up pseudo DA and do Batcall to change mapping of fragment we have found
40
MOV r2,SP ;temp DANode
......@@ -3307,7 +3341,11 @@ LogOp_MapOut ROUT
MOV r7, r3
LDR r12, [r12, #CamEntriesPointer]
LDR r3, =Nowhere
[ LongDesc
LDR r10, =LL3PT
|
LDR r10, =L2PT
]
MOV r9, #-1
05
LDR r11, [r7], #4
......@@ -3331,11 +3369,19 @@ LogOp_MapOut ROUT
GetTempUncache r2, lr, r1, r4
06
; Bypass BangCAM and update L2PT directly (avoids CAM gaining any unwanted temp uncacheability flags)
[ LongDesc
ADD lr, r10, r11, LSR #9
LDRD r4, [lr]
BIC r4, r4, #TempUncache_L3PTMask
ORR r4, r4, r2
STRD r4, [lr]
|
LDR r4, =TempUncache_L2PTMask
LDR lr, [r10, r11, LSR #10]
BIC lr, lr, r4
ORR lr, lr, r2
STR lr, [r10, r11, LSR #10]
]
; r6 bit 0 set if TLB+cache invalidation done on per-page basis
TST r6, #1
BEQ %FT07
......@@ -4409,7 +4455,7 @@ InitDynamicAreas Entry "r0-r12"
]
LDR lr, =ZeroPage+SysHeapDANode ; initialise system heap node
ADR r0, InitSysHeapTable
ADRL r0, InitSysHeapTable
LDMIA r0, {r0-r8}
STMIA lr, {r0-r8}
LDR r0, =ZeroPage
......@@ -4581,7 +4627,7 @@ DynArea_AddrLookup_loop
STR r0, [sp]
LDR r0, [r5, #InitUsedStart]
ADD r0, r0, #DRAMOffset_FirstFixed - DRAMOffset_L1PT
ADD r0, r0, #DRAMOffset_FirstFixed - DRAMOffset_PageTables
MOV r1, #0 ; only know 32-bit addresses for now
BL PhysAddrToPageNo
MOV r7, r0 ; r7 = page number of start of static chunk
......
......@@ -97,7 +97,6 @@
$GetUnsqueeze
GET s.ArthurSWIs
$GetKernelMEMC
GET s.ShortDesc
GET s.Exceptions
GET s.ChangeDyn
GET s.HAL
......
This diff is collapsed.
......@@ -119,6 +119,8 @@ $label LDR $reg, =ZeroPage+VduDriverWorkSpace
; *** Call Get4KPTE/Get64KPTE/Get1MPTE functions, ***
; *** with arbitrary in/out regs ***
; *****************************************************
GBLA GetPTEOut2
GetPTEOut2 SETA 0
MACRO
GetPTE $out, $size, $addr, $flags
Push "r0-r3,lr"
......@@ -138,6 +140,17 @@ $label LDR $reg, =ZeroPage+VduDriverWorkSpace
|
MOV $out, r0
]
[ LongDesc
GetPTEOut2 SETA GetPTEOut2 + 1
LCLS out2
out2 SETS "GetPTEOut2" :CC: :STR: GetPTEOut2
$out2 RN (:INDEX:$out)+1
[ $out2 < 4
STR r1, [sp, #:INDEX:$out2 * 4]
|
MOV $out2, r1
]
]
Pull "r0-r3,lr"
MEND
......
......@@ -24,13 +24,27 @@ memset
ADD a1, a1, a3
TST a1, #3 ; check for unaligned end
BNE %FT80
05 SUBS a3, a3, #32 ; if at least 32, do 32 at a time
BLO %FT50
Push "v1-v5"
05
AND a2, a2, #&FF
ORR a2, a2, a2, LSL #8
ORR a2, a2, a2, LSL #16
SUBS a3, a3, #32 ; if at least 32, do 32 at a time
BLO %FT50
[ LongDesc
; Use STRD to make sure this is safe to use for clearing page tables
Push "v1-v2"
MOV v1, a2
MOV v2, a2
10 STRD v1, [a1, #-8]!
STRD v1, [a1, #-8]!
STRD v1, [a1, #-8]!
STRD v1, [a1, #-8]!
SUBS a3, a3, #32
BHS %BT10
Pull "v1-v2"
|
Push "v1-v5"
MOV a4, a2
MOV v1, a2
MOV v2, a2
......@@ -42,6 +56,7 @@ memset
SUBS a3, a3, #32
BHS %BT10
Pull "v1-v5"
]
50 ADDS a3, a3, #32-4 ; if at least 4, do 4 at a time
BMI %FT70
......
; Copyright 1996 Acorn Computers Ltd
; Copyright 2016 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; Page table interaction - "long descriptor" format (ARMv7+ 8 bytes per entry)
; Note that to ensure page table reads & writes are seen as atomic by both the
; MMU and other CPU cores, we only use LDRD & STRD when reading/writing entries.
;----------------------------------------------------------------------------------------
; logical_to_physical
;
; In: r4 = logical address
;
; Out: r5 corrupt
; CC => r8,r9 = physical address
; CS => invalid logical address, r8,r9 corrupted
;
; Convert logical address to physical address.
;
logical_to_physical
LDR r9, =LL3PT
MOV r5, r4, LSR #12 ; r5 = logical page number
ADD r5, r9, r5, LSL #3 ; r5 -> L3PT entry for logical address
MOV r8, r5, LSR #12 ; r8 = page offset to L3PT entry for logical address
ADD r8, r9, r8, LSL #3 ; r8 -> L3PT entry for L3PT entry for logical address
LDRD r8, [r8]
ASSERT LL3_Page != 0
ASSERT LL_Fault = 0
TST r8, #LL3_Page ; Check for valid (4K) page
BEQ meminfo_returncs
LDRD r8, [r5]
TST r8, #LL3_Page ; Check for valid (4K) page
BEQ meminfo_returncs
BFI r8, r4, #0, #12 ; Valid, so apply offset within the page
AND r9, r9, #LL_HighAddr ; And high address mask
CLC
MOV pc, lr
[ CacheablePageTables
MakePageTablesCacheable ROUT
Entry "r0,r4-r5,r8-r9"
BL GetPageFlagsForCacheablePageTables
; Update PageTable_PageFlags
LDR r1, =ZeroPage
STR r0, [r1, #PageTable_PageFlags]
; Adjust the logical mapping of the page tables to use the specified page flags
LDR r1, =LL1PT
LDR r2, =4096 ; Round up to page multiple
BL AdjustMemoryPageFlags
LDR r1, =LL2PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =LL3PT
LDR r2, =8*1024*1024
BL AdjustMemoryPageFlags
; Update the TTBR
LDR r4, =LL1PT
BL logical_to_physical
MOV r0, r8 ; Assume only 32bit address
LDR r1, =ZeroPage
BL SetTTBR
; Perform a full TLB flush to make sure the new mappings are visible
ARMop TLB_InvalidateAll,,,r1
EXIT
MakePageTablesNonCacheable ROUT
Entry "r0-r1,r4-r5,r8-r9"
; Flush the page tables from the cache, so that when we update the TTBR
; below we can be sure that the MMU will be seeing the current page
; tables
LDR r0, =LL1PT
ADD r1, r0, #4096
LDR r4, =ZeroPage
ARMop Cache_CleanRange,,,r4
LDR r0, =LL2PT
ADD r1, r0, #16*1024
ARMop Cache_CleanRange,,,r4
LDR r0, =LL3PT
ADD r1, r0, #8*1024*1024
ARMop Cache_CleanRange,,,r4
; Update the TTBR so the MMU performs non-cacheable accesses
LDR r0, =AreaFlags_PageTablesAccess :OR: DynAreaFlags_NotCacheable :OR: DynAreaFlags_NotBufferable
STR r0, [r4, #PageTable_PageFlags]
LDR r4, =LL1PT
BL logical_to_physical
MOV r0, r8 ; Assume only 32bit address
LDR r1, =ZeroPage
BL SetTTBR
; Perform a full TLB flush just in case
ARMop TLB_InvalidateAll,,,r1
; Now we can adjust the logical mapping of the page tables to be non-cacheable
LDR r0, [r1, #PageTable_PageFlags]
LDR r1, =LL1PT
LDR r2, =4096
BL AdjustMemoryPageFlags
LDR r1, =LL2PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =LL3PT
LDR r2, =8*1024*1024
BL AdjustMemoryPageFlags
EXIT
]
;**************************************************************************
;
; AllocateBackingLevel2 - Allocate L3 pages for an area
;
; Internal routine called by DynArea_Create
;
; in: r3 = base address (will be page aligned)
; r4 = area flags (NB if doubly mapped, then have to allocate for both halves)
; r5 = size (of each half in doubly mapped areas)
;
; out: If successfully allocated pages, then
; All registers preserved
; V=0
; else
; r0 -> error
; V=1
; endif
AllocateBackingLevel2 Entry "r0-r8,r11"
TST r4, #DynAreaFlags_DoublyMapped ; if doubly mapped
SUBNE r3, r3, r5 ; then area starts further back
MOVNE r5, r5, LSL #1 ; and is twice the size
; NB no need to do sanity checks on addresses here, they've already been checked
; now round address range to 2M boundaries
ADD r5, r5, r3 ; r5 -> end
MOV r0, #1 :SHL: 21
SUB r0, r0, #1
BIC r8, r3, r0 ; round start address down (+ save for later)
ADD r5, r5, r0
BIC r5, r5, r0 ; but round end address up
; first go through existing L3PT working out how much we need
LDR r7, =LL3PT
ADD r3, r7, r8, LSR #9 ; r3 -> start of L3PT for area
ADD r5, r7, r5, LSR #9 ; r5 -> end of L3PT for area +1
ADD r1, r7, r3, LSR #9 ; r1 -> L3PT for r3
ADD r2, r7, r5, LSR #9 ; r2 -> L3PT for r5
TEQ r1, r2 ; if no pages needed
BEQ %FT30
MOV r4, #0 ; number of backing pages needed
10
LDRD r6, [r1], #8 ; get L3PT entry for L3PT
TST r6, #LL_TypeMask ; EQ if translation fault
ADDEQ r4, r4, #1 ; if not there then 1 more page needed
TEQ r1, r2
BNE %BT10
; if no pages needed, then exit
TEQ r4, #0
BEQ %FT30
; now we need to claim r4 pages from the free pool, if possible; return error if not
LDR r1, =ZeroPage
LDR r6, [r1, #FreePoolDANode + DANode_PMPSize]
SUBS r6, r6, r4 ; reduce free pool size by that many pages
BCS %FT14 ; if enough, skip next bit
; not enough pages in free pool currently, so try to grow it by the required amount
Push "r0, r1"
MOV r0, #ChangeDyn_FreePool
RSB r1, r6, #0 ; size change we want (+ve)
MOV r1, r1, LSL #12
SWI XOS_ChangeDynamicArea
Pull "r0, r1"
BVS %FT90 ; didn't manage change, so report error
MOV r6, #0 ; will be no pages left in free pool after this
14
STR r6, [r1, #FreePoolDANode + DANode_PMPSize] ; if possible then update size
LDR r0, [r1, #FreePoolDANode + DANode_PMP] ; r0 -> free pool page list
ADD r0, r0, r6, LSL #2 ; r0 -> first page we're taking out of free pool
LDR lr, =LL2PT
ADD r8, lr, r8, LSR #18 ; point r8 at start of L2 we may be updating
LDR r7, =LL3PT
ADD r1, r7, r3, LSR #9 ; point r1 at L3PT for r3 again
LDR r11, =ZeroPage
LDR r11, [r11, #PageTable_PageFlags] ; access privs (+CB bits)
20
LDRD r6, [r1], #8 ; get L2PT entry again
TST r6, #LL_TypeMask ; if no fault
BNE %FT25 ; then skip
Push "r1-r2, r4"
MOV lr, #-1
LDR r2, [r0] ; get page number to use
STR lr, [r0], #4 ; remove from PMP
Push "r0"
BL BangCamUpdate ; Map in to L3PT access window
; now that the page is mapped in we can zero its contents (=> cause translation fault for area initially)
; L2PT won't know about the page yet, so mapping it in with garbage initially shouldn't cause any issues
ADD r0, r3, #4096
MOV r1, #0
MOV r2, #0
MOV r4, #0
MOV r6, #0
15
STMDB r0!, {r1,r2,r4,r6} ; store data
TEQ r0, r3
BNE %BT15