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

Start moving page table code into s.ShortDesc

In preparation for the addition of long descriptor page table support,
start moving low-level page table routines into their own file
(s.ShortDesc) so that we can add a corresponding long descriptor
implementation in the future.

* logical_to_physical, MakePageTablesCacheable,
MakePageTablesNonCacheable, AllocateBackingLevel2, AMB_movepagesin_L2PT,
AMB_movecacheablepagesout_L2PT, AMB_moveuncacheablepagesout_L2PT
routines, and PageNumToL2PT macros, all moved to s.ShortDesc with no
changes.
* Add new UpdateL1PTForPageReplacement routine (by splitting some code
out of s.ChangeDyn)
parent 4fd2dd01
......@@ -356,50 +356,6 @@ AMB_SetMemMapEntries_MapOut_Lazy ROUT
AMB_SetMemMapEntries_MapOut_Lazy * AMB_SetMemMapEntries_MapOut
]
;
; ----------------------------------------------------------------------------------
;
;convert page number in $pnum to L2PT entry (physical address+protection bits),
;using cached PhysRamTable entries for speed
;
;entry: $ptable -> PhysRamTable, $pbits = protection bits
; $cache0, $cache1, $cache2 = PhysRamTable cache
;exit: $temp corrupted
; $cache0, $cache1, $cache2 updated
;
MACRO
PageNumToL2PT $pnum,$ptable,$cache0,$cache1,$cache2,$pbits,$temp
SUB $temp,$pnum,$cache0 ; no. pages into block
CMP $temp,$cache2
BLHS PageNumToL2PTCache_$ptable._$cache0._$cache1._$cache2._$temp
ADD $pnum,$cache1,$temp,LSL #Log2PageSize ; physical address of page
ORR $pnum,$pbits,$pnum ; munge in protection bits
MEND
MACRO
PageNumToL2PTInit $ptable,$cache0,$cache1,$cache2
ASSERT $cache2 > $cache1
LDR $ptable,=ZeroPage+PhysRamTable
MOV $cache0,#0
LDMIA $ptable,{$cache1,$cache2}
MOV $cache2,$cache2,LSR #12
MEND
PageNumToL2PTCache_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_LazyMapIn
; ----------------------------------------------------------------------------------
......@@ -621,54 +577,6 @@ AMB_MakeHonestPN ROUT
] ;AMB_LazyMapIn
; ----------------------------------------------------------------------------------
;
;AMB_movepagesin_L2PT
;
;updates L2PT 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
PageNumToL2PTInit r4,r5,r6,r7
LDR r9,=L2PT
ADD r9,r9,r3,LSR #(Log2PageSize-2) ;r9 -> L2PT for 1st new logical page
CMP r8,#4
BLT %FT20
10
LDMIA r10!,{r0-r3} ;next 4 page numbers
PageNumToL2PT r0,r4,r5,r6,r7,r11,r12
PageNumToL2PT r1,r4,r5,r6,r7,r11,r12
PageNumToL2PT r2,r4,r5,r6,r7,r11,r12
PageNumToL2PT r3,r4,r5,r6,r7,r11,r12
STMIA r9!,{r0-r3} ;write 4 L2PT entries
SUB r8,r8,#4
CMP r8,#4
BGE %BT10
20
CMP r8,#0
BEQ %FT35
30
LDR r0,[r10],#4
PageNumToL2PT r0,r4,r5,r6,r7,r11,r12
STR r0,[r9],#4
SUBS r8,r8,#1
BNE %BT30
35
PageTableSync
EXIT
; ----------------------------------------------------------------------------------
;
;update CAM entry for page number in $reg
......@@ -791,111 +699,6 @@ AMB_movepagesout_CAM ROUT
BNE %BT30
EXIT
; ----------------------------------------------------------------------------------
;
;AMB_movecacheablepagesout_L2PT
;
;updates L2PT 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 L2PT 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_L2PTMask
LDR lr,=L2PT
ADD lr,lr,r4,LSR #(Log2PageSize-2) ;lr -> L2PT 1st entry
CMP r8,#4
BLT %FT20
10
LDMIA lr,{r2-r5}
BIC r2,r2,r1
BIC r3,r3,r1
BIC r4,r4,r1
BIC r5,r5,r1
ORR r2,r2,r0
ORR r3,r3,r0
ORR r4,r4,r0
ORR r5,r5,r0
STMIA lr!,{r2-r5}
SUB r8,r8,#4
CMP r8,#4
BGE %BT10
20
CMP r8,#0
BEQ %FT35
30
LDR r2,[lr]
BIC r2,r2,r1
ORR r2,r2,r0
STR r2,[lr],#4
SUBS r8,r8,#1
BNE %BT30
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 L2PT 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 moveuncacheablepagesout
LDR lr,=L2PT
ADD lr,lr,r4,LSR #(Log2PageSize-2) ;lr -> L2PT 1st entry
MOV r0,#0 ;0 means translation fault
MOV r1,#0
MOV r2,#0
MOV r3,#0
MOV r4,#0
MOV r5,#0
MOV r6,#0
MOV r7,#0
CMP r8,#8
BLT %FT70
60
STMIA lr!,{r0-r7} ;blam! (8 entries)
SUB r8,r8,#8
CMP r8,#8
BGE %BT60
70
CMP r8,#0
BEQ %FT85
80
STR r0,[lr],#4
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
......
......@@ -4240,171 +4240,6 @@ GetNextRange Entry "r7,r8"
ADDNE r0, r0, #8 ; then advance fixed ptr
EXIT
;**************************************************************************
;
; AllocateBackingLevel2 - Allocate L2 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 4M boundaries
ADD r5, r5, r3 ; r5 -> end
MOV r0, #1 :SHL: 22
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 L2PT working out how much we need
LDR r7, =L2PT
ADD r3, r7, r8, LSR #10 ; r3 -> start of L2PT for area
ADD r5, r7, r5, LSR #10 ; r5 -> end of L2PT for area +1
ADD r1, r7, r3, LSR #10 ; r1 -> L2PT for r3
ADD r2, r7, r5, LSR #10 ; r2 -> L2PT for r5
TEQ r1, r2 ; if no pages needed
BEQ %FT30
MOV r4, #0 ; number of backing pages needed
10
LDR r6, [r1], #4 ; get L2PT entry for L2PT
TST r6, #3 ; 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, =L1PT
ADD r8, lr, r8, LSR #18 ; point r8 at start of L1 we may be updating
ADD r1, r7, r3, LSR #10 ; point r1 at L2PT for r3 again
LDR r11, =ZeroPage
LDR r11, [r11, #PageTable_PageFlags] ; access privs (+CB bits)
20
LDR r6, [r1], #4 ; get L2PT entry again
TST r6, #3 ; 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 L2PT access window
; now that the page is mapped in we can zero its contents (=> cause translation fault for area initially)
; L1PT 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 L1PT to make
; it visible to the MMU
PageTableSync
Pull "r0-r2, r4"
LDR lr, =ZeroPage
LDR r6, [lr, #L2PTUsed]
ADD r6, r6, #4096
STR r6, [lr, #L2PTUsed]
; 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!)
LDR r6, [r1, #-4] ; r6 = physical address for L2 page + other L2 bits
MOV r6, r6, LSR #12 ; r6 = phys.addr >> 12
[ MEMM_Type = "VMSAv6"
LDR lr, =L1_Page
|
LDR lr, =L1_Page + L1_U ; form other bits to put in L1
]
ORR lr, lr, r6, LSL #12 ; complete L1 entry
STR lr, [r8, #0] ; store entry for 1st MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #4] ; store entry for 2nd MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #8] ; store entry for 3rd MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #12] ; store entry for 4th MB
25
ADD r3, r3, #4096 ; advance L2PT logical address
ADD r8, r8, #16 ; move onto L1 for next 4M
TEQ r1, r2
BNE %BT20
PageTableSync
30
CLRV
EXIT
; Come here if not enough space in free pool to allocate level2
90
ADRL r0, ErrorBlock_CantAllocateLevel2
[ International
BL TranslateError
|
SETV
]
STR r0, [sp]
EXIT
;**************************************************************************
[ ChocolateSysHeap
......@@ -6178,7 +6013,7 @@ ReplacePage_BothUnmapped
; Now map in dest
MOV r0, #L1_B
LDR r1, [r8, #PageBlockSize+8] ; r1 = physical address of src for copy
LDR r1, [r8, #PageBlockSize+8] ; r1 = physical address of dest for copy
MOV r2, #0
MOV r3, #0 ; no oldp needed
BL RISCOS_AccessPhysicalAddress
......@@ -6240,35 +6075,9 @@ ReplacePage_Done
; now check if page we're replacing is in L2PT, and if so then adjust L1PT entries (4 of these)
LDR r2, =L2PT
LDR r6, [r8, #4] ; look at logical address of page being replaced
SUBS r6, r6, r2
BCC %FT84 ; address is below L2PT
CMP r6, #4*1024*1024
BCS %FT84 ; address is above L2PT
LDR r2, =L1PT
ADD r2, r2, r6, LSR #(12-4) ; address in L1 of 4 consecutive words to update
LDR r3, [r2] ; load 1st word, to get AP etc bits
MOV r3, r3, LSL #(31-9) ; junk other bits
LDR r4, [r8, #PageBlockSize+8] ; load new physical address for page
ORR r3, r4, r3, LSR #(31-9) ; and merge with AP etc bits
STR r3, [r2], #4
ADD r3, r3, #&400
STR r3, [r2], #4
ADD r3, r3, #&400
STR r3, [r2], #4
ADD r3, r3, #&400
STR r3, [r2], #4
[ MEMM_Type = "VMSAv6"
; 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,,,r3
]
LDR r0, [r8, #4] ; look at logical address of page being replaced
LDR r1, [r8, #PageBlockSize+8] ; load new physical address for page
BL UpdateL1PTForPageReplacement
84
Pull "r0-r4,r7-r12" ; restore registers
......
......@@ -98,6 +98,7 @@
$GetUnsqueeze
GET s.ArthurSWIs
$GetKernelMEMC
GET s.ShortDesc
GET s.Exceptions
GET s.ChangeDyn
GET s.HAL
......
......@@ -398,50 +398,6 @@ ppn_to_logical
CLC
MOV pc, lr
;----------------------------------------------------------------------------------------
; 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 r5, =L2PT
MOV r9, r4, LSR #12 ; r9 = logical page number
ADD r9, r5, r9, LSL #2 ; r9 -> L2PT entry for logical address
MOV r8, r9, LSR #12 ; r8 = page offset to L2PT entry for logical address
LDR r8, [r5, r8, LSL #2] ; r8 = L2PT entry for L2PT entry for logical address
[ MEMM_Type = "ARM600"
ASSERT ((L2_SmallPage :OR: L2_ExtPage) :AND: 2) <> 0
ASSERT (L2_LargePage :AND: 2) = 0
|
ASSERT L2_SmallPage = 2
ASSERT L2_XN = 1 ; Because XN is bit 0, bit 1 is the only bit we can check when looking for small pages
]
TST r8, #2 ; Check for valid (4K) page.
BEQ meminfo_returncs
LDR r8, [r9] ; r8 = L2PT entry for logical address
TST r8, #2 ; Check for valid (4K) page.
BEQ meminfo_returncs
[ NoARMT2
LDR r9, =&FFF ; Valid so
BIC r8, r8, r9 ; mask off bits 0-11,
AND r9, r4, r9 ; get page offset from logical page
ORR r8, r8, r9 ; combine with physical page address.
|
BFI r8, r4, #0, #12 ; Valid, so apply offset within the page
]
MOV r9, #0 ; 4K pages are always in the low 4GB
CLC
MOV pc, lr
meminfo_returncs_pullr8
Pull "r8"
meminfo_returncs
......
......@@ -500,61 +500,6 @@ DoTheShrink ROUT
EXIT
[ 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, =L1PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =L2PT
LDR r2, =4*1024*1024
BL AdjustMemoryPageFlags
; Update the TTBR
LDR r4, =L1PT
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, =L1PT
ADD r1, r0, #16*1024
LDR r4, =ZeroPage
ARMop Cache_CleanRange,,,r4
LDR r0, =L2PT
ADD r1, r0, #4*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, =L1PT
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, =L1PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =L2PT
LDR r2, =4*1024*1024
BL AdjustMemoryPageFlags
EXIT
; In:
; R0 = new page flags
; R1 = base of area (page aligned)
......
; 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 - "short descriptor" format (ARMv3+ 4 bytes per entry)
;----------------------------------------------------------------------------------------
; 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 r5, =L2PT
MOV r9, r4, LSR #12 ; r9 = logical page number
ADD r9, r5, r9, LSL #2 ; r9 -> L2PT entry for logical address
MOV r8, r9, LSR #12 ; r8 = page offset to L2PT entry for logical address
LDR r8, [r5, r8, LSL #2] ; r8 = L2PT entry for L2PT entry for logical address
[ MEMM_Type = "ARM600"
ASSERT ((L2_SmallPage :OR: L2_ExtPage) :AND: 2) <> 0
ASSERT (L2_LargePage :AND: 2) = 0
|
ASSERT L2_SmallPage = 2
ASSERT L2_XN = 1 ; Because XN is bit 0, bit 1 is the only bit we can check when looking for small pages
]
TST r8, #2 ; Check for valid (4K) page.
BEQ meminfo_returncs
LDR r8, [r9] ; r8 = L2PT entry for logical address
TST r8, #2 ; Check for valid (4K) page.
BEQ meminfo_returncs
[ NoARMT2
LDR r9, =&FFF ; Valid so
BIC r8, r8, r9 ; mask off bits 0-11,
AND r9, r4, r9 ; get page offset from logical page
ORR r8, r8, r9 ; combine with physical page address.
|
BFI r8, r4, #0, #12 ; Valid, so apply offset within the page
]
MOV r9, #0 ; 4K pages are always in the low 4GB
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, =L1PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =L2PT
LDR r2, =4*1024*1024
BL AdjustMemoryPageFlags
; Update the TTBR
LDR r4, =L1PT
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, =L1PT
ADD r1, r0, #16*1024
LDR r4, =ZeroPage
ARMop Cache_CleanRange,,,r4
LDR r0, =L2PT
ADD r1, r0, #4*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, =L1PT
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, =L1PT
LDR r2, =16*1024
BL AdjustMemoryPageFlags
LDR r1, =L2PT
LDR r2, =4*1024*1024
BL AdjustMemoryPageFlags
EXIT
]
;**************************************************************************
;
; AllocateBackingLevel2 - Allocate L2 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 4M boundaries
ADD r5, r5, r3 ; r5 -> end
MOV r0, #1 :SHL: 22
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 L2PT working out how much we need
LDR r7, =L2PT
ADD r3, r7, r8, LSR #10 ; r3 -> start of L2PT for area
ADD r5, r7, r5, LSR #10 ; r5 -> end of L2PT for area +1
ADD r1, r7, r3, LSR #10 ; r1 -> L2PT for r3
ADD r2, r7, r5, LSR #10 ; r2 -> L2PT for r5
TEQ r1, r2 ; if no pages needed
BEQ %FT30
MOV r4, #0 ; number of backing pages needed
10
LDR r6, [r1], #4 ; get L2PT entry for L2PT
TST r6, #3 ; 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, =L1PT
ADD r8, lr, r8, LSR #18 ; point r8 at start of L1 we may be updating
ADD r1, r7, r3, LSR #10 ; point r1 at L2PT for r3 again
LDR r11, =ZeroPage
LDR r11, [r11, #PageTable_PageFlags] ; access privs (+CB bits)
20
LDR r6, [r1], #4 ; get L2PT entry again
TST r6, #3 ; 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 L2PT access window
; now that the page is mapped in we can zero its contents (=> cause translation fault for area initially)
; L1PT 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 L1PT to make
; it visible to the MMU
PageTableSync
Pull "r0-r2, r4"
LDR lr, =ZeroPage
LDR r6, [lr, #L2PTUsed]
ADD r6, r6, #4096
STR r6, [lr, #L2PTUsed]
; 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!)
LDR r6, [r1, #-4] ; r6 = physical address for L2 page + other L2 bits
MOV r6, r6, LSR #12 ; r6 = phys.addr >> 12
[ MEMM_Type = "VMSAv6"
LDR lr, =L1_Page
|
LDR lr, =L1_Page + L1_U ; form other bits to put in L1
]
ORR lr, lr, r6, LSL #12 ; complete L1 entry
STR lr, [r8, #0] ; store entry for 1st MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #4] ; store entry for 2nd MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #8] ; store entry for 3rd MB
ADD lr, lr, #1024 ; advance L2 pointer
STR lr, [r8, #12] ; store entry for 4th MB
25
ADD r3, r3, #4096 ; advance L2PT logical address
ADD r8, r8, #16 ; move onto L1 for next 4M
TEQ r1, r2
BNE %BT20
PageTableSync
30
CLRV
EXIT
; Come here if not enough space in free pool to allocate level2
90
ADRL r0, ErrorBlock_CantAllocateLevel2
[ International
BL TranslateError
|
SETV
]
STR r0, [sp]
EXIT
;**************************************************************************
;
; UpdateL1PTForPageReplacement
;
; Updates L1PT to point to the right place, if a physical L2PT 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
LDR r2, =L2PT
SUBS r0, r0, r2
MOVCC pc, lr ; address is below L2PT
CMP r0, #4*1024*1024
MOVCS pc, lr ; address is above L2PT
LDR r2, =L1PT
ADD r2, r2, r0, LSR #(12-4) ; address in L1 of 4 consecutive words to update
LDR r3, [r2] ; load 1st L1PT entry
MOV r3, r3, LSL #(31-9) ; junk old phys addr
ORR r3, r1, r3, LSR #(31-9) ; merge in new phys addr
STR r3, [r2], #4
ADD r3, r3, #&400 ; advance by 1K for each L1PT word
STR r3, [r2], #4
ADD r3, r3, #&400
STR r3, [r2], #4
ADD r3, r3, #&400
STR r3, [r2], #4
[ MEMM_Type = "VMSAv6"
; 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
|
; With older architectures there shouldn't be any TLB maintenance
; required. But we do potentially need to drain the write buffer to make
; sure the CPU actually sees the changes.
[ CacheablePageTables
LDR r3, =ZeroPage
ARMop DSB_ReadWrite,,tailcall,r3
|
MOV pc, lr
]
]
;
; ----------------------------------------------------------------------------------
;
;convert page number in $pnum to L2PT entry (physical address+protection bits),
;using cached PhysRamTable entries for speed
;
;entry: $ptable -> PhysRamTable, $pbits = protection bits
; $cache0, $cache1, $cache2 = PhysRamTable cache
;exit: $temp corrupted
; $cache0, $cache1, $cache2 updated
;
MACRO
PageNumToL2PT $pnum,$ptable,$cache0,$cache1,$cache2,$pbits,$temp
SUB $temp,$pnum,$cache0 ; no. pages into block
CMP $temp,$cache2
BLHS PageNumToL2PTCache_$ptable._$cache0._$cache1._$cache2._$temp
ADD $pnum,$cache1,$temp,LSL #Log2PageSize ; physical address of page
ORR $pnum,$pbits,$pnum ; munge in protection bits
MEND
MACRO
PageNumToL2PTInit $ptable,$cache0,$cache1,$cache2
ASSERT $cache2 > $cache1
LDR $ptable,=ZeroPage+PhysRamTable
MOV $cache0,#0
LDMIA $ptable,{$cache1,$cache2}
MOV $cache2,$cache2,LSR #12
MEND
PageNumToL2PTCache_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 L2PT 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
PageNumToL2PTInit r4,r5,r6,r7
LDR r9,=L2PT
ADD r9,r9,r3,LSR #(Log2PageSize-2) ;r9 -> L2PT for 1st new logical page
CMP r8,#4
BLT %FT20
10
LDMIA r10!,{r0-r3} ;next 4 page numbers
PageNumToL2PT r0,r4,r5,r6,r7,r11,r12
PageNumToL2PT r1,r4,r5,r6,r7,r11,r12
PageNumToL2PT r2,r4,r5,r6,r7,r11,r12
PageNumToL2PT r3,r4,r5,r6,r7,r11,r12
STMIA r9!,{r0-r3} ;write 4 L2PT entries
SUB r8,r8,#4
CMP r8,#4
BGE %BT10
20
CMP r8,#0
BEQ %FT35
30
LDR r0,[r10],#4
PageNumToL2PT r0,r4,r5,r6,r7,r11,r12
STR r0,[r9],#4
SUBS r8,r8,#1
BNE %BT30
35
PageTableSync
EXIT
; ----------------------------------------------------------------------------------
;
;AMB_movecacheablepagesout_L2PT
;
;updates L2PT 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 L2PT 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_L2PTMask
LDR lr,=L2PT
ADD lr,lr,r4,LSR #(Log2PageSize-2) ;lr -> L2PT 1st entry
CMP r8,#4
BLT %FT20
10
LDMIA lr,{r2-r5}
BIC r2,r2,r1
BIC r3,r3,r1
BIC r4,r4,r1
BIC r5,r5,r1
ORR r2,r2,r0
ORR r3,r3,r0
ORR r4,r4,r0
ORR r5,r5,r0
STMIA lr!,{r2-r5}
SUB r8,r8,#4
CMP r8,#4
BGE %BT10
20
CMP r8,#0
BEQ %FT35
30
LDR r2,[lr]
BIC r2,r2,r1
ORR r2,r2,r0
STR r2,[lr],#4
SUBS r8,r8,#1
BNE %BT30
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 L2PT 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 moveuncacheablepagesout
LDR lr,=L2PT
ADD lr,lr,r4,LSR #(Log2PageSize-2) ;lr -> L2PT 1st entry
MOV r0,#0 ;0 means translation fault
MOV r1,#0
MOV r2,#0
MOV r3,#0
MOV r4,#0
MOV r5,#0
MOV r6,#0
MOV r7,#0
CMP r8,#8
BLT %FT70
60
STMIA lr!,{r0-r7} ;blam! (8 entries)
SUB r8,r8,#8
CMP r8,#8
BGE %BT60
70
CMP r8,#0
BEQ %FT85
80
STR r0,[lr],#4
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
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