ia64/xen-unstable

changeset 2215:249ef8d5db7d

bitkeeper revision 1.1159.17.23 (411bb1570PNo_cbCYAWmPnmxDw4a1w)

Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into scramble.cl.cam.ac.uk:/local/scratch/kaf24/xeno
author kaf24@scramble.cl.cam.ac.uk
date Thu Aug 12 18:05:11 2004 +0000 (2004-08-12)
parents 8481b2eee50a 6b585a1087bc
children 36edd9229334 bcf4ddddff97
files linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c
line diff
     1.1 --- a/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c	Thu Aug 12 17:35:14 2004 +0000
     1.2 +++ b/linux-2.6.7-xen-sparse/arch/xen/kernel/fixup.c	Thu Aug 12 18:05:11 2004 +0000
     1.3 @@ -37,8 +37,8 @@
     1.4      if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
     1.5      __LINE__, __FILE__); *(int*)0=0; }
     1.6  #define DPRINTK(_f, _a...) printk(KERN_ALERT \
     1.7 -                           "(file=%s, line=%d, eip=%08lx) " _f "\n", \
     1.8 -                           __FILE__ , __LINE__ , eip, ## _a )
     1.9 +                           "(file=%s, line=%d) " _f "\n", \
    1.10 +                           __FILE__ , __LINE__ , ## _a )
    1.11  #else
    1.12  #define ASSERT(_p) ((void)0)
    1.13  #define DPRINTK(_f, _a...) ((void)0)
    1.14 @@ -138,6 +138,28 @@ static unsigned char insn_decode[256] = 
    1.15      O, O, O, O, O, O, O|M, X
    1.16  };
    1.17  
    1.18 +/* Bitmap of faulting instructions that we can handle. */
    1.19 +static unsigned char handleable_code[32] = {
    1.20 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.21 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.22 +    /* 0x80-0x83, 0x89, 0x8B */
    1.23 +    0x0F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.24 +    /* 0xC7 */
    1.25 +    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.26 +};
    1.27 +
    1.28 +/* Bitmap of opcodes that use a register operand specified by Mod/RM. */
    1.29 +static unsigned char opcode_uses_reg[32] = {
    1.30 +    /* 0x00 - 0x3F */
    1.31 +    0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
    1.32 +    /* 0x40 - 0x7F */
    1.33 +    0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x00, 0x00,
    1.34 +    /* 0x80 - 0xBF */
    1.35 +    0xF0, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.36 +    /* 0xC0 - 0xFF */
    1.37 +    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.38 +};
    1.39 +
    1.40  static unsigned int parse_insn(unsigned char *insn, 
    1.41                                 unsigned char *p_opcode,
    1.42                                 unsigned char *p_decode)
    1.43 @@ -188,27 +210,61 @@ static unsigned int parse_insn(unsigned 
    1.44      return ((pb - insn) + 1 + (d & INSN_SUFFIX_BYTES));
    1.45  }
    1.46  
    1.47 -/* Bitmap of faulting instructions that we can handle. */
    1.48 -static unsigned char handleable_code[32] = {
    1.49 -    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.50 -    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.51 -    /* 0x80-0x83, 0x89, 0x8B */
    1.52 -    0x0F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.53 -    /* 0xC7 */
    1.54 -    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.55 -};
    1.56 +/*
    1.57 + * Mainly this function checks that our patches can't erroneously get flushed
    1.58 + * to a file on disc, which would screw us after reboot!
    1.59 + */
    1.60 +static int safe_to_patch(unsigned long addr)
    1.61 +{
    1.62 +    struct mm_struct      *mm = current->mm;
    1.63 +    struct vm_area_struct *vma;
    1.64 +    struct file           *file;
    1.65 +    unsigned char          _name[30], *name;
    1.66 +
    1.67 +    /* Always safe to patch the fixup buffer. */
    1.68 +    if ( addr <= (FIXUP_BUF_USER + FIXUP_BUF_SIZE) )
    1.69 +        return 1;
    1.70 +
    1.71 +    down_read(&mm->mmap_sem);
    1.72 +
    1.73 +    if ( (vma = find_vma(current->mm, addr)) == NULL )
    1.74 +    {
    1.75 +        DPRINTK("No VMA contains fault address.");
    1.76 +        goto fail;
    1.77 +    }
    1.78 +
    1.79 +    /* No backing file, so safe to patch. */
    1.80 +    if ( (file = vma->vm_file) == NULL )
    1.81 +        goto success;
    1.82  
    1.83 -/* Bitmap of opcodes that use a register operand specified by Mod/RM. */
    1.84 -static unsigned char opcode_uses_reg[32] = {
    1.85 -    /* 0x00 - 0x3F */
    1.86 -    0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
    1.87 -    /* 0x40 - 0x7F */
    1.88 -    0x00, 0x00, 0x00, 0x00, 0x0C, 0x0A, 0x00, 0x00,
    1.89 -    /* 0x80 - 0xBF */
    1.90 -    0xF0, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.91 -    /* 0xC0 - 0xFF */
    1.92 -    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    1.93 -};
    1.94 +    /* No shared mappings => nobody can dirty the file. */
    1.95 +    /* XXX Note the assumption that noone will dirty the file in future! */
    1.96 +    if ( file->f_mapping->i_mmap_writable != 0 )
    1.97 +    {
    1.98 +        DPRINTK("Shared mappings exist.");
    1.99 +        goto fail;
   1.100 +    }
   1.101 +
   1.102 +    /*
   1.103 +     * Because of above dodgy assumption, we will only patch things in
   1.104 +     * /lib/tls. Our belief is that updates here will only ever occur by
   1.105 +     * unlinking the old files and installing completely fresh ones. :-)
   1.106 +     */
   1.107 +    name = d_path(file->f_dentry, file->f_vfsmnt, _name, sizeof(_name));
   1.108 +    if ( strncmp("/lib/tls", name, 8) != 0 )
   1.109 +    {
   1.110 +        DPRINTK("Backing file is not in /lib/tls");
   1.111 +        goto fail;
   1.112 +    }
   1.113 +
   1.114 + success:
   1.115 +    up_read(&mm->mmap_sem);
   1.116 +    return 1;
   1.117 +
   1.118 + fail:
   1.119 +    up_read(&mm->mmap_sem);
   1.120 +    return 0;
   1.121 +}
   1.122  
   1.123  asmlinkage void do_fixup_4gb_segment(struct pt_regs *regs, long error_code)
   1.124  {
   1.125 @@ -219,6 +275,7 @@ asmlinkage void do_fixup_4gb_segment(str
   1.126      unsigned char b[20], modrm, mod, reg, rm, sib, patch[20], opcode, decode;
   1.127      unsigned long eip = regs->eip - insn_len;
   1.128      struct fixup_entry *fe;
   1.129 +    struct page *page;
   1.130      pte_t *pte;
   1.131      pmd_t *pmd;
   1.132      pgd_t *pgd;
   1.133 @@ -231,26 +288,8 @@ asmlinkage void do_fixup_4gb_segment(str
   1.134          return;
   1.135      }
   1.136  
   1.137 -    if ( unlikely(eip >= (PAGE_OFFSET-32)) )
   1.138 -    {
   1.139 -        DPRINTK("User executing out of kernel space?!");
   1.140 +    if ( unlikely(!safe_to_patch(eip)) )
   1.141          return;
   1.142 -    }
   1.143 -
   1.144 -    /*
   1.145 -     * Check that the page to be patched is part of a private VMA. This 
   1.146 -     * means that our patch will never erroneously get flushed to disc.
   1.147 -     */
   1.148 -    if ( eip > (FIXUP_BUF_USER + FIXUP_BUF_SIZE) ) /* don't check fixup area */
   1.149 -    {
   1.150 -        /* [SMP] Need to grab the mmap_sem semaphore. */
   1.151 -        struct vm_area_struct *vma = find_vma(current->mm, eip);
   1.152 -        if ( (vma == NULL) || (vma->vm_flags & VM_MAYSHARE) )
   1.153 -        {
   1.154 -            DPRINTK("Cannot patch a shareable VMA.");
   1.155 -            return;
   1.156 -        }
   1.157 -    }
   1.158  
   1.159      if ( unlikely(copy_from_user(b, (void *)eip, sizeof(b)) != 0) )
   1.160      {
   1.161 @@ -591,6 +630,17 @@ asmlinkage void do_fixup_4gb_segment(str
   1.162      for ( i = 5; i < fe->patched_code_len; i++ )
   1.163          patch[i] = 0x90; /* nop */
   1.164  
   1.165 +    /* Find the physical page that is to be patched. Check it isn't dirty. */
   1.166 +    pgd = pgd_offset(current->mm, eip);
   1.167 +    pmd = pmd_offset(pgd, eip);
   1.168 +    pte = pte_offset_kernel(pmd, eip);
   1.169 +    page = pte_page(*pte);
   1.170 +    if ( unlikely(PageDirty(page)) )
   1.171 +    {
   1.172 +        DPRINTK("Page is already dirty.");
   1.173 +        return;
   1.174 +    }
   1.175 +
   1.176      if ( put_user(eip + PATCH_LEN, (unsigned long *)regs->esp - 1) != 0 )
   1.177      {
   1.178          DPRINTK("Failed to place return address on user stack.");
   1.179 @@ -602,12 +652,9 @@ asmlinkage void do_fixup_4gb_segment(str
   1.180      regs->eip = FIXUP_BUF_USER + fe->return_idx;
   1.181  
   1.182      /* [SMP] Need to pause other threads while patching. */
   1.183 -    pgd = pgd_offset(current->mm, eip);
   1.184 -    pmd = pmd_offset(pgd, eip);
   1.185 -    pte = pte_offset_kernel(pmd, eip);
   1.186 -    veip = kmap(pte_page(*pte));
   1.187 +    veip = kmap(page);
   1.188      memcpy((char *)veip + (eip & ~PAGE_MASK), patch, fe->patched_code_len);
   1.189 -    kunmap(pte_page(*pte));
   1.190 +    kunmap(page);
   1.191  
   1.192      return;
   1.193  }