1 // SPDX-License-Identifier: GPL-2.0 2 3 //! x86_64 page size compat 4 //! 5 //! C header: [`include/linux/page_size_compat.h`](srctree/include/linux/page_size_compat.h). 6 //! 7 //! Rust helpers for x86_64 page size emulation. 8 9 use kernel::{bindings, jump_label, page}; 10 11 /// __page_shift is the emulated page shift. 12 #[inline(always)] __page_shift() -> usize13pub fn __page_shift() -> usize { 14 // SAFETY: Accessing C static key 15 let emulated = unsafe { 16 jump_label::static_branch_unlikely!( 17 bindings::page_shift_compat_enabled, 18 bindings::static_key_false, 19 key 20 ) 21 }; 22 23 if emulated { 24 // SAFETY: Reading static C variable page_shift_compat. 25 // page_size_compat is marked __ro_after_init in the C code. 26 let shift = unsafe { bindings::page_shift_compat }; 27 28 // page_shift_compat is sanitized and range checked by boot 29 // parameter parsing; so this conversion should always be safe. 30 shift.try_into().unwrap() 31 } else { 32 page::PAGE_SHIFT 33 } 34 } 35 36 /// __page_size is the emulated page size. 37 #[inline(always)] __page_size() -> usize38pub fn __page_size() -> usize { 39 let shift = __page_shift(); 40 41 1usize << shift 42 } 43 44 /// __page_mask can be used to align addresses to a __page boundary. 45 #[inline(always)] __page_mask() -> usize46pub fn __page_mask() -> usize { 47 let page_size = __page_size(); 48 49 !(page_size - 1) 50 } 51 52 /// Aligns the given address UP to the nearest __page boundary. 53 #[inline(always)] __page_align(addr: usize) -> usize54pub fn __page_align(addr: usize) -> usize { 55 let page_size = __page_size(); 56 let mask = !(page_size - 1); 57 58 // Parentheses around `page_size - 1` to avoid triggering 59 // overflow sanitizers in the wrong cases. 60 (addr + (page_size - 1)) & mask 61 } 62 63 /// Aligns the given address DOWN to the nearest __page boundary. 64 #[inline(always)] __page_align_down(addr: usize) -> usize65pub fn __page_align_down(addr: usize) -> usize { 66 let mask = __page_mask(); 67 68 addr & mask 69 } 70