source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/flushtlb.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 3.0 KB
Line 
1/******************************************************************************
2 * flushtlb.c
3 *
4 * TLB flushes are timestamped using a global virtual 'clock' which ticks
5 * on any TLB flush on any processor.
6 *
7 * Copyright (c) 2003-2006, K A Fraser
8 */
9
10#include <xen/config.h>
11#include <xen/sched.h>
12#include <xen/softirq.h>
13#include <asm/flushtlb.h>
14#include <asm/page.h>
15
16/* Debug builds: Wrap frequently to stress-test the wrap logic. */
17#ifdef NDEBUG
18#define WRAP_MASK (0xFFFFFFFFU)
19#else
20#define WRAP_MASK (0x000003FFU)
21#endif
22
23u32 tlbflush_clock = 1U;
24DEFINE_PER_CPU(u32, tlbflush_time);
25
26/*
27 * pre_flush(): Increment the virtual TLB-flush clock. Returns new clock value.
28 *
29 * This must happen *before* we flush the TLB. If we do it after, we race other
30 * CPUs invalidating PTEs. For example, a page invalidated after the flush
31 * might get the old timestamp, but this CPU can speculatively fetch the
32 * mapping into its TLB after the flush but before inc'ing the clock.
33 */
34static u32 pre_flush(void)
35{
36    u32 t, t1, t2;
37
38    t = tlbflush_clock;
39    do {
40        t1 = t2 = t;
41        /* Clock wrapped: someone else is leading a global TLB shootdown. */
42        if ( unlikely(t1 == 0) )
43            goto skip_clocktick;
44        t2 = (t + 1) & WRAP_MASK;
45    }
46    while ( unlikely((t = cmpxchg(&tlbflush_clock, t1, t2)) != t1) );
47
48    /* Clock wrapped: we will lead a global TLB shootdown. */
49    if ( unlikely(t2 == 0) )
50        raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ);
51
52 skip_clocktick:
53    return t2;
54}
55
56/*
57 * post_flush(): Update this CPU's timestamp with specified clock value.
58 *
59 * Note that this happens *after* flushing the TLB, as otherwise we can race a
60 * NEED_FLUSH() test on another CPU. (e.g., other CPU sees the updated CPU
61 * stamp and so does not force a synchronous TLB flush, but the flush in this
62 * function hasn't yet occurred and so the TLB might be stale). The ordering
63 * would only actually matter if this function were interruptible, and
64 * something that abuses the stale mapping could exist in an interrupt
65 * handler. In fact neither of these is the case, so really we are being ultra
66 * paranoid.
67 */
68static void post_flush(u32 t)
69{
70    this_cpu(tlbflush_time) = t;
71}
72
73void write_cr3(unsigned long cr3)
74{
75    unsigned long flags;
76    u32 t;
77
78    /* This non-reentrant function is sometimes called in interrupt context. */
79    local_irq_save(flags);
80
81    t = pre_flush();
82
83#ifdef USER_MAPPINGS_ARE_GLOBAL
84    __pge_off();
85    __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
86    __pge_on();
87#else
88    __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (cr3) : "memory" );
89#endif
90
91    post_flush(t);
92
93    local_irq_restore(flags);
94}
95
96void local_flush_tlb(void)
97{
98    unsigned long flags;
99    u32 t;
100
101    /* This non-reentrant function is sometimes called in interrupt context. */
102    local_irq_save(flags);
103
104    t = pre_flush();
105
106#ifdef USER_MAPPINGS_ARE_GLOBAL
107    __pge_off();
108    __pge_on();
109#else
110    __asm__ __volatile__ ( "mov %0, %%cr3" : : "r" (read_cr3()) : "memory" );
111#endif
112
113    post_flush(t);
114
115    local_irq_restore(flags);
116}
Note: See TracBrowser for help on using the repository browser.