debuggers.hg

view xen/include/asm-x86/mm.h @ 3632:fec8b1778268

bitkeeper revision 1.1159.212.60 (41febc4bKKSkh9u-Zes9v2CmBuLZxA)

More bootstrap fixes for x86/64. Next thing to do is sort out the IDT and
get traps.c working; then we can get rid of a bunch of dummy labels from
end of boot/x86_64.S. We're also going to need some kind of entry.S before
we can safely enable interrupts. Also bear in mind that not all of physical
RAM may be mapped (only first 1GB) and no m2p table is yet allocated or
mapped. Plenty to be done!
author kaf24@viper.(none)
date Mon Jan 31 23:16:27 2005 +0000 (2005-01-31)
parents eef1949801b8
children d55d523078f7
line source
2 #ifndef __ASM_X86_MM_H__
3 #define __ASM_X86_MM_H__
5 #include <xen/config.h>
6 #include <xen/list.h>
7 #include <xen/spinlock.h>
8 #include <xen/perfc.h>
9 #include <xen/sched.h>
11 #include <asm/processor.h>
12 #include <asm/atomic.h>
13 #include <asm/desc.h>
14 #include <asm/flushtlb.h>
15 #include <asm/io.h>
17 #include <public/xen.h>
19 /*
20 * Per-page-frame information.
21 *
22 * Every architecture must ensure the following:
23 * 1. 'struct pfn_info' contains a 'struct list_head list'.
24 * 2. Provide a PFN_ORDER() macro for accessing the order of a free page.
25 */
26 #define PFN_ORDER(_pfn) ((_pfn)->u.free.order)
28 struct pfn_info
29 {
30 /* Each frame can be threaded onto a doubly-linked list. */
31 struct list_head list;
33 /* Reference count and various PGC_xxx flags and fields. */
34 u32 count_info;
36 /* Context-dependent fields follow... */
37 union {
39 /* Page is in use: ((count_info & PGC_count_mask) != 0). */
40 struct {
41 /* Owner of this page (NULL if page is anonymous). */
42 struct domain *domain;
43 /* Type reference count and various PGT_xxx flags and fields. */
44 u32 type_info;
45 } inuse;
47 /* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
48 struct {
49 /* Mask of possibly-tainted TLBs. */
50 unsigned long cpu_mask;
51 /* Order-size of the free chunk this page is the head of. */
52 u8 order;
53 } free;
55 } u;
57 /* Timestamp from 'TLB clock', used to reduce need for safety flushes. */
58 u32 tlbflush_timestamp;
59 };
61 /* The following page types are MUTUALLY EXCLUSIVE. */
62 #define PGT_none (0<<29) /* no special uses of this page */
63 #define PGT_l1_page_table (1<<29) /* using this page as an L1 page table? */
64 #define PGT_l2_page_table (2<<29) /* using this page as an L2 page table? */
65 #define PGT_l3_page_table (3<<29) /* using this page as an L3 page table? */
66 #define PGT_l4_page_table (4<<29) /* using this page as an L4 page table? */
67 #define PGT_gdt_page (5<<29) /* using this page in a GDT? */
68 #define PGT_ldt_page (6<<29) /* using this page in an LDT? */
69 #define PGT_writable_page (7<<29) /* has writable mappings of this page? */
70 #define PGT_type_mask (7<<29) /* Bits 29-31. */
71 /* Has this page been validated for use as its current type? */
72 #define _PGT_validated 28
73 #define PGT_validated (1U<<_PGT_validated)
74 /* Owning guest has pinned this page to its current type? */
75 #define _PGT_pinned 27
76 #define PGT_pinned (1U<<_PGT_pinned)
77 /* The 10 most significant bits of virt address if this is a page table. */
78 #define PGT_va_shift 17
79 #define PGT_va_mask (((1U<<10)-1)<<PGT_va_shift)
80 /* Is the back pointer still mutable (i.e. not fixed yet)? */
81 #define PGT_va_mutable (((1U<<10)-1)<<PGT_va_shift)
82 /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
83 #define PGT_va_unknown (((1U<<10)-2)<<PGT_va_shift)
84 /* 17-bit count of uses of this frame as its current type. */
85 #define PGT_count_mask ((1U<<17)-1)
87 /* Cleared when the owning guest 'frees' this page. */
88 #define _PGC_allocated 31
89 #define PGC_allocated (1U<<_PGC_allocated)
90 /* 31-bit count of references to this frame. */
91 #define PGC_count_mask ((1U<<31)-1)
93 /* We trust the slab allocator in slab.c, and our use of it. */
94 #define PageSlab(page) (1)
95 #define PageSetSlab(page) ((void)0)
96 #define PageClearSlab(page) ((void)0)
98 #define IS_XEN_HEAP_FRAME(_pfn) (page_to_phys(_pfn) < xenheap_phys_end)
100 #define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
101 do { \
102 (_pfn)->u.inuse.domain = (_dom); \
103 /* The incremented type count is intended to pin to 'writable'. */ \
104 (_pfn)->u.inuse.type_info = PGT_writable_page | PGT_validated | 1; \
105 wmb(); /* install valid domain ptr before updating refcnt. */ \
106 spin_lock(&(_dom)->page_alloc_lock); \
107 /* _dom holds an allocation reference */ \
108 ASSERT((_pfn)->count_info == 0); \
109 (_pfn)->count_info |= PGC_allocated | 1; \
110 if ( unlikely((_dom)->xenheap_pages++ == 0) ) \
111 get_knownalive_domain(_dom); \
112 list_add_tail(&(_pfn)->list, &(_dom)->xenpage_list); \
113 spin_unlock(&(_dom)->page_alloc_lock); \
114 } while ( 0 )
116 #define INVALID_P2M_ENTRY (~0UL)
118 extern struct pfn_info *frame_table;
119 extern unsigned long frame_table_size;
120 extern unsigned long max_page;
121 void init_frametable(void);
123 int alloc_page_type(struct pfn_info *page, unsigned int type);
124 void free_page_type(struct pfn_info *page, unsigned int type);
126 static inline void put_page(struct pfn_info *page)
127 {
128 u32 nx, x, y = page->count_info;
130 do {
131 x = y;
132 nx = x - 1;
133 }
134 while ( unlikely((y = cmpxchg(&page->count_info, x, nx)) != x) );
136 if ( unlikely((nx & PGC_count_mask) == 0) )
137 free_domheap_page(page);
138 }
141 static inline int get_page(struct pfn_info *page,
142 struct domain *domain)
143 {
144 u32 x, nx, y = page->count_info;
145 struct domain *d, *nd = page->u.inuse.domain;
147 do {
148 x = y;
149 nx = x + 1;
150 d = nd;
151 if ( unlikely((x & PGC_count_mask) == 0) || /* Not allocated? */
152 unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */
153 unlikely(d != domain) ) /* Wrong owner? */
154 {
155 DPRINTK("Error pfn %08lx: ed=%p, sd=%p, caf=%08x, taf=%08x\n",
156 page_to_pfn(page), domain, d,
157 x, page->u.inuse.type_info);
158 return 0;
159 }
160 __asm__ __volatile__(
161 LOCK_PREFIX "cmpxchg8b %3"
162 : "=d" (nd), "=a" (y), "=c" (d),
163 "=m" (*(volatile u64 *)(&page->count_info))
164 : "0" (d), "1" (x), "c" (d), "b" (nx) );
165 }
166 while ( unlikely(nd != d) || unlikely(y != x) );
168 return 1;
169 }
171 void put_page_type(struct pfn_info *page);
172 int get_page_type(struct pfn_info *page, u32 type);
174 static inline void put_page_and_type(struct pfn_info *page)
175 {
176 put_page_type(page);
177 put_page(page);
178 }
181 static inline int get_page_and_type(struct pfn_info *page,
182 struct domain *domain,
183 u32 type)
184 {
185 int rc = get_page(page, domain);
187 if ( likely(rc) && unlikely(!get_page_type(page, type)) )
188 {
189 put_page(page);
190 rc = 0;
191 }
193 return rc;
194 }
196 #define ASSERT_PAGE_IS_TYPE(_p, _t) \
197 ASSERT(((_p)->u.inuse.type_info & PGT_type_mask) == (_t)); \
198 ASSERT(((_p)->u.inuse.type_info & PGT_count_mask) != 0)
199 #define ASSERT_PAGE_IS_DOMAIN(_p, _d) \
200 ASSERT(((_p)->count_info & PGC_count_mask) != 0); \
201 ASSERT((_p)->u.inuse.domain == (_d))
203 int check_descriptor(unsigned long *d);
205 /*
206 * Use currently-executing domain's pagetables on the specified CPUs.
207 * i.e., stop borrowing someone else's tables if you are the idle domain.
208 */
209 void synchronise_pagetables(unsigned long cpu_mask);
211 /*
212 * The MPT (machine->physical mapping table) is an array of word-sized
213 * values, indexed on machine frame number. It is expected that guest OSes
214 * will use it to store a "physical" frame number to give the appearance of
215 * contiguous (or near contiguous) physical memory.
216 */
217 #undef machine_to_phys_mapping
219 /*
220 * The phys_to_machine_mapping is the reversed mapping of MPT for full
221 * virtualization.
222 */
223 #undef phys_to_machine_mapping
225 /* Don't call virt_to_phys on this: it isn't direct mapped. Using
226 m2p_start_mfn instead. */
227 #define machine_to_phys_mapping ((unsigned long *)RDWR_MPT_VIRT_START)
228 extern unsigned long m2p_start_mfn;
229 #define phys_to_machine_mapping ((unsigned long *)PERDOMAIN_VIRT_START)
231 #define set_machinetophys(_mfn, _pfn) machine_to_phys_mapping[(_mfn)] = (_pfn)
233 #define DEFAULT_GDT_ENTRIES (LAST_RESERVED_GDT_ENTRY+1)
234 #define DEFAULT_GDT_ADDRESS ((unsigned long)gdt_table)
236 #ifdef MEMORY_GUARD
237 void *memguard_init(void *heap_start);
238 void memguard_guard_range(void *p, unsigned long l);
239 void memguard_unguard_range(void *p, unsigned long l);
240 #else
241 #define memguard_init(_s) (_s)
242 #define memguard_guard_range(_p,_l) ((void)0)
243 #define memguard_unguard_range(_p,_l) ((void)0)
244 #endif
247 typedef struct {
248 void (*enable)(struct domain *);
249 void (*disable)(struct domain *);
250 } vm_assist_info_t;
251 extern vm_assist_info_t vm_assist_info[];
254 /* Writable Pagetables */
255 typedef struct {
256 /* Linear address where the guest is updating the p.t. page. */
257 unsigned long l1va;
258 /* Copy of the p.t. page, taken before guest is given write access. */
259 l1_pgentry_t *page;
260 /* A temporary Xen mapping of the actual p.t. page. */
261 l1_pgentry_t *pl1e;
262 /* Index in L2 page table where this L1 p.t. is always hooked. */
263 unsigned int l2_idx; /* NB. Only used for PTWR_PT_ACTIVE. */
264 } ptwr_ptinfo_t;
266 typedef struct {
267 ptwr_ptinfo_t ptinfo[2];
268 } __cacheline_aligned ptwr_info_t;
270 extern ptwr_info_t ptwr_info[];
272 #define PTWR_PT_ACTIVE 0
273 #define PTWR_PT_INACTIVE 1
275 #define PTWR_CLEANUP_ACTIVE 1
276 #define PTWR_CLEANUP_INACTIVE 2
278 void ptwr_flush(const int);
279 int ptwr_do_page_fault(unsigned long);
281 int new_guest_cr3(unsigned long pfn);
283 #define __cleanup_writable_pagetable(_what) \
284 do { \
285 int cpu = smp_processor_id(); \
286 if ((_what) & PTWR_CLEANUP_ACTIVE) \
287 if (ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va) \
288 ptwr_flush(PTWR_PT_ACTIVE); \
289 if ((_what) & PTWR_CLEANUP_INACTIVE) \
290 if (ptwr_info[cpu].ptinfo[PTWR_PT_INACTIVE].l1va) \
291 ptwr_flush(PTWR_PT_INACTIVE); \
292 } while ( 0 )
294 #define cleanup_writable_pagetable(_d) \
295 do { \
296 if ( unlikely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) \
297 __cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | \
298 PTWR_CLEANUP_INACTIVE); \
299 } while ( 0 )
301 #ifndef NDEBUG
302 void audit_domain(struct domain *d);
303 void audit_domains(void);
304 #else
305 #define audit_domain(_d) ((void)0)
306 #define audit_domains() ((void)0)
307 #endif
309 void propagate_page_fault(unsigned long addr, u16 error_code);
311 #endif /* __ASM_X86_MM_H__ */