162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_GENERIC_SECTIONS_H_ 362306a36Sopenharmony_ci#define _ASM_GENERIC_SECTIONS_H_ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci/* References to section boundaries */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/compiler.h> 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * Usage guidelines: 1262306a36Sopenharmony_ci * _text, _data: architecture specific, don't use them in arch-independent code 1362306a36Sopenharmony_ci * [_stext, _etext]: contains .text.* sections, may also contain .rodata.* 1462306a36Sopenharmony_ci * and/or .init.* sections 1562306a36Sopenharmony_ci * [_sdata, _edata]: contains .data.* sections, may also contain .rodata.* 1662306a36Sopenharmony_ci * and/or .init.* sections. 1762306a36Sopenharmony_ci * [__start_rodata, __end_rodata]: contains .rodata.* sections 1862306a36Sopenharmony_ci * [__start_ro_after_init, __end_ro_after_init]: 1962306a36Sopenharmony_ci * contains .data..ro_after_init section 2062306a36Sopenharmony_ci * [__init_begin, __init_end]: contains .init.* sections, but .init.text.* 2162306a36Sopenharmony_ci * may be out of this range on some architectures. 2262306a36Sopenharmony_ci * [_sinittext, _einittext]: contains .init.text.* sections 2362306a36Sopenharmony_ci * [__bss_start, __bss_stop]: contains BSS sections 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Following global variables are optional and may be unavailable on some 2662306a36Sopenharmony_ci * architectures and/or kernel configurations. 2762306a36Sopenharmony_ci * _text, _data 2862306a36Sopenharmony_ci * __kprobes_text_start, __kprobes_text_end 2962306a36Sopenharmony_ci * __entry_text_start, __entry_text_end 3062306a36Sopenharmony_ci * __ctors_start, __ctors_end 3162306a36Sopenharmony_ci * __irqentry_text_start, __irqentry_text_end 3262306a36Sopenharmony_ci * __softirqentry_text_start, __softirqentry_text_end 3362306a36Sopenharmony_ci * __start_opd, __end_opd 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ciextern char _text[], _stext[], _etext[]; 3662306a36Sopenharmony_ciextern char _data[], _sdata[], _edata[]; 3762306a36Sopenharmony_ciextern char __bss_start[], __bss_stop[]; 3862306a36Sopenharmony_ciextern char __init_begin[], __init_end[]; 3962306a36Sopenharmony_ciextern char _sinittext[], _einittext[]; 4062306a36Sopenharmony_ciextern char __start_ro_after_init[], __end_ro_after_init[]; 4162306a36Sopenharmony_ciextern char _end[]; 4262306a36Sopenharmony_ciextern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[]; 4362306a36Sopenharmony_ciextern char __kprobes_text_start[], __kprobes_text_end[]; 4462306a36Sopenharmony_ciextern char __entry_text_start[], __entry_text_end[]; 4562306a36Sopenharmony_ciextern char __start_rodata[], __end_rodata[]; 4662306a36Sopenharmony_ciextern char __irqentry_text_start[], __irqentry_text_end[]; 4762306a36Sopenharmony_ciextern char __softirqentry_text_start[], __softirqentry_text_end[]; 4862306a36Sopenharmony_ciextern char __start_once[], __end_once[]; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Start and end of .ctors section - used for constructor calls. */ 5162306a36Sopenharmony_ciextern char __ctors_start[], __ctors_end[]; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Start and end of .opd section - used for function descriptors. */ 5462306a36Sopenharmony_ciextern char __start_opd[], __end_opd[]; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* Start and end of instrumentation protected text section */ 5762306a36Sopenharmony_ciextern char __noinstr_text_start[], __noinstr_text_end[]; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciextern __visible const void __nosave_begin, __nosave_end; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Function descriptor handling (if any). Override in asm/sections.h */ 6262306a36Sopenharmony_ci#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS 6362306a36Sopenharmony_civoid *dereference_function_descriptor(void *ptr); 6462306a36Sopenharmony_civoid *dereference_kernel_function_descriptor(void *ptr); 6562306a36Sopenharmony_ci#else 6662306a36Sopenharmony_ci#define dereference_function_descriptor(p) ((void *)(p)) 6762306a36Sopenharmony_ci#define dereference_kernel_function_descriptor(p) ((void *)(p)) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* An address is simply the address of the function. */ 7062306a36Sopenharmony_citypedef struct { 7162306a36Sopenharmony_ci unsigned long addr; 7262306a36Sopenharmony_ci} func_desc_t; 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline bool have_function_descriptors(void) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci return IS_ENABLED(CONFIG_HAVE_FUNCTION_DESCRIPTORS); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * memory_contains - checks if an object is contained within a memory region 8262306a36Sopenharmony_ci * @begin: virtual address of the beginning of the memory region 8362306a36Sopenharmony_ci * @end: virtual address of the end of the memory region 8462306a36Sopenharmony_ci * @virt: virtual address of the memory object 8562306a36Sopenharmony_ci * @size: size of the memory object 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * Returns: true if the object specified by @virt and @size is entirely 8862306a36Sopenharmony_ci * contained within the memory region defined by @begin and @end, false 8962306a36Sopenharmony_ci * otherwise. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic inline bool memory_contains(void *begin, void *end, void *virt, 9262306a36Sopenharmony_ci size_t size) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return virt >= begin && virt + size <= end; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * memory_intersects - checks if the region occupied by an object intersects 9962306a36Sopenharmony_ci * with another memory region 10062306a36Sopenharmony_ci * @begin: virtual address of the beginning of the memory region 10162306a36Sopenharmony_ci * @end: virtual address of the end of the memory region 10262306a36Sopenharmony_ci * @virt: virtual address of the memory object 10362306a36Sopenharmony_ci * @size: size of the memory object 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Returns: true if an object's memory region, specified by @virt and @size, 10662306a36Sopenharmony_ci * intersects with the region specified by @begin and @end, false otherwise. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic inline bool memory_intersects(void *begin, void *end, void *virt, 10962306a36Sopenharmony_ci size_t size) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci void *vend = virt + size; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (virt < end && vend > begin) 11462306a36Sopenharmony_ci return true; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return false; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/** 12062306a36Sopenharmony_ci * init_section_contains - checks if an object is contained within the init 12162306a36Sopenharmony_ci * section 12262306a36Sopenharmony_ci * @virt: virtual address of the memory object 12362306a36Sopenharmony_ci * @size: size of the memory object 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * Returns: true if the object specified by @virt and @size is entirely 12662306a36Sopenharmony_ci * contained within the init section, false otherwise. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic inline bool init_section_contains(void *virt, size_t size) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return memory_contains(__init_begin, __init_end, virt, size); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/** 13462306a36Sopenharmony_ci * init_section_intersects - checks if the region occupied by an object 13562306a36Sopenharmony_ci * intersects with the init section 13662306a36Sopenharmony_ci * @virt: virtual address of the memory object 13762306a36Sopenharmony_ci * @size: size of the memory object 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Returns: true if an object's memory region, specified by @virt and @size, 14062306a36Sopenharmony_ci * intersects with the init section, false otherwise. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistatic inline bool init_section_intersects(void *virt, size_t size) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return memory_intersects(__init_begin, __init_end, virt, size); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * is_kernel_core_data - checks if the pointer address is located in the 14962306a36Sopenharmony_ci * .data or .bss section 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * @addr: address to check 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * Returns: true if the address is located in .data or .bss, false otherwise. 15462306a36Sopenharmony_ci * Note: On some archs it may return true for core RODATA, and false 15562306a36Sopenharmony_ci * for others. But will always be true for core RW data. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic inline bool is_kernel_core_data(unsigned long addr) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci if (addr >= (unsigned long)_sdata && addr < (unsigned long)_edata) 16062306a36Sopenharmony_ci return true; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (addr >= (unsigned long)__bss_start && 16362306a36Sopenharmony_ci addr < (unsigned long)__bss_stop) 16462306a36Sopenharmony_ci return true; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return false; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * is_kernel_rodata - checks if the pointer address is located in the 17162306a36Sopenharmony_ci * .rodata section 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * @addr: address to check 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * Returns: true if the address is located in .rodata, false otherwise. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic inline bool is_kernel_rodata(unsigned long addr) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci return addr >= (unsigned long)__start_rodata && 18062306a36Sopenharmony_ci addr < (unsigned long)__end_rodata; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/** 18462306a36Sopenharmony_ci * is_kernel_inittext - checks if the pointer address is located in the 18562306a36Sopenharmony_ci * .init.text section 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * @addr: address to check 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Returns: true if the address is located in .init.text, false otherwise. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic inline bool is_kernel_inittext(unsigned long addr) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci return addr >= (unsigned long)_sinittext && 19462306a36Sopenharmony_ci addr < (unsigned long)_einittext; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * __is_kernel_text - checks if the pointer address is located in the 19962306a36Sopenharmony_ci * .text section 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * @addr: address to check 20262306a36Sopenharmony_ci * 20362306a36Sopenharmony_ci * Returns: true if the address is located in .text, false otherwise. 20462306a36Sopenharmony_ci * Note: an internal helper, only check the range of _stext to _etext. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic inline bool __is_kernel_text(unsigned long addr) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci return addr >= (unsigned long)_stext && 20962306a36Sopenharmony_ci addr < (unsigned long)_etext; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * __is_kernel - checks if the pointer address is located in the kernel range 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * @addr: address to check 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * Returns: true if the address is located in the kernel range, false otherwise. 21862306a36Sopenharmony_ci * Note: an internal helper, check the range of _stext to _end, 21962306a36Sopenharmony_ci * and range from __init_begin to __init_end, which can be outside 22062306a36Sopenharmony_ci * of the _stext to _end range. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic inline bool __is_kernel(unsigned long addr) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci return ((addr >= (unsigned long)_stext && 22562306a36Sopenharmony_ci addr < (unsigned long)_end) || 22662306a36Sopenharmony_ci (addr >= (unsigned long)__init_begin && 22762306a36Sopenharmony_ci addr < (unsigned long)__init_end)); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#endif /* _ASM_GENERIC_SECTIONS_H_ */ 231