aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-08-18 17:05:17 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-08-18 17:05:17 +0000
commitaaad736a3bd14957109d14a664c672f0a10c6dc5 (patch)
treefc2a1f83bfefc37f0b3c949588bb8cd3a23a6c16
parent23ab2ce075b7042ae1e3bcccab7aec8718327a35 (diff)
parent37dca5a201291a41bfcb5f85cec9ea2ade1314d4 (diff)
downloadxen-aaad736a3bd14957109d14a664c672f0a10c6dc5.tar.gz
xen-aaad736a3bd14957109d14a664c672f0a10c6dc5.tar.bz2
xen-aaad736a3bd14957109d14a664c672f0a10c6dc5.zip
bitkeeper revision 1.1159.1.80 (41238c4dRvX9mwKLbPmS4BpU24zugA)
Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk into scramble.cl.cam.ac.uk:/local/scratch/kaf24/xeno
-rw-r--r--linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c802
1 files changed, 32 insertions, 770 deletions
diff --git a/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c b/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c
index 50861e2b1d..b437d829fe 100644
--- a/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c
+++ b/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c
@@ -5,6 +5,11 @@
* Used to avoid repeated slow emulation of common instructions used by the
* user-space TLS (Thread-Local Storage) libraries.
*
+ * **** NOTE ****
+ * Issues with the binary rewriting have caused it to be removed. Instead
+ * we rely on Xen's emulator to boot the kernel, and then print a banner
+ * message recommending that the user disables /lib/tls.
+ *
* Copyright (c) 2004, K A Fraser
*
* This program is free software; you can redistribute it and/or modify
@@ -27,790 +32,47 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/kernel.h>
-#include <linux/pagemap.h>
-#include <linux/vmalloc.h>
-#include <linux/highmem.h>
-#include <linux/mman.h>
-#include <asm/fixmap.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#if 1
-#define ASSERT(_p) \
- if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
- __LINE__, __FILE__); *(int*)0=0; }
-#define DPRINTK(_f, _a...) printk(KERN_ALERT \
- "(file=%s, line=%d) " _f "\n", \
- __FILE__ , __LINE__ , ## _a )
-#else
-#define ASSERT(_p) ((void)0)
-#define DPRINTK(_f, _a...) ((void)0)
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#define TestSetPageLocked(_p) TryLockPage(_p)
-#define PageAnon(_p) 0 /* no equivalent in 2.4 */
-#define pte_offset_kernel pte_offset
-#define remap_page_range(_a,_b,_c,_d,_e) remap_page_range(_b,_c,_d,_e)
-#define daemonize(_n) \
- do { \
- daemonize(); \
- strcpy(current->comm, _n); \
- sigfillset(&current->blocked); \
- } while ( 0 )
-#endif
-
-static unsigned char *fixup_buf;
-#define FIXUP_BUF_USER PAGE_SIZE
-#define FIXUP_BUF_ORDER 1
-#define FIXUP_BUF_SIZE (PAGE_SIZE<<FIXUP_BUF_ORDER)
-#define PATCH_LEN 5
-
-struct fixup_entry {
- unsigned char patched_code[20];
- unsigned short patched_code_len;
- unsigned short fixup_idx;
- unsigned short return_idx;
- struct fixup_entry *next;
-};
-
-#define FIXUP_HASHSZ 128
-static struct fixup_entry *fixup_hash[FIXUP_HASHSZ];
-static inline int FIXUP_HASH(char *b)
-{
- int i, j = 0;
- for ( i = 0; i < PATCH_LEN; i++ )
- j ^= b[i];
- return j & (FIXUP_HASHSZ-1);
-}
-
-/* General instruction properties. */
-#define INSN_SUFFIX_BYTES (7)
-#define PREFIX_BYTE (1<<3)
-#define OPCODE_BYTE (1<<4)
-#define HAS_MODRM (1<<5)
-
-/* Helpful codes for the main decode routine. */
-#define CODE_MASK (3<<6)
-#define PUSH (1<<6) /* PUSH onto stack */
-#define POP (2<<6) /* POP from stack */
-#define JMP (3<<6) /* 8-bit relative JMP */
-
-/* Short forms for the table. */
-#define X 0 /* invalid for some random reason */
-#define S 0 /* invalid because it munges the stack */
-#define P PREFIX_BYTE
-#define O OPCODE_BYTE
-#define M HAS_MODRM
-
-static unsigned char insn_decode[256] = {
- /* 0x00 - 0x0F */
- O|M, O|M, O|M, O|M, O|1, O|4, S, S,
- O|M, O|M, O|M, O|M, O|1, O|4, S, X,
- /* 0x10 - 0x1F */
- O|M, O|M, O|M, O|M, O|1, O|4, S, S,
- O|M, O|M, O|M, O|M, O|1, O|4, S, S,
- /* 0x20 - 0x2F */
- O|M, O|M, O|M, O|M, O|1, O|4, P, O,
- O|M, O|M, O|M, O|M, O|1, O|4, P, O,
- /* 0x30 - 0x3F */
- O|M, O|M, O|M, O|M, O|1, O|4, P, O,
- O|M, O|M, O|M, O|M, O|1, O|4, P, O,
- /* 0x40 - 0x4F */
- O, O, O, O, S, O, O, O,
- O, O, O, O, S, O, O, O,
- /* 0x50 - 0x5F */
- O|PUSH, O|PUSH, O|PUSH, O|PUSH, S, O|PUSH, O|PUSH, O|PUSH,
- O|POP, O|POP, O|POP, O|POP, S, O|POP, O|POP, O|POP,
- /* 0x60 - 0x6F */
- S, S, O|M, O|M, P, P, X, X,
- O|4|PUSH, O|M|4, O|1|PUSH, O|M|1, O, O, O, O,
- /* 0x70 - 0x7F */
- O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
- O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP, O|1|JMP,
- /* 0x80 - 0x8F */
- O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
- O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M|POP,
- /* 0x90 - 0x9F */
- O, O, O, O, S, O, O, O,
- O, O, X, O, O, O, O, O,
- /* 0xA0 - 0xAF */
- O|1, O|4, O|1, O|4, O, O, O, O,
- O|1, O|4, O, O, O, O, O, O,
- /* 0xB0 - 0xBF */
- O|1, O|1, O|1, O|1, O|1, O|1, O|1, O|1,
- O|4, O|4, O|4, O|4, O|4, O|4, O|4, O|4,
- /* 0xC0 - 0xCF */
- O|M|1, O|M|1, X, O, X, X, O|M|1, O|M|4,
- X, X, X, X, X, X, X, X,
- /* 0xD0 - 0xDF */
- O|M, O|M, O|M, O|M, O|1, O|1, X, X,
- X, X, X, X, X, X, X, X,
- /* 0xE0 - 0xEF */
- X, X, X, X, X, X, X, X,
- X, O|4, X, O|1|JMP, X, X, X, X,
- /* 0xF0 - 0xFF */
- P, X, P, P, O, O, O|M|1, O|M|4,
- O, O, O, O, O, O, O|M, X
-};
+#include <linux/delay.h>
-/* Bitmap of faulting instructions that we can handle. */
-static unsigned char handleable_code[32] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 0x80-0x83, 0x89, 0x8B */
- 0x0F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 0xC7 */
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-/* Bitmap of opcodes that use a register operand specified by Mod/RM. */
-static unsigned char opcode_uses_reg[32] = {
- /* 0x00 - 0x3F */
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
- /* 0x40 - 0x7F */
- 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x00, 0x00,
- /* 0x80 - 0xBF */
- 0xF0, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 0xC0 - 0xFF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static unsigned int parse_insn(unsigned char *insn,
- unsigned char *p_opcode,
- unsigned char *p_decode)
-{
- unsigned char b, d, *pb, mod, rm;
-
- /* 1. Step over the prefix bytes. */
- for ( pb = insn; (pb - insn) < 4; pb++ )
- {
- b = *pb;
- d = insn_decode[b];
- if ( !(d & PREFIX_BYTE) )
- break;
- }
-
- *p_opcode = b;
- *p_decode = d;
-
- /* 2. Ensure we have a valid opcode byte. */
- if ( !(d & OPCODE_BYTE) )
- return 0;
-
- /* 3. Process Mod/RM if there is one. */
- if ( d & HAS_MODRM )
- {
- b = *(++pb);
- if ( (mod = (b >> 6) & 3) != 3 )
- {
- if ( (rm = (b >> 0) & 7) == 4 )
- pb += 1; /* SIB byte */
- switch ( mod )
- {
- case 0:
- if ( rm == 5 )
- pb += 4; /* disp32 */
- break;
- case 1:
- pb += 1; /* disp8 */
- break;
- case 2:
- pb += 4; /* disp32 */
- break;
- }
- }
- }
-
- /* 4. All done. Result is all bytes stepped over, plus any immediates. */
- return ((pb - insn) + 1 + (d & INSN_SUFFIX_BYTES));
-}
-
-#define SUCCESS 1
-#define FAIL 0
-static int map_fixup_buf(struct mm_struct *mm)
-{
- struct vm_area_struct *vma;
-
- /* Already mapped? This is a pretty safe check. */
- if ( ((vma = find_vma(current->mm, FIXUP_BUF_USER)) != NULL) &&
- (vma->vm_start <= FIXUP_BUF_USER) &&
- (vma->vm_flags == (VM_READ | VM_MAYREAD | VM_RESERVED)) &&
- (vma->vm_file == NULL) )
- return SUCCESS;
-
- if ( (vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL)) == NULL )
- {
- DPRINTK("Cannot allocate VMA.");
- return FAIL;
- }
-
- memset(vma, 0, sizeof(*vma));
-
- vma->vm_mm = mm;
- vma->vm_flags = VM_READ | VM_MAYREAD | VM_RESERVED;
- vma->vm_page_prot = PAGE_READONLY;
-
- down_write(&mm->mmap_sem);
-
- vma->vm_start = get_unmapped_area(
- NULL, FIXUP_BUF_USER, FIXUP_BUF_SIZE,
- 0, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED);
- if ( vma->vm_start != FIXUP_BUF_USER )
- {
- DPRINTK("Cannot allocate low-memory-region VMA.");
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, vma);
- return FAIL;
- }
-
- vma->vm_end = vma->vm_start + FIXUP_BUF_SIZE;
-
- if ( remap_page_range(vma, vma->vm_start, __pa(fixup_buf),
- vma->vm_end - vma->vm_start, vma->vm_page_prot) )
- {
- DPRINTK("Cannot map low-memory-region VMA.");
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, vma);
- return FAIL;
- }
-
- insert_vm_struct(mm, vma);
-
- mm->total_vm += FIXUP_BUF_SIZE >> PAGE_SHIFT;
-
- up_write(&mm->mmap_sem);
-
- return SUCCESS;
-}
-
-/*
- * Mainly this function checks that our patches can't erroneously get flushed
- * to a file on disc, which would screw us after reboot!
- */
-#define SUCCESS 1
-#define FAIL 0
-static int safe_to_patch(struct mm_struct *mm, unsigned long addr)
-{
- struct vm_area_struct *vma;
- struct file *file;
- unsigned char _name[30], *name;
-
- /* Always safe to patch the fixup buffer. */
- if ( addr <= (FIXUP_BUF_USER + FIXUP_BUF_SIZE) )
- return SUCCESS;
-
- if ( ((vma = find_vma(current->mm, addr)) == NULL) ||
- (vma->vm_start > addr) )
- {
- DPRINTK("No VMA contains fault address.");
- return FAIL;
- }
-
- /* Only patch shared libraries. */
- if ( (file = vma->vm_file) == NULL )
- {
- DPRINTK("VMA is anonymous!");
- return FAIL;
- }
-
- /* No shared mappings => nobody can dirty the file. */
- /* XXX Note the assumption that noone will dirty the file in future! */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- if ( file->f_mapping->i_mmap_writable != 0 )
-#else
- if ( file->f_dentry->d_inode->i_mapping->i_mmap_shared != NULL )
-#endif
- {
- DPRINTK("Shared mappings exist.");
- return FAIL;
- }
-
- /*
- * Because of above dodgy assumption, we will only patch things in
- * /lib/tls. Our belief is that updates here will only ever occur by
- * unlinking the old files and installing completely fresh ones. :-)
- */
- name = d_path(file->f_dentry, file->f_vfsmnt, _name, sizeof(_name));
- if ( IS_ERR(name) || (strncmp("/lib/tls", name, 8) != 0) )
- {
- DPRINTK("Backing file is not in /lib/tls");
- return FAIL;
- }
-
- return SUCCESS;
-}
+#define DP(_f) printk(KERN_ALERT " " _f "\n")
asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
{
- static unsigned int fixup_idx = 0;
- struct mm_struct *mm = current->mm;
- unsigned int fi;
- int save_indirect_reg, hash, i;
- unsigned int insn_len = (unsigned int)error_code, new_insn_len;
- unsigned char b[20], modrm, mod, reg, rm, sib, patch[20], opcode, decode;
- unsigned long eip = regs->eip - insn_len;
- struct fixup_entry *fe;
- struct page *page;
- pte_t *pte;
- pmd_t *pmd;
- pgd_t *pgd;
- void *veip;
-
- /* Easy check that code segment has base 0, max limit. */
- if ( unlikely(regs->xcs != __USER_CS) )
- {
- DPRINTK("Unexpected CS value.");
- return;
- }
-
- if ( unlikely(!map_fixup_buf(mm)) )
- goto out;
-
- /* Hold the mmap_sem to prevent the mapping from disappearing under us. */
- down_read(&mm->mmap_sem);
-
- if ( unlikely(!safe_to_patch(mm, eip)) )
- goto out;
-
- if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
- {
- DPRINTK("Could not read instruction bytes from user space.");
- goto out;
- }
-
- /* Already created a fixup for this code sequence? */
- hash = FIXUP_HASH(b);
- for ( fe = fixup_hash[hash]; fe != NULL; fe = fe->next )
- {
- if ( memcmp(fe->patched_code, b, fe->patched_code_len) == 0 )
- goto do_the_patch;
- }
-
- /* Guaranteed enough room to patch? */
- if ( unlikely((fi = fixup_idx) > (FIXUP_BUF_SIZE-64)) )
- {
- static int printed = 0;
- if ( !printed )
- printk(KERN_ALERT "WARNING: Out of room in segment-fixup page.\n");
- printed = 1;
- goto out;
- }
-
- /* Must be a handleable opcode with GS override. */
- if ( (b[0] != 0x65) ||
- !test_bit((unsigned int)b[1], (unsigned long *)handleable_code) )
- {
- DPRINTK("No GS override, or not a MOV (%02x %02x).", b[0], b[1]);
- goto out;
- }
-
- modrm = b[2];
- mod = (modrm >> 6) & 3;
- reg = (modrm >> 3) & 7;
- rm = (modrm >> 0) & 7;
-
- /* If indirect register isn't clobbered then we must push/pop it. */
- save_indirect_reg = !((b[1] == 0x8b) && (reg == rm));
-
- /* We don't grok SIB bytes. */
- if ( rm == 4 )
- {
- DPRINTK("We don't grok SIB bytes.");
- goto out;
- }
-
- /* Ensure Mod/RM specifies (r32) or disp8(r32). */
- switch ( mod )
- {
- case 0:
- if ( rm == 5 )
- {
- DPRINTK("Unhandleable disp32 EA %d.", rm);
- goto out;
- }
- break; /* m32 == (r32) */
- case 1:
- break; /* m32 == disp8(r32) */
- default:
- DPRINTK("Unhandleable Mod value %d.", mod);
- goto out;
- }
-
- /* Indirect jump pointer. */
- *(u32 *)&fixup_buf[fi] = FIXUP_BUF_USER + fi + 4;
- fi += 4;
-
- /* push <r32> */
- if ( save_indirect_reg )
- fixup_buf[fi++] = 0x50 + rm;
-
- /* pushf */
- fixup_buf[fi++] = 0x9c;
-
- /* add %gs:0,<r32> */
- fixup_buf[fi++] = 0x65;
- fixup_buf[fi++] = 0x03;
- fixup_buf[fi++] = 0x05 | (rm << 3);
- *(unsigned long *)&fixup_buf[fi] = 0;
- fi += 4;
-
- /* popf */
- fixup_buf[fi++] = 0x9d;
-
- /* Relocate the faulting instruction, minus the GS override. */
- memcpy(&fixup_buf[fi], &b[1], error_code - 1);
- fi += error_code - 1;
-
- /* pop <r32> */
- if ( save_indirect_reg )
- fixup_buf[fi++] = 0x58 + rm;
+ static unsigned long printed = 0;
+ int i;
- for ( ; ; )
+ if ( !test_and_set_bit(0, &printed) )
{
- if ( insn_len >= PATCH_LEN )
- {
- /* ret */
- fixup_buf[fi++] = 0xc3;
- break;
- }
-
- /* Bail if can't decode the following instruction. */
- if ( unlikely((new_insn_len =
- parse_insn(&b[insn_len], &opcode, &decode)) == 0) )
- {
- DPRINTK("Could not decode following instruction.");
- goto out;
- }
-
- if ( (decode & CODE_MASK) == JMP )
- {
- long off;
-
- memcpy(&fixup_buf[fi], &b[insn_len], new_insn_len - 1);
- fi += new_insn_len - 1;
-
- /* Patch the 8-bit relative offset. */
- fixup_buf[fi++] = 1;
-
- insn_len += new_insn_len;
- ASSERT(insn_len >= PATCH_LEN);
-
- /* ret */
- fixup_buf[fi++] = 0xc3;
-
- /* pushf */
- fixup_buf[fi++] = 0x9c;
-
- off = (insn_len - PATCH_LEN) + (long)(char)b[insn_len-1];
- if ( unlikely(off > 127) )
- {
- /* add <imm32>,4(%esp) */
- fixup_buf[fi++] = 0x81;
- fixup_buf[fi++] = 0x44;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0x04;
- fi += 4;
- *(long *)&fixup_buf[fi-4] = off;
- }
- else
- {
- /* add <imm8>,4(%esp) [sign-extended] */
- fixup_buf[fi++] = 0x83;
- fixup_buf[fi++] = 0x44;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0x04;
- fixup_buf[fi++] = (char)(off & 0xff);
- }
-
- /* popf */
- fixup_buf[fi++] = 0x9d;
-
- /* ret */
- fixup_buf[fi++] = 0xc3;
-
- break;
- }
- else if ( opcode == 0xe9 ) /* jmp <rel32> */
- {
- insn_len += new_insn_len;
- ASSERT(insn_len >= PATCH_LEN);
-
- /* pushf */
- fixup_buf[fi++] = 0x9c;
-
- /* add <imm32>,4(%esp) */
- fixup_buf[fi++] = 0x81;
- fixup_buf[fi++] = 0x44;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0x04;
- fi += 4;
- *(long *)&fixup_buf[fi-4] =
- (insn_len - PATCH_LEN) + *(long *)&b[insn_len-4];
-
- /* popf */
- fixup_buf[fi++] = 0x9d;
-
- /* ret */
- fixup_buf[fi++] = 0xc3;
-
- break;
- }
- else if ( opcode == 0xc3 ) /* ret */
- {
- /* pop -4(%esp) [doesn't affect EFLAGS] */
- fixup_buf[fi++] = 0x8f;
- fixup_buf[fi++] = 0x44;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0xfc;
- }
- else
- {
- int stack_addon = 4;
-
- if ( (decode & CODE_MASK) == PUSH )
- {
- stack_addon = 8;
- /* push (%esp) */
- fixup_buf[fi++] = 0xff;
- fixup_buf[fi++] = 0x34;
- fixup_buf[fi++] = 0x24;
- }
- else if ( (decode & CODE_MASK) == POP )
- {
- stack_addon = 8;
- /* push 4(%esp) */
- fixup_buf[fi++] = 0xff;
- fixup_buf[fi++] = 0x74;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0x04;
- }
-
- /* Check for EA calculations involving ESP, and skip return addr */
- if ( decode & HAS_MODRM )
- {
- do { new_insn_len--; }
- while ( (fixup_buf[fi++] = b[insn_len++]) != opcode );
-
- modrm = fixup_buf[fi++] = b[insn_len++];
- new_insn_len--;
- mod = (modrm >> 6) & 3;
- reg = (modrm >> 3) & 7;
- rm = (modrm >> 0) & 7;
-
- if ( (reg == 4) &&
- test_bit(opcode, (unsigned long *)opcode_uses_reg) )
- {
- DPRINTK("Data movement to ESP unsupported.");
- goto out;
- }
-
- if ( rm == 4 )
- {
- if ( mod == 3 )
- {
- DPRINTK("Data movement to ESP is unsupported.");
- goto out;
- }
-
- sib = fixup_buf[fi++] = b[insn_len++];
- new_insn_len--;
- if ( (sib & 7) == 4 )
- {
- switch ( mod )
- {
- case 0:
- mod = 1;
- fixup_buf[fi-2] |= 0x40;
- fixup_buf[fi++] = stack_addon;
- break;
- case 1:
- fixup_buf[fi++] = b[insn_len++] + stack_addon;
- new_insn_len--;
- break;
- case 2:
- *(long *)&fixup_buf[fi] =
- *(long *)&b[insn_len] + stack_addon;
- fi += 4;
- insn_len += 4;
- new_insn_len -= 4;
- break;
- }
- }
- }
- }
-
- /* Relocate the (remainder of) the instruction. */
- if ( new_insn_len != 0 )
- {
- memcpy(&fixup_buf[fi], &b[insn_len], new_insn_len);
- fi += new_insn_len;
- }
-
- if ( (decode & CODE_MASK) == PUSH )
- {
- /* pop 4(%esp) */
- fixup_buf[fi++] = 0x8f;
- fixup_buf[fi++] = 0x44;
- fixup_buf[fi++] = 0x24;
- fixup_buf[fi++] = 0x04;
- }
- else if ( (decode & CODE_MASK) == POP )
- {
- /* pop (%esp) */
- fixup_buf[fi++] = 0x8f;
- fixup_buf[fi++] = 0x04;
- fixup_buf[fi++] = 0x24;
- }
- }
-
- if ( (insn_len += new_insn_len) > 20 )
- {
- DPRINTK("Code to patch is too long!");
- goto out;
- }
+ HYPERVISOR_vm_assist(VMASST_CMD_disable,
+ VMASST_TYPE_4gb_segments_notify);
- /* Can't have a RET in the middle of a patch sequence. */
- if ( (opcode == 0xc3) && (insn_len < PATCH_LEN) )
+ DP("");
+ DP("***************************************************************");
+ DP("***************************************************************");
+ DP("** WARNING: Currently emulating unsupported memory accesses **");
+ DP("** in /lib/tls libraries. Although this emulation **");
+ DP("** ensures correct execution, it is very slow! **");
+ DP("** TO OBTAIN FULL PERFORMANCE, EXECUTE THE **");
+ DP("** FOLLOWING AS ROOT: **");
+ DP("** mv /lib/tls /lib/tls.disabled **");
+ DP("***************************************************************");
+ DP("***************************************************************");
+ DP("");
+
+ for ( i = 5; i > 0; i-- )
{
- DPRINTK("RET in middle of patch seq!\n");
- goto out;
+ printk("Pausing... %d", i);
+ mdelay(1000);
+ printk("\b\b\b\b\b\b\b\b\b\b\b\b");
}
+ printk("Continuing...\n\n");
}
-
- /* Create an entry for a new fixup patch. */
- fe = kmalloc(sizeof(struct fixup_entry), GFP_KERNEL);
- if ( unlikely(fe == NULL) )
- {
- DPRINTK("Not enough memory to allocate a fixup_entry.");
- goto out;
- }
- fe->patched_code_len = insn_len;
- memcpy(fe->patched_code, b, insn_len);
- fe->fixup_idx = fixup_idx;
- fe->return_idx =
- fixup_idx + error_code + (save_indirect_reg ? 14 : 12);
- fe->next = fixup_hash[hash];
- fixup_hash[hash] = fe;
-
- /* Commit the patch. */
- fixup_idx = fi;
-
- do_the_patch:
-
- if ( unlikely(((eip ^ (eip + fe->patched_code_len)) & PAGE_MASK) != 0) )
- {
- DPRINTK("Patch instruction would straddle a page boundary.");
- goto out;
- }
-
- if ( put_user(eip + PATCH_LEN, (unsigned long *)regs->esp - 1) != 0 )
- {
- DPRINTK("Failed to place return address on user stack.");
- goto out;
- }
-
- /* Create the patching instructions in a temporary buffer. */
- patch[0] = 0x67;
- patch[1] = 0xff;
- patch[2] = 0x16; /* call <r/m16> */
- *(u16 *)&patch[3] = FIXUP_BUF_USER + fe->fixup_idx;
- for ( i = 5; i < fe->patched_code_len; i++ )
- patch[i] = 0x90; /* nop */
-
- spin_lock(&mm->page_table_lock);
-
- /* Find the physical page that is to be patched. */
- pgd = pgd_offset(current->mm, eip);
- if ( unlikely(!pgd_present(*pgd)) )
- goto unlock_and_out;
- pmd = pmd_offset(pgd, eip);
- if ( unlikely(!pmd_present(*pmd)) )
- goto unlock_and_out;
- pte = pte_offset_kernel(pmd, eip);
- if ( unlikely(!pte_present(*pte)) )
- goto unlock_and_out;
- page = pte_page(*pte);
-
- /*
- * We get lock to prevent page going AWOL on us. Also a locked page
- * might be getting flushed to disc!
- */
- if ( unlikely(TestSetPageLocked(page)) )
- {
- DPRINTK("Page is locked.");
- goto unlock_and_out;
- }
-
- /*
- * If page is dirty it will get flushed back to disc - bad news! An
- * anonymous page may be moulinexed under our feet by another thread.
- */
- if ( unlikely(PageDirty(page)) || unlikely(PageAnon(page)) )
- {
- DPRINTK("Page is dirty or anonymous.");
- unlock_page(page);
- goto unlock_and_out;
- }
-
- veip = kmap(page);
- memcpy((char *)veip + (eip & ~PAGE_MASK), patch, fe->patched_code_len);
- kunmap(page);
-
- unlock_page(page);
- spin_unlock(&mm->page_table_lock);
-
- /* Success! Return to user land to execute 2nd insn of the pair. */
- regs->esp -= 4;
- regs->eip = FIXUP_BUF_USER + fe->return_idx;
-
- out:
- up_read(&mm->mmap_sem);
- return;
-
- unlock_and_out:
- spin_unlock(&mm->page_table_lock);
- up_read(&mm->mmap_sem);
- return;
}
-static int fixup_thread(void *unused)
-{
- daemonize("segfixup");
-
- for ( ; ; )
- {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
-}
-
-static int nosegfixup = 0;
-
static int __init fixup_init(void)
{
- int i;
-
- nosegfixup = 1; /* XXX */
-
- if ( !nosegfixup )
- {
- HYPERVISOR_vm_assist(VMASST_CMD_enable,
- VMASST_TYPE_4gb_segments_notify);
- fixup_buf = (char *)__get_free_pages(GFP_ATOMIC, FIXUP_BUF_ORDER);
- for ( i = 0; i < (1 << FIXUP_BUF_ORDER); i++ )
- SetPageReserved(virt_to_page(fixup_buf) + i);
- memset(fixup_hash, 0, sizeof(fixup_hash));
- (void)kernel_thread(fixup_thread, NULL, CLONE_FS | CLONE_FILES);
- }
-
+ HYPERVISOR_vm_assist(VMASST_CMD_enable,
+ VMASST_TYPE_4gb_segments_notify);
return 0;
}
__initcall(fixup_init);
-
-static int __init fixup_setup(char *str)
-{
- nosegfixup = 1;
- return 0;
-}
-__setup("nosegfixup", fixup_setup);