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.
No related merge requests found
......@@ -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
; Make sure the page is seen to be clear before we update L2PT to make
; it visible to the MMU
PageTableSync
Pull "r0-r2, r4"
LDR lr, =ZeroPage
LDR r6, [lr, #LxPTUsed]
ADD r6, r6, #4096
STR r6, [lr, #LxPTUsed]
; now update 1 entry in L2PT (corresponding to 2M of address space which is covered by the 4K of L3)
; and point it at the physical page we've just allocated (r1!-8 will already hold physical address+bits now!)
LDRD r6, [r1, #-8] ; r6,r7 = L3PT entry describing our logical mapping of the new page
BFC r6, #0, #LL_LowAddr_Start ; Low phys addr
AND r7, r7, #LL_HighAddr ; High phys addr
ORR r6, r6, #LL12_Table ; It's a table ptr
STRD r6, [r8] ; Store as L2PT entry
25
ADD r3, r3, #4096 ; advance L3PT logical address
ADD r8, r8, #8 ; move onto L2 for next 2M
TEQ r1, r2
BNE %BT20
PageTableSync
30
CLRV
EXIT
; Come here if not enough space in free pool to allocate level3
90
ADRL r0, ErrorBlock_CantAllocateLevel2
[ International
BL TranslateError
|
SETV
]
STR r0, [sp]
EXIT
;**************************************************************************
;
; UpdateL1PTForPageReplacement
;
; Updates L2PT to point to the right place, if a physical L3PT page has been
; replaced with a substitute.
;
; In: r0 = log addr of page being replaced
; r1 = phys addr of replacement page
;
; Out: r0-r4, r7-r12 can be corrupted
;
UpdateL1PTForPageReplacement ROUT
MOV r2, #0 ; XXX high phys addr
LDR r3, =LL3PT
SUBS r0, r0, r3
MOVCC pc, lr ; address is below L3PT
CMP r0, #8*1024*1024
MOVCS pc, lr ; address is above L3PT
LDR r3, =LL2PT
ADD r0, r3, r0, LSR #(12-3) ; address in L2 of entry to update
LDRD r8, [r0] ; load L2PT entry
MOV r1, r1, LSR #LL_LowAddr_Start
BFI r8, r1, #LL_LowAddr_Start, #LL_LowAddr_Size ; Update low phys addr
ASSERT LL_HighAddr_Start = 0
BFI r9, r2, #0, #LL_HighAddr_Size ; Update high phys addr
STRD r8, [r0]
; In order to guarantee that the result of a page table write is
; visible, the ARMv6+ memory order model requires us to perform TLB
; maintenance (equivalent to the MMU_ChangingUncached ARMop) after we've
; performed the write. Performing the maintenance beforehand (as we've
; done traditionally) will work most of the time, but not always.
LDR r3, =ZeroPage
ARMop MMU_ChangingUncached,,tailcall,r3
;
; ----------------------------------------------------------------------------------
;
;convert page number in $pnum to L3PT entry (physical address+protection bits),
;using cached PhysRamTable entries for speed
;
;entry: $ptable -> PhysRamTable, $pbits,$pbits2 = protection bits
; $cache0, $cache1, $cache2 = PhysRamTable cache
;exit: $cache0, $cache1, $cache2 updated
;
MACRO
PageNumToL3PT $pnum,$pnum2,$ptable,$cache0,$cache1,$cache2,$pbits,$pbits2
MOV $pnum2,$pbits2
SUB $pbits2,$pnum,$cache0 ; no. pages into block
CMP $pbits2,$cache2
BLHS PageNumToL3PTCache_$ptable._$cache0._$cache1._$cache2._$pbits2
ADD $pnum,$cache1,$pbits2,LSL #Log2PageSize ; physical address of page
ORR $pnum,$pbits,$pnum ; munge in protection bits
MOV $pbits2,$pnum2
MEND
MACRO
PageNumToL3PTInit $ptable,$cache0,$cache1,$cache2
ASSERT $cache2 > $cache1
LDR $ptable,=ZeroPage+PhysRamTable
MOV $cache0,#0
LDMIA $ptable,{$cache1,$cache2}
MOV $cache2,$cache2,LSR #12
MEND
PageNumToL3PTCache_r4_r5_r6_r7_r12 ROUT
Entry "r4"
ADD r12,r12,r5 ; Restore page number
MOV r5,#0
10
LDMIA r4!,{r6,r7} ; Get PhysRamTable entry
MOV r7,r7,LSR #12
CMP r12,r7
SUBHS r12,r12,r7
ADDHS r5,r5,r7
BHS %BT10
EXIT ; r5-r7 = cache entry, r12 = offset into entry
; ----------------------------------------------------------------------------------
;
;AMB_movepagesin_L2PT
;
;updates L3PT for new logical page positions, does not update CAM
;
; entry:
; r3 = new logical address of 1st page
; r8 = number of pages
; r9 = page flags
; r10 -> page list
;
AMB_movepagesin_L2PT ROUT
Entry "r0-r12"
MOV r0, #0
GetPTE r11, 4K, r0, r9
PageNumToL3PTInit r4,r5,r6,r7
LDR r9,=LL3PT
ADD r9,r9,r3,LSR #(Log2PageSize-3) ;r9 -> L3PT for 1st new logical page
CMP r8,#2
BLT %FT20
10
LDMIA r10!,{r0,r2} ;next 2 page numbers
PageNumToL3PT r0,r1,r4,r5,r6,r7,r11,r12
PageNumToL3PT r2,r3,r4,r5,r6,r7,r11,r12
STRD r0,[r9],#16 ;write L3PT entries
STRD r2,[r9,#-8]
SUB r8,r8,#2
CMP r8,#2
BGE %BT10
20
CMP r8,#0
BEQ %FT35
LDR r0,[r10],#4
PageNumToL3PT r0,r1,r4,r5,r6,r7,r11,r12
STRD r0,[r9]
35
PageTableSync
EXIT
; ----------------------------------------------------------------------------------
;
;AMB_movecacheablepagesout_L2PT
;
;updates L3PT for old logical page positions, does not update CAM
;
; entry:
; r3 = old page flags
; r4 = old logical address of 1st page
; r8 = number of pages
;
AMB_movecacheablepagesout_L2PT
Entry "r0-r8"
; Calculate L3PT flags needed to make the pages uncacheable
; Assume all pages will have identical flags (or at least close enough)
LDR lr,=ZeroPage
LDR lr,[lr, #MMU_PCBTrans]
GetTempUncache r0, r3, lr, r1
LDR r1, =TempUncache_L3PTMask
LDR lr,=LL3PT
ADD lr,lr,r4,LSR #(Log2PageSize-3) ;lr -> L3PT 1st entry
CMP r8,#2
BLT %FT20
10
LDRD r2,[lr]
LDRD r4,[lr,#8]
BIC r2,r2,r1
BIC r4,r4,r1
ORR r2,r2,r0
ORR r4,r4,r0
STRD r2,[lr],#16
STRD r4,[lr,#-8]
SUB r8,r8,#2
CMP r8,#2
BGE %BT10
20
CMP r8,#0
BEQ %FT35
LDRD r2,[lr]
BIC r2,r2,r1
ORR r2,r2,r0
STRD r2,[lr]
35
FRAMLDR r0,,r4 ;address of 1st page
FRAMLDR r1,,r8 ;number of pages
LDR r3,=ZeroPage
ARMop MMU_ChangingEntries,,,r3
FRAMLDR r4
FRAMLDR r8
B %FT55 ; -> moveuncacheablepagesout_L2PT (avoid pop+push of large stack frame)
; ----------------------------------------------------------------------------------
;
;AMB_moveuncacheablepagesout_L2PT
;
;updates L3PT for old logical page positions, does not update CAM
;
; entry:
; r4 = old logical address of 1st page
; r8 = number of pages
;
AMB_moveuncacheablepagesout_L2PT
ALTENTRY
55 ; Enter here from movecacheablepagesout
LDR lr,=LL3PT
ADD lr,lr,r4,LSR #(Log2PageSize-3) ;lr -> L2PT 1st entry
MOV r0,#0 ;0 means translation fault
MOV r1,#0
CMP r8,#8
BLT %FT70
60
STRD r0,[lr],#8*8
STRD r0,[lr,#-7*8]
STRD r0,[lr,#-6*8]
STRD r0,[lr,#-5*8]
STRD r0,[lr,#-4*8]
STRD r0,[lr,#-3*8]
STRD r0,[lr,#-2*8]
STRD r0,[lr,#-1*8]
SUB r8,r8,#8
CMP r8,#8
BGE %BT60
70
CMP r8,#0
BEQ %FT85
80
STRD r0,[lr],#8
SUBS r8,r8,#1
BNE %BT80
85
FRAMLDR r0,,r4 ;address of 1st page
FRAMLDR r1,,r8 ;number of pages
LDR r3,=ZeroPage
ARMop MMU_ChangingUncachedEntries,,,r3 ;no cache worries, hoorah
EXIT
LTORG
END
......@@ -241,10 +241,73 @@ MemoryConvertNoFIQCheck ROUT
BNE %BT10 ; Do next entry if we don't have to change L2.
MOV r4, r4, LSR #12
[ LongDesc
LDR r8, =LL3PT
LDR r3, =ZeroPage
ADD r4, r8, r4, LSL #3 ; Address of L3 entry for logical address.
; VMSAv6 is hard, use XCBTable/PCBTrans
ASSERT DynAreaFlags_CPBits = 7*XCB_P :SHL: 10
ASSERT DynAreaFlags_NotCacheable = XCB_NC :SHL: 4
ASSERT DynAreaFlags_NotBufferable = XCB_NB :SHL: 4
TST r0, #cacheable_bit ; n.b. must match EQ/NE used by ARMop calls
AND lr, r5, #DynAreaFlags_NotCacheable + DynAreaFlags_NotBufferable
AND r5, r5, #DynAreaFlags_CPBits
ORR lr, lr, r5, LSR #10-4
LDR r5, [r3, #MMU_PCBTrans]
ORREQ lr, lr, #XCB_TU<<4 ; if temp uncache, set TU bit
LDRB lr, [r5, lr, LSR #4] ; get AttrIndx value
LDRD r8, [r4] ; Get L3 entry (safe as we know address is valid).
BIC r8, r8, #TempUncache_L3PTMask ; Knock out existing attributes (n.b. assumed to not be large page!)
ORR r8, r8, lr ; Set new attributes
BNE %FT63
; Making page non-cacheable
; There's a potential interrupt hole here - many ARMs ignore cache hits
; for pages which are marked as non-cacheable (seen on XScale,
; Cortex-A53, Cortex-A15 to name but a few, and documented in many TRMs)
; We can't be certain that this page isn't being used by an interrupt
; handler, so if we're making it non-cacheable we have to take the safe
; route of disabling interrupts around the operation.
; Note - currently no consideration is given to FIQ handlers.
; Note - we clean the cache as the last step (as opposed to doing it at
; the start) to make sure prefetching doesn't pull data back into the
; cache.
MRS r11, CPSR
ORR lr, r11, #I32_bit ; IRQs off
; Yuck, we also need to deal with the case where we're making the
; current SVC stack page uncacheable (coherency issue when calling the
; ARMops if cache hits to uncacheable pages are ignored). Deal with this
; by temporarily dropping into IRQ mode (and thus a different stack) if
; we think this is going to happen.
MOV r5, r4, LSL #9 ; R5 = original logical address
[ (LL3PT:SHL:9) <> 0
SUB r5, r5, #LL3PT:SHL:9
]
SUB r10, sp, r5
CMP r10, #8192 ; Be extra cautious
EORLO lr, lr, #SVC32_mode :EOR: IRQ32_mode
MSR CPSR_c, lr ; Switch mode
Push "r0, lr" ; Preserve OS_Memory flags and (potential) IRQ lr
STRD r8, [r4] ; Write back new L3 entry.
MOV r0, r5
ARMop MMU_ChangingEntry,,,r3 ; Clean TLB+cache
Pull "r0, lr" ; Restore OS_Memory flags + IRQ lr
MSR CPSR_c, r11 ; Back to original mode + IRQ state
B %FT65
63
; Making page cacheable again
; Shouldn't be any cache maintenance worries
STRD r8, [r4] ; Write back new L2 entry.
MOV r4, r0
MOV r0, r5
ARMop MMU_ChangingUncachedEntry,,,r3 ; Clean TLB
MOV r0, r4
65
B %BT10
|
LDR r8, =L2PT
LDR r3, =ZeroPage
ADD r4, r8, r4, LSL #2 ; Address of L2 entry for logical address.
[ MEMM_Type = "VMSAv6"
[ MEMM_Type = "VMSAv6"
; VMSAv6 is hard, use XCBTable/PCBTrans
ASSERT DynAreaFlags_CPBits = 7*XCB_P :SHL: 10
ASSERT DynAreaFlags_NotCacheable = XCB_NC :SHL: 4
......@@ -260,12 +323,12 @@ MemoryConvertNoFIQCheck ROUT
LDR r5, [r4] ; Get L2 entry (safe as we know address is valid).
BIC r5, r5, #TempUncache_L2PTMask ; Knock out existing attributes (n.b. assumed to not be large page!)
ORR r5, r5, lr ; Set new attributes
|
|
LDR r5, [r4] ; Get L2 entry (safe as we know address is valid).
TST r0, #cacheable_bit
BICEQ r5, r5, #L2_C ; Disable/enable cacheability.
ORRNE r5, r5, #L2_C
]
]
BNE %FT63
; Making page non-cacheable
; There's a potential interrupt hole here - many ARMs ignore cache hits
......@@ -295,7 +358,7 @@ MemoryConvertNoFIQCheck ROUT
ASSERT (L2PT :SHL: 10) = 0 ; Ensure we can convert r4 back to the page log addr
MOV r0, r4, LSL #10
ARMop MMU_ChangingEntry,,,r3 ; Clean TLB+cache
Pull "r5, lr" ; Restore OS_Memory flags + IRQ lr
Pull "r0, lr" ; Restore OS_Memory flags + IRQ lr
MSR CPSR_c, r11 ; Back to original mode + IRQ state
B %FT65
63
......@@ -306,9 +369,10 @@ MemoryConvertNoFIQCheck ROUT
ASSERT (L2PT :SHL: 10) = 0 ; Ensure we can convert r4 back to the page log addr
MOV r0, r4, LSL #10
ARMop MMU_ChangingUncachedEntry,,,r3 ; Clean TLB
65
MOV r0, r5
65
B %BT10
]
70
CLRV
......@@ -898,12 +962,23 @@ MapIO64permanent
ASSERT MapInFlag_DoublyMapped = 1:SHL:20
MOV r0, r0, LSL #4
; Convert DA flags to page table entry
[ LongDesc
Push "r0,r1"
MOV r0, #0
GetPTE r0, 2M, r0, r12
UBFX r0, r0, #0, #LL_LowAttr_Start+LL_LowAttr_Size ; Only keep the low attribtues (only high attribute is XN/PXN, which is always forced)
Pull "r1"
ORR r0, r0, r1 ; Add in the extra flags
Pull "r1"
BL RISCOS_MapInIO_LowAttr
|
GetPTE r0, 1M, r0, r12
[ MEMM_Type = "VMSAv6"
[ MEMM_Type = "VMSAv6"
ORR r0, r0, #L1_XN ; force non-executable to prevent speculative instruction fetches
]
]
; Map in the region
BL RISCOS_MapInIO_PTE
]
MOV r3, r0
PullEnv
CMP r3, #0 ;MOV,CMP rather than MOVS to be sure to clear V
......@@ -1097,16 +1172,29 @@ MAI_SoftCAM
EXIT
MAI_L1PT
[ LongDesc
; Combined L1PT & L2PT
ASSERT LL1PT = LL2PT+16*1024
LDR r1, =LL2PT
MOV r2, #16*1024+4096
|
LDR r1, =L1PT
MOV r2, #16*1024
]
MOV r3, r2
EXIT
MAI_L2PT
LDR r0, =ZeroPage
[ LongDesc
; Actually L3PT
LDR r1, =LL3PT
MOV r2, #8*1024*1024
|
LDR r1, =L2PT
MOV r2, #4*1024*1024
LDR r3, [r0, #L2PTUsed]
]
LDR r3, [r0, #LxPTUsed]
EXIT
MAI_HALWs
......@@ -2127,6 +2215,20 @@ CheckMemoryAccess ROUT
LDR r5, =CMA_HALWorkspaceNCNB
BL CMA_AddRange
70
[ LongDesc
ASSERT LL3PT > HALWorkspaceNCNB
LDR r3, =LL3PT
MOV r4, #8*1024*1024
LDR r5, =CMA_PageTablesAccess+CMA_CheckL2PT ; L3PT contains gaps due to logical indexing
BL CMA_AddRange
ASSERT LL2PT > LL3PT
ASSERT LL1PT = LL2PT+16*1024
LDR r3, =LL2PT
MOV r4, #16*1024+4096
LDR r5, =CMA_PageTablesAccess
BL CMA_AddRange
ASSERT CursorChunkAddress > LL1PT
|
ASSERT L2PT > HALWorkspaceNCNB
LDR r3, =L2PT
MOV r4, #4*1024*1024
......@@ -2138,6 +2240,7 @@ CheckMemoryAccess ROUT
LDR r5, =CMA_PageTablesAccess
BL CMA_AddRange
ASSERT CursorChunkAddress > L1PT
]
LDR r3, =CursorChunkAddress
MOV r4, #32*1024
LDR r5, =CMA_CursorChunk
......
......@@ -162,12 +162,17 @@ CamMapBroke
;
; 4K page size assumed!
RemoveCacheabilityR0ByMinusR2 ROUT
[ LongDesc
Entry "r0-r5,r8-r9"
|
Entry "r0-r5"
]
MOV r5, #DynAreaFlags_NotCacheable
MOV r1, #-1
10
SUB r0, r0, #4096
BL GetPageFlagsForR0IntoR6
BVS %FT99
TST r6, #DynAreaFlags_NotCacheable
BNE %FT90
; Work out required page flags - use cached flags from last page if possible
......@@ -178,6 +183,15 @@ RemoveCacheabilityR0ByMinusR2 ROUT
LDR r3, [r3, #MMU_PCBTrans]
GetTempUncache r4, r6, r3, lr
20
[ LongDesc
; Update the current L3PT entry
LDR r3, =LL3PT
ADD r3, r3, r0, LSR #9
LDRD r8, [r3]
BIC r8, r8, #TempUncache_L3PTMask
ORR r8, r8, r4
STRD r8, [r3]
|
; Update the current L2PT entry
LDR r3, =L2PT
LDR lr, =TempUncache_L2PTMask
......@@ -185,6 +199,7 @@ RemoveCacheabilityR0ByMinusR2 ROUT
BIC r5, r5, lr
ORR r5, r5, r4
STR r5, [r3, r0, LSR #10]
]
; Clear the flag from R5
MOV r5, #0
90
......@@ -202,6 +217,9 @@ RemoveCacheabilityR0ByMinusR2 ROUT
ARMop MMU_ChangingUncachedEntries,NE,tailcall,r4
91
EXIT
99
FRAMSTR r0
EXIT
]
; Move pages at [R0-R4,R0) to [R1-R4,R1)
......@@ -498,8 +516,13 @@ AdjustMemoryPageFlags ROUT
; be performing cacheable accesses, so the maintenance performed by
; BangCamUpdate won't have done anything useful.
; So start by flushing the L2PT word from the cache.
[ LongDesc
LDR r0, =LL3PT
ADD r0, r0, r3, LSR #9 ; -> L3PT entry we modified
|
LDR r0, =L2PT
ADD r0, r0, r3, LSR #10 ; -> L2PT entry we modified
]
LDRB r2, [r12, #DCache_LineLen]
SUB r2, r2, #1
BIC r0, r0, r2
......
......@@ -1532,8 +1532,13 @@ osri6_table
DCD ZeroPage+ModuleSHT_Entries ;10
DCD ZeroPage+ModuleSWI_HashTab ;11
DCD 0 ;12 (was IOSystemType)
[ LongDesc
DCD 0
DCD 0
|
DCD L1PT ;13
DCD L2PT ;14
]
DCD UNDSTK ;15
DCD SVCSTK ;16
DCD SysHeapStart ;17
......
......@@ -88,7 +88,11 @@ CmosScreenWillDo
CONT_Break
AddressHAL
MOV a1, #1
[ LongDesc
LDR a2, =LL1PT ; Probably not very useful (L2PT would be better)
|
LDR a2, =L1PT
]
CallHAL HAL_Reset
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......
......@@ -744,7 +744,11 @@ PerformReset
BNE %FT15
AddressHAL
MOV a1, #0
[ LongDesc
LDR a2, =LL1PT ; Probably not very useful (L2PT would be better)
|
LDR a2, =L1PT
]
CallHAL HAL_Reset
15
B CONT_Break ; If we can't turn the power off,we may end up back here anyway
......
......@@ -236,9 +236,9 @@ AllocateBackingLevel2 Entry "r0-r8,r11"
Pull "r0-r2, r4"
LDR lr, =ZeroPage
LDR r6, [lr, #L2PTUsed]
LDR r6, [lr, #LxPTUsed]
ADD r6, r6, #4096
STR r6, [lr, #L2PTUsed]
STR r6, [lr, #LxPTUsed]
; now update 4 words in L1PT (corresponding to 4M of address space which is covered by the 4K of L2)
; and point them at the physical page we've just allocated (r1!-4 will already hold physical address+bits now!)
......@@ -494,7 +494,7 @@ AMB_movecacheablepagesout_L2PT
;
AMB_moveuncacheablepagesout_L2PT
ALTENTRY
55 ; Enter here from moveuncacheablepagesout
55 ; Enter here from movecacheablepagesout
LDR lr,=L2PT
ADD lr,lr,r4,LSR #(Log2PageSize-2) ;lr -> L2PT 1st entry
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment