ia64/xen-unstable

changeset 1099:42978d167ae5

bitkeeper revision 1.732 (403351fdWpb7sTMMhh7hUEOPzmRvoQ)

hypervisor.h, hypervisor.c, traps.c, entry.S:
Fix failsafe handling and LDT-trap handling.
author kaf24@scramble.cl.cam.ac.uk
date Wed Feb 18 11:52:29 2004 +0000 (2004-02-18)
parents 099594bb1c15
children 7a9e36d29982
files xen/arch/i386/traps.c xenolinux-2.4.24-sparse/arch/xeno/kernel/entry.S xenolinux-2.4.24-sparse/arch/xeno/kernel/traps.c xenolinux-2.4.24-sparse/arch/xeno/mm/hypervisor.c xenolinux-2.4.24-sparse/include/asm-xeno/hypervisor.h
line diff
     1.1 --- a/xen/arch/i386/traps.c	Tue Feb 17 22:47:33 2004 +0000
     1.2 +++ b/xen/arch/i386/traps.c	Wed Feb 18 11:52:29 2004 +0000
     1.3 @@ -317,16 +317,24 @@ asmlinkage void do_page_fault(struct pt_
     1.4  {
     1.5      struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
     1.6      trap_info_t *ti;
     1.7 -    unsigned long addr, fixup;
     1.8 +    unsigned long off, addr, fixup;
     1.9      struct task_struct *p = current;
    1.10      extern int map_ldt_shadow_page(unsigned int);
    1.11  
    1.12      __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
    1.13  
    1.14 -    if ( unlikely(addr > PAGE_OFFSET) )
    1.15 -        goto fault_in_xen_space;
    1.16 -
    1.17 - propagate_fault:
    1.18 +    if ( unlikely(addr >= LDT_VIRT_START) && 
    1.19 +         (addr < (LDT_VIRT_START + (p->mm.ldt_ents*LDT_ENTRY_SIZE))) )
    1.20 +    {
    1.21 +        /*
    1.22 +         * Copy a mapping from the guest's LDT, if it is valid. Otherwise we
    1.23 +         * send the fault up to the guest OS to be handled.
    1.24 +         */
    1.25 +        off  = addr - LDT_VIRT_START;
    1.26 +        addr = p->mm.ldt_base + off;
    1.27 +        if ( likely(map_ldt_shadow_page(off >> PAGE_SHIFT) == 0) )
    1.28 +            return; /* successfully copied the mapping */
    1.29 +    }
    1.30  
    1.31      if ( unlikely(!(regs->xcs & 3)) )
    1.32          goto fault_in_hypervisor;
    1.33 @@ -341,20 +349,6 @@ asmlinkage void do_page_fault(struct pt_
    1.34          clear_bit(EVENTS_MASTER_ENABLE_BIT, &p->shared_info->events_mask);
    1.35      return; 
    1.36  
    1.37 -    /*
    1.38 -     * FAULT IN XEN ADDRESS SPACE:
    1.39 -     *  We only deal with one kind -- a fault in the shadow LDT mapping.
    1.40 -     *  If this occurs we pull a mapping from the guest's LDT, if it is
    1.41 -     *  valid. Otherwise we send the fault up to the guest OS to be handled.
    1.42 -     */
    1.43 - fault_in_xen_space:
    1.44 -
    1.45 -    if ( (addr < LDT_VIRT_START) || 
    1.46 -         (addr >= (LDT_VIRT_START + (p->mm.ldt_ents*LDT_ENTRY_SIZE))) ||
    1.47 -         map_ldt_shadow_page((addr - LDT_VIRT_START) >> PAGE_SHIFT) )
    1.48 -        goto propagate_fault;
    1.49 -    return;
    1.50 -
    1.51   fault_in_hypervisor:
    1.52  
    1.53      if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
     2.1 --- a/xenolinux-2.4.24-sparse/arch/xeno/kernel/entry.S	Tue Feb 17 22:47:33 2004 +0000
     2.2 +++ b/xenolinux-2.4.24-sparse/arch/xeno/kernel/entry.S	Wed Feb 18 11:52:29 2004 +0000
     2.3 @@ -367,10 +367,12 @@ critical_fixup_table:
     2.4  
     2.5  # Hypervisor uses this for application faults while it executes.
     2.6  ENTRY(failsafe_callback)
     2.7 +        call SYMBOL_NAME(install_safe_pf_handler)
     2.8  1:      pop  %ds
     2.9  2:      pop  %es
    2.10  3:      pop  %fs
    2.11  4:      pop  %gs
    2.12 +        call SYMBOL_NAME(install_normal_pf_handler)
    2.13  5:      iret
    2.14  .section .fixup,"ax";	\
    2.15  6:	movl $0,(%esp);	\
    2.16 @@ -470,34 +472,37 @@ ENTRY(alignment_check)
    2.17  
    2.18  # This handler is special, because it gets an extra value on its stack,
    2.19  # which is the linear faulting address.
    2.20 -ENTRY(page_fault)
    2.21 -	pushl %ds
    2.22 -	pushl %eax
    2.23 -	xorl %eax,%eax
    2.24 -	pushl %ebp
    2.25 -	pushl %edi
    2.26 -	pushl %esi
    2.27 -	pushl %edx
    2.28 -	decl %eax			# eax = -1
    2.29 -	pushl %ecx
    2.30 -	pushl %ebx
    2.31 -	GET_CURRENT(%ebx)
    2.32 -	cld
    2.33 -	movl %es,%ecx
    2.34 -	movl ORIG_EAX(%esp), %esi	# get the error code
    2.35 -	movl ES(%esp), %edi		# get the faulting address
    2.36 -	movl %eax, ORIG_EAX(%esp)
    2.37 -	movl %ecx, ES(%esp)
    2.38 -	movl %esp,%edx
    2.39 -        pushl %edi                      # push the faulting address
    2.40 -	pushl %esi			# push the error code
    2.41 -	pushl %edx			# push the pt_regs pointer
    2.42 -	movl $(__KERNEL_DS),%edx
    2.43 -	movl %edx,%ds
    2.44 -	movl %edx,%es
    2.45 -	call SYMBOL_NAME(do_page_fault)
    2.46 -	addl $12,%esp
    2.47 -	jmp ret_from_exception
    2.48 +#define PAGE_FAULT_STUB(_name1, _name2)                                  \
    2.49 +ENTRY(_name1)                                                            \
    2.50 +	pushl %ds                                                      ; \
    2.51 +	pushl %eax                                                     ; \
    2.52 +	xorl %eax,%eax                                                 ; \
    2.53 +	pushl %ebp                                                     ; \
    2.54 +	pushl %edi                                                     ; \
    2.55 +	pushl %esi                                                     ; \
    2.56 +	pushl %edx                                                     ; \
    2.57 +	decl %eax                      /* eax = -1 */                  ; \
    2.58 +	pushl %ecx                                                     ; \
    2.59 +	pushl %ebx                                                     ; \
    2.60 +	GET_CURRENT(%ebx)                                              ; \
    2.61 +	cld                                                            ; \
    2.62 +	movl %es,%ecx                                                  ; \
    2.63 +	movl ORIG_EAX(%esp), %esi      /* get the error code */        ; \
    2.64 +	movl ES(%esp), %edi            /* get the faulting address */  ; \
    2.65 +	movl %eax, ORIG_EAX(%esp)                                      ; \
    2.66 +	movl %ecx, ES(%esp)                                            ; \
    2.67 +	movl %esp,%edx                                                 ; \
    2.68 +        pushl %edi                     /* push the faulting address */ ; \
    2.69 +	pushl %esi                     /* push the error code */       ; \
    2.70 +	pushl %edx                     /* push the pt_regs pointer */  ; \
    2.71 +	movl $(__KERNEL_DS),%edx                                       ; \
    2.72 +	movl %edx,%ds                                                  ; \
    2.73 +	movl %edx,%es                                                  ; \
    2.74 +	call SYMBOL_NAME(_name2)                                       ; \
    2.75 +	addl $12,%esp                                                  ; \
    2.76 +	jmp ret_from_exception                                         ;
    2.77 +PAGE_FAULT_STUB(page_fault, do_page_fault)
    2.78 +PAGE_FAULT_STUB(safe_page_fault, do_safe_page_fault)
    2.79  
    2.80  ENTRY(machine_check)
    2.81  	pushl $0
     3.1 --- a/xenolinux-2.4.24-sparse/arch/xeno/kernel/traps.c	Tue Feb 17 22:47:33 2004 +0000
     3.2 +++ b/xenolinux-2.4.24-sparse/arch/xeno/kernel/traps.c	Wed Feb 18 11:52:29 2004 +0000
     3.3 @@ -59,6 +59,7 @@ asmlinkage void segment_not_present(void
     3.4  asmlinkage void stack_segment(void);
     3.5  asmlinkage void general_protection(void);
     3.6  asmlinkage void page_fault(void);
     3.7 +asmlinkage void safe_page_fault(void);
     3.8  asmlinkage void coprocessor_error(void);
     3.9  asmlinkage void simd_coprocessor_error(void);
    3.10  asmlinkage void alignment_check(void);
    3.11 @@ -601,7 +602,6 @@ static trap_info_t trap_table[] = {
    3.12            3, __KERNEL_CS, (unsigned long)system_call                 },
    3.13      {  0, 0,           0, 0                           }
    3.14  };
    3.15 -    
    3.16  
    3.17  
    3.18  void __init trap_init(void)
    3.19 @@ -620,3 +620,65 @@ void __init trap_init(void)
    3.20  
    3.21      cpu_init();
    3.22  }
    3.23 +
    3.24 +
    3.25 +/*
    3.26 + * install_safe_pf_handler / install_normal_pf_handler:
    3.27 + * 
    3.28 + * These are used within the failsafe_callback handler in entry.S to avoid
    3.29 + * taking a full page fault when reloading FS and GS. This is because FS and 
    3.30 + * GS could be invalid at pretty much any point while Xenolinux executes (we 
    3.31 + * don't set them to safe values on entry to the kernel). At *any* point Xen 
    3.32 + * may be entered due to a hardware interrupt --- on exit from Xen an invalid 
    3.33 + * FS/GS will cause our failsafe_callback to be executed. This could occur, 
    3.34 + * for example, while the mmmu_update_queue is in an inconsistent state. This
    3.35 + * is disastrous because the normal page-fault handler touches the update
    3.36 + * queue!
    3.37 + * 
    3.38 + * Fortunately, within the failsafe handler it is safe to force DS/ES/FS/GS
    3.39 + * to zero if they cannot be reloaded -- at this point executing a normal
    3.40 + * page fault would not change this effect. The safe page-fault handler
    3.41 + * ensures this end result (blow away the selector value) without the dangers
    3.42 + * of the normal page-fault handler.
    3.43 + * 
    3.44 + * NB. Perhaps this can all go away after we have implemented writeable
    3.45 + * page tables. :-)
    3.46 + */
    3.47 +
    3.48 +asmlinkage void do_safe_page_fault(struct pt_regs *regs, 
    3.49 +                                   unsigned long error_code,
    3.50 +                                   unsigned long address)
    3.51 +{
    3.52 +    unsigned long fixup;
    3.53 +
    3.54 +    if ( (fixup = search_exception_table(regs->eip)) != 0 )
    3.55 +    {
    3.56 +        regs->eip = fixup;
    3.57 +        return;
    3.58 +    }
    3.59 +
    3.60 +    die("Unhandleable 'safe' page fault!", regs, error_code);
    3.61 +}
    3.62 +
    3.63 +unsigned long install_safe_pf_handler(void)
    3.64 +{
    3.65 +    static trap_info_t safe_pf[] = { 
    3.66 +        { 14, 0, __KERNEL_CS, (unsigned long)safe_page_fault },
    3.67 +        {  0, 0,           0, 0                              }
    3.68 +    };
    3.69 +    unsigned long flags;
    3.70 +    local_irq_save(flags);
    3.71 +    HYPERVISOR_set_trap_table(safe_pf);
    3.72 +    return flags; /* This is returned in %%eax */
    3.73 +}
    3.74 +
    3.75 +__attribute__((regparm(3))) /* This function take its arg in %%eax */
    3.76 +void install_normal_pf_handler(unsigned long flags)
    3.77 +{
    3.78 +    static trap_info_t normal_pf[] = { 
    3.79 +        { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
    3.80 +        {  0, 0,           0, 0                         }
    3.81 +    };
    3.82 +    HYPERVISOR_set_trap_table(normal_pf);
    3.83 +    local_irq_restore(flags);
    3.84 +}
     4.1 --- a/xenolinux-2.4.24-sparse/arch/xeno/mm/hypervisor.c	Tue Feb 17 22:47:33 2004 +0000
     4.2 +++ b/xenolinux-2.4.24-sparse/arch/xeno/mm/hypervisor.c	Wed Feb 18 11:52:29 2004 +0000
     4.3 @@ -86,8 +86,9 @@ static void DEBUG_disallow_pt_read(unsig
     4.4  void MULTICALL_flush_page_update_queue(void)
     4.5  {
     4.6      unsigned long flags;
     4.7 +    unsigned int _idx;
     4.8      spin_lock_irqsave(&update_lock, flags);
     4.9 -    if ( idx != 0 ) 
    4.10 +    if ( (_idx = idx) != 0 ) 
    4.11      {
    4.12  #if MMU_UPDATE_DEBUG > 1
    4.13          printk("Flushing %d entries from pt update queue\n", idx);
    4.14 @@ -95,24 +96,27 @@ void MULTICALL_flush_page_update_queue(v
    4.15  #if MMU_UPDATE_DEBUG > 0
    4.16          DEBUG_allow_pt_reads();
    4.17  #endif
    4.18 +        idx = 0;
    4.19 +        wmb(); /* Make sure index is cleared first to avoid double updates. */
    4.20          queue_multicall2(__HYPERVISOR_mmu_update, 
    4.21                           (unsigned long)update_queue, 
    4.22 -                         idx);
    4.23 -        idx = 0;
    4.24 +                         _idx);
    4.25      }
    4.26      spin_unlock_irqrestore(&update_lock, flags);
    4.27  }
    4.28  
    4.29  static inline void __flush_page_update_queue(void)
    4.30  {
    4.31 +    unsigned int _idx = idx;
    4.32  #if MMU_UPDATE_DEBUG > 1
    4.33      printk("Flushing %d entries from pt update queue\n", idx);
    4.34  #endif
    4.35  #if MMU_UPDATE_DEBUG > 0
    4.36      DEBUG_allow_pt_reads();
    4.37  #endif
    4.38 -    HYPERVISOR_mmu_update(update_queue, idx);
    4.39      idx = 0;
    4.40 +    wmb(); /* Make sure index is cleared first to avoid double updates. */
    4.41 +    HYPERVISOR_mmu_update(update_queue, _idx);
    4.42  }
    4.43  
    4.44  void _flush_page_update_queue(void)
     5.1 --- a/xenolinux-2.4.24-sparse/include/asm-xeno/hypervisor.h	Tue Feb 17 22:47:33 2004 +0000
     5.2 +++ b/xenolinux-2.4.24-sparse/include/asm-xeno/hypervisor.h	Wed Feb 18 11:52:29 2004 +0000
     5.3 @@ -169,7 +169,11 @@ static inline int HYPERVISOR_mmu_update(
     5.4          "b" (req), "c" (count) : "memory" );
     5.5  
     5.6      if ( unlikely(ret < 0) )
     5.7 +    {
     5.8 +        extern void show_trace(unsigned long *);
     5.9 +        show_trace(NULL);
    5.10          panic("Failed mmu update: %p, %d", req, count);
    5.11 +    }
    5.12  
    5.13      return ret;
    5.14  }