Messages in this thread Patch in this message | | | From | Jeffrey Brian Arnold <> | Subject | [RFC PATCH 7/9] Ksplice: x86-32 and x86-64 support | Date | Sat, 13 Sep 2008 00:49:55 -0400 |
| |
Add support for Ksplice on x86.
Signed-off-by: Jeffrey Brian Arnold <jbarnold@mit.edu> Signed-off-by: Anders Kaseorg <andersk@mit.edu> Signed-off-by: Tim Abbott <tabbott@mit.edu> --- arch/x86/Kconfig | 1 + arch/x86/kernel/ksplice-arch.c | 91 ++++++++++++++++++++++++++++++++++++++++ arch/x86/mm/init_32.c | 6 +- arch/x86/mm/init_64.c | 4 +- 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 arch/x86/kernel/ksplice-arch.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ed92864..b5ec2f4 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -23,6 +23,7 @@ config X86 select HAVE_OPROFILE select HAVE_IOREMAP_PROT select HAVE_KPROBES + select HAVE_KSPLICE select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_KRETPROBES select HAVE_DYNAMIC_FTRACE diff --git a/arch/x86/kernel/ksplice-arch.c b/arch/x86/kernel/ksplice-arch.c new file mode 100644 index 0000000..52314c4 --- /dev/null +++ b/arch/x86/kernel/ksplice-arch.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2007-2008 Jeffrey Brian Arnold <jbarnold@mit.edu> + * Copyright (C) 2008 Anders Kaseorg <andersk@mit.edu>, + * Tim Abbott <tabbott@mit.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#define KSPLICE_IP(x) ((x)->thread.ip) +#define KSPLICE_SP(x) ((x)->thread.sp) + +static const struct ksplice_symbol trampoline_symbol = { + .name = NULL, + .label = "<trampoline>", +}; + +static const struct ksplice_reloc trampoline_reloc = { + .symbol = &trampoline_symbol, + .pcrel = 1, + .addend = -4, + .size = 4, + .dst_mask = 0xffffffffL, + .rightshift = 0, + .signed_addend = 1, +}; + +static abort_t trampoline_target(struct ksplice_pack *pack, unsigned long addr, + unsigned long *new_addr) +{ + abort_t ret; + unsigned char byte; + + if (probe_kernel_read(&byte, (void *)addr, sizeof(byte)) == -EFAULT) + return NO_MATCH; + + if (byte != 0xe9) + return NO_MATCH; + + ret = read_reloc_value(pack, &trampoline_reloc, addr + 1, new_addr); + if (ret != OK) + return ret; + + *new_addr += addr + 1; + return OK; +} + +static abort_t prepare_trampoline(struct ksplice_pack *pack, + struct ksplice_trampoline *t) +{ + t->size = 5; + t->trampoline[0] = 0xe9; + return write_reloc_value(pack, &trampoline_reloc, + (unsigned long)t->trampoline + 1, + t->repladdr - (t->oldaddr + 1)); +} + +static abort_t handle_paravirt(struct ksplice_pack *pack, + unsigned long pre_addr, unsigned long run_addr, + int *matched) +{ + unsigned char run[5], pre[5]; + *matched = 0; + + if (probe_kernel_read(&run, (void *)run_addr, sizeof(run)) == -EFAULT || + probe_kernel_read(&pre, (void *)pre_addr, sizeof(pre)) == -EFAULT) + return OK; + + if ((run[0] == 0xe8 && pre[0] == 0xe8) || + (run[0] == 0xe9 && pre[0] == 0xe9)) + if (run_addr + 1 + *(int32_t *)&run[1] == + pre_addr + 1 + *(int32_t *)&pre[1]) + *matched = 5; + return OK; +} + +static bool valid_stack_ptr(const struct thread_info *tinfo, const void *p) +{ + return p > (const void *)tinfo + && p <= (const void *)tinfo + THREAD_SIZE - sizeof(long); +} + diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index d37f293..5998d5c 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -1036,8 +1036,8 @@ void mark_rodata_ro(void) unsigned long start = PFN_ALIGN(_text); unsigned long size = PFN_ALIGN(_etext) - start; -#ifndef CONFIG_DYNAMIC_FTRACE - /* Dynamic tracing modifies the kernel text section */ +#if !defined(CONFIG_DYNAMIC_FTRACE) && !defined(CONFIG_KSPLICE) + /* Dynamic tracing and Ksplice modify the kernel text section */ set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); printk(KERN_INFO "Write protecting the kernel text: %luk\n", size >> 10); @@ -1050,7 +1050,7 @@ void mark_rodata_ro(void) printk(KERN_INFO "Testing CPA: write protecting again\n"); set_pages_ro(virt_to_page(start), size>>PAGE_SHIFT); #endif -#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* !CONFIG_DYNAMIC_FTRACE && !CONFIG_KSPLICE */ start += size; size = (unsigned long)__end_rodata - start; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index d3746ef..31db657 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -857,8 +857,8 @@ void mark_rodata_ro(void) unsigned long rodata_start = ((unsigned long)__start_rodata + PAGE_SIZE - 1) & PAGE_MASK; -#ifdef CONFIG_DYNAMIC_FTRACE - /* Dynamic tracing modifies the kernel text section */ +#if defined(CONFIG_DYNAMIC_FTRACE) || defined(CONFIG_KSPLICE) + /* Dynamic tracing and Ksplice modify the kernel text section */ start = rodata_start; #endif -- 1.5.4.3
| |