@@ -46,15 +46,26 @@ pub fn halt() {
4646
4747/// Reads the current page table root register for kernel space (`TTBR1_EL1`).
4848///
49+ /// When the "arm-el2" feature is enabled,
50+ /// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
51+ ///
4952/// Returns the physical address of the page table root.
5053#[ inline]
5154pub fn read_kernel_page_table ( ) -> PhysAddr {
55+ #[ cfg( not( feature = "arm-el2" ) ) ]
5256 let root = TTBR1_EL1 . get ( ) ;
57+
58+ #[ cfg( feature = "arm-el2" ) ]
59+ let root = TTBR0_EL2 . get ( ) ;
60+
5361 pa ! ( root as usize )
5462}
5563
5664/// Reads the current page table root register for user space (`TTBR0_EL1`).
5765///
66+ /// When the "arm-el2" feature is enabled, for user-mode programs,
67+ /// virtualization is completely transparent to them, so there is no need to modify
68+ ///
5869/// Returns the physical address of the page table root.
5970#[ inline]
6071pub fn read_user_page_table ( ) -> PhysAddr {
@@ -65,19 +76,33 @@ pub fn read_user_page_table() -> PhysAddr {
6576/// Writes the register to update the current page table root for kernel space
6677/// (`TTBR1_EL1`).
6778///
79+ /// When the "arm-el2" feature is enabled,
80+ /// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
81+ ///
6882/// Note that the TLB is **NOT** flushed after this operation.
6983///
7084/// # Safety
7185///
7286/// This function is unsafe as it changes the virtual memory address space.
7387#[ inline]
7488pub unsafe fn write_kernel_page_table ( root_paddr : PhysAddr ) {
75- // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
76- TTBR1_EL1 . set ( root_paddr. as_usize ( ) as _ ) ;
89+ #[ cfg( not( feature = "arm-el2" ) ) ]
90+ {
91+ // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
92+ TTBR1_EL1 . set ( root_paddr. as_usize ( ) as _ ) ;
93+ }
94+
95+ #[ cfg( feature = "arm-el2" ) ]
96+ {
97+ // kernel space page table at EL2 use TTBR0_EL2 (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff)
98+ TTBR0_EL2 . set ( root_paddr. as_usize ( ) as _ ) ;
99+ }
77100}
78101
79102/// Writes the register to update the current page table root for user space
80103/// (`TTBR1_EL0`).
104+ /// When the "arm-el2" feature is enabled, for user-mode programs,
105+ /// virtualization is completely transparent to them, so there is no need to modify
81106///
82107/// Note that the TLB is **NOT** flushed after this operation.
83108///
@@ -97,10 +122,27 @@ pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
97122pub fn flush_tlb ( vaddr : Option < VirtAddr > ) {
98123 unsafe {
99124 if let Some ( vaddr) = vaddr {
100- asm ! ( "tlbi vaae1is, {}; dsb sy; isb" , in( reg) vaddr. as_usize( ) )
125+ const VA_MASK : usize = ( 1 << 44 ) - 1 ; // 0xFFFF_FFFF_FFFF
126+ let operand = ( vaddr. as_usize ( ) >> 12 ) & VA_MASK ;
127+
128+ #[ cfg( not( feature = "arm-el2" ) ) ]
129+ {
130+ asm ! ( "tlbi vaae1is, {}; dsb sy; isb" , in( reg) operand)
131+ }
132+ #[ cfg( feature = "arm-el2" ) ]
133+ {
134+ asm ! ( "tlbi vae2is, {}; dsb sy; isb" , in( reg) operand)
135+ }
101136 } else {
102137 // flush the entire TLB
103- asm ! ( "tlbi vmalle1; dsb sy; isb" )
138+ #[ cfg( not( feature = "arm-el2" ) ) ]
139+ {
140+ asm ! ( "tlbi vmalle1; dsb sy; isb" )
141+ }
142+ #[ cfg( feature = "arm-el2" ) ]
143+ {
144+ asm ! ( "tlbi alle2; dsb sy; isb" )
145+ }
104146 }
105147 }
106148}
@@ -124,8 +166,11 @@ pub fn flush_dcache_line(vaddr: VirtAddr) {
124166/// This function is unsafe as it changes the exception handling behavior of the
125167/// current CPU.
126168#[ inline]
127- pub unsafe fn write_exception_vector_base ( vbar_el1 : usize ) {
128- VBAR_EL1 . set ( vbar_el1 as _ ) ;
169+ pub unsafe fn write_exception_vector_base ( vbar : usize ) {
170+ #[ cfg( not( feature = "arm-el2" ) ) ]
171+ VBAR_EL1 . set ( vbar as _ ) ;
172+ #[ cfg( feature = "arm-el2" ) ]
173+ VBAR_EL2 . set ( vbar as _ ) ;
129174}
130175
131176/// Reads the thread pointer of the current CPU (`TPIDR_EL0`).
0 commit comments