11da177e4SLinus Torvalds /* Rewritten by Rusty Russell, on the backs of many others... 21da177e4SLinus Torvalds Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. 31da177e4SLinus Torvalds 41da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify 51da177e4SLinus Torvalds it under the terms of the GNU General Public License as published by 61da177e4SLinus Torvalds the Free Software Foundation; either version 2 of the License, or 71da177e4SLinus Torvalds (at your option) any later version. 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds This program is distributed in the hope that it will be useful, 101da177e4SLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 111da177e4SLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 121da177e4SLinus Torvalds GNU General Public License for more details. 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds You should have received a copy of the GNU General Public License 151da177e4SLinus Torvalds along with this program; if not, write to the Free Software 161da177e4SLinus Torvalds Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 171da177e4SLinus Torvalds */ 188b96f011SFrederic Weisbecker #include <linux/ftrace.h> 19*f80d2d77SDmitri Vorobiev #include <linux/memory.h> 20505f2b97SIngo Molnar #include <linux/module.h> 21505f2b97SIngo Molnar #include <linux/mutex.h> 22505f2b97SIngo Molnar #include <linux/init.h> 23505f2b97SIngo Molnar 241da177e4SLinus Torvalds #include <asm/sections.h> 25505f2b97SIngo Molnar #include <asm/uaccess.h> 26505f2b97SIngo Molnar 27505f2b97SIngo Molnar /* 28505f2b97SIngo Molnar * mutex protecting text section modification (dynamic code patching). 29505f2b97SIngo Molnar * some users need to sleep (allocating memory...) while they hold this lock. 30505f2b97SIngo Molnar * 31505f2b97SIngo Molnar * NOT exported to modules - patching kernel text is a really delicate matter. 32505f2b97SIngo Molnar */ 33505f2b97SIngo Molnar DEFINE_MUTEX(text_mutex); 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[]; 361da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[]; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */ 391da177e4SLinus Torvalds void __init sort_main_extable(void) 401da177e4SLinus Torvalds { 411da177e4SLinus Torvalds sort_extable(__start___ex_table, __stop___ex_table); 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */ 451da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds const struct exception_table_entry *e; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds e = search_extable(__start___ex_table, __stop___ex_table-1, addr); 501da177e4SLinus Torvalds if (!e) 511da177e4SLinus Torvalds e = search_module_extables(addr); 521da177e4SLinus Torvalds return e; 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 553861a17bSFrederic Weisbecker int core_kernel_text(unsigned long addr) 561da177e4SLinus Torvalds { 571da177e4SLinus Torvalds if (addr >= (unsigned long)_stext && 581da177e4SLinus Torvalds addr <= (unsigned long)_etext) 591da177e4SLinus Torvalds return 1; 601da177e4SLinus Torvalds 61a2da4052SRusty Russell if (system_state == SYSTEM_BOOTING && 62a2da4052SRusty Russell addr >= (unsigned long)_sinittext && 631da177e4SLinus Torvalds addr <= (unsigned long)_einittext) 641da177e4SLinus Torvalds return 1; 651da177e4SLinus Torvalds return 0; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 683861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds if (core_kernel_text(addr)) 711da177e4SLinus Torvalds return 1; 721da177e4SLinus Torvalds return __module_text_address(addr) != NULL; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds int kernel_text_address(unsigned long addr) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds if (core_kernel_text(addr)) 781da177e4SLinus Torvalds return 1; 791da177e4SLinus Torvalds return module_text_address(addr) != NULL; 801da177e4SLinus Torvalds } 81ab7476cfSArjan van de Ven 82ab7476cfSArjan van de Ven /* 83ab7476cfSArjan van de Ven * On some architectures (PPC64, IA64) function pointers 84ab7476cfSArjan van de Ven * are actually only tokens to some data that then holds the 85ab7476cfSArjan van de Ven * real function address. As a result, to find if a function 86ab7476cfSArjan van de Ven * pointer is part of the kernel text, we need to do some 87ab7476cfSArjan van de Ven * special dereferencing first. 88ab7476cfSArjan van de Ven */ 89ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr) 90ab7476cfSArjan van de Ven { 91ab7476cfSArjan van de Ven unsigned long addr; 92ab7476cfSArjan van de Ven addr = (unsigned long) dereference_function_descriptor(ptr); 93ab7476cfSArjan van de Ven if (core_kernel_text(addr)) 94ab7476cfSArjan van de Ven return 1; 95ab7476cfSArjan van de Ven return module_text_address(addr) != NULL; 96ab7476cfSArjan van de Ven } 97