1 /*
2 *
3 * Copyright (c) 2004 Christian Limpach.
4 * Copyright (c) 2004-2006,2008 Kip Macy
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Christian Limpach.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/8.2/sys/i386/xen/xen_machdep.c 216602 2010-12-20 20:39:49Z cperciva $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/ktr.h>
40 #include <sys/lock.h>
41 #include <sys/mount.h>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44 #include <sys/kernel.h>
45 #include <sys/reboot.h>
46 #include <sys/sysproto.h>
47
48 #include <machine/xen/xen-os.h>
49
50 #include <vm/vm.h>
51 #include <vm/pmap.h>
52 #include <machine/segments.h>
53 #include <machine/pcb.h>
54 #include <machine/stdarg.h>
55 #include <machine/vmparam.h>
56 #include <machine/cpu.h>
57 #include <machine/intr_machdep.h>
58 #include <machine/md_var.h>
59 #include <machine/asmacros.h>
60
61
62
63 #include <xen/hypervisor.h>
64 #include <machine/xen/xenvar.h>
65 #include <machine/xen/xenfunc.h>
66 #include <machine/xen/xenpmap.h>
67 #include <machine/xen/xenfunc.h>
68 #include <xen/interface/memory.h>
69 #include <machine/xen/features.h>
70 #ifdef SMP
71 #include <machine/privatespace.h>
72 #endif
73
74
75 #include <vm/vm_page.h>
76
77
78 #define IDTVEC(name) __CONCAT(X,name)
79
80 extern inthand_t
81 IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
82 IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
83 IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
84 IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
85 IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall);
86
87
88 int xendebug_flags;
89 start_info_t *xen_start_info;
90 shared_info_t *HYPERVISOR_shared_info;
91 xen_pfn_t *xen_machine_phys = machine_to_phys_mapping;
92 xen_pfn_t *xen_phys_machine;
93 xen_pfn_t *xen_pfn_to_mfn_frame_list[16];
94 xen_pfn_t *xen_pfn_to_mfn_frame_list_list;
95 int preemptable, init_first;
96 extern unsigned int avail_space;
97
98 void ni_cli(void);
99 void ni_sti(void);
100
101
102 void
103 ni_cli(void)
104 {
105 CTR0(KTR_SPARE2, "ni_cli disabling interrupts");
106 __asm__("pushl %edx;"
107 "pushl %eax;"
108 );
109 __cli();
110 __asm__("popl %eax;"
111 "popl %edx;"
112 );
113 }
114
115
116 void
117 ni_sti(void)
118 {
119 __asm__("pushl %edx;"
120 "pushl %esi;"
121 "pushl %eax;"
122 );
123 __sti();
124 __asm__("popl %eax;"
125 "popl %esi;"
126 "popl %edx;"
127 );
128 }
129
130 /*
131 * Modify the cmd_line by converting ',' to NULLs so that it is in a format
132 * suitable for the static env vars.
133 */
134 char *
135 xen_setbootenv(char *cmd_line)
136 {
137 char *cmd_line_next;
138
139 /* Skip leading spaces */
140 for (; *cmd_line == ' '; cmd_line++);
141
142 printk("xen_setbootenv(): cmd_line='%s'\n", cmd_line);
143
144 for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;);
145 return cmd_line;
146 }
147
148 static struct
149 {
150 const char *ev;
151 int mask;
152 } howto_names[] = {
153 {"boot_askname", RB_ASKNAME},
154 {"boot_single", RB_SINGLE},
155 {"boot_nosync", RB_NOSYNC},
156 {"boot_halt", RB_ASKNAME},
157 {"boot_serial", RB_SERIAL},
158 {"boot_cdrom", RB_CDROM},
159 {"boot_gdb", RB_GDB},
160 {"boot_gdb_pause", RB_RESERVED1},
161 {"boot_verbose", RB_VERBOSE},
162 {"boot_multicons", RB_MULTIPLE},
163 {NULL, 0}
164 };
165
166 int
167 xen_boothowto(char *envp)
168 {
169 int i, howto = 0;
170
171 /* get equivalents from the environment */
172 for (i = 0; howto_names[i].ev != NULL; i++)
173 if (getenv(howto_names[i].ev) != NULL)
174 howto |= howto_names[i].mask;
175 return howto;
176 }
177
178 #define PRINTK_BUFSIZE 1024
179 void
180 printk(const char *fmt, ...)
181 {
182 __va_list ap;
183 int retval;
184 static char buf[PRINTK_BUFSIZE];
185
186 va_start(ap, fmt);
187 retval = vsnprintf(buf, PRINTK_BUFSIZE - 1, fmt, ap);
188 va_end(ap);
189 buf[retval] = 0;
190 (void)HYPERVISOR_console_write(buf, retval);
191 }
192
193
194 #define XPQUEUE_SIZE 128
195
196 struct mmu_log {
197 char *file;
198 int line;
199 };
200
201 #ifdef SMP
202 /* per-cpu queues and indices */
203 #ifdef INVARIANTS
204 static struct mmu_log xpq_queue_log[MAX_VIRT_CPUS][XPQUEUE_SIZE];
205 #endif
206
207 static int xpq_idx[MAX_VIRT_CPUS];
208 static mmu_update_t xpq_queue[MAX_VIRT_CPUS][XPQUEUE_SIZE];
209
210 #define XPQ_QUEUE_LOG xpq_queue_log[vcpu]
211 #define XPQ_QUEUE xpq_queue[vcpu]
212 #define XPQ_IDX xpq_idx[vcpu]
213 #define SET_VCPU() int vcpu = smp_processor_id()
214 #else
215
216 static mmu_update_t xpq_queue[XPQUEUE_SIZE];
217 static struct mmu_log xpq_queue_log[XPQUEUE_SIZE];
218 static int xpq_idx = 0;
219
220 #define XPQ_QUEUE_LOG xpq_queue_log
221 #define XPQ_QUEUE xpq_queue
222 #define XPQ_IDX xpq_idx
223 #define SET_VCPU()
224 #endif /* !SMP */
225
226 #define XPQ_IDX_INC atomic_add_int(&XPQ_IDX, 1);
227
228 #if 0
229 static void
230 xen_dump_queue(void)
231 {
232 int _xpq_idx = XPQ_IDX;
233 int i;
234
235 if (_xpq_idx <= 1)
236 return;
237
238 printk("xen_dump_queue(): %u entries\n", _xpq_idx);
239 for (i = 0; i < _xpq_idx; i++) {
240 printk(" val: %llx ptr: %llx\n", XPQ_QUEUE[i].val, XPQ_QUEUE[i].ptr);
241 }
242 }
243 #endif
244
245
246 static __inline void
247 _xen_flush_queue(void)
248 {
249 SET_VCPU();
250 int _xpq_idx = XPQ_IDX;
251 int error, i;
252 /* window of vulnerability here? */
253
254 if (__predict_true(gdtset))
255 critical_enter();
256 XPQ_IDX = 0;
257 /* Make sure index is cleared first to avoid double updates. */
258 error = HYPERVISOR_mmu_update((mmu_update_t *)&XPQ_QUEUE,
259 _xpq_idx, NULL, DOMID_SELF);
260
261 #if 0
262 if (__predict_true(gdtset))
263 for (i = _xpq_idx; i > 0;) {
264 if (i >= 3) {
265 CTR6(KTR_PMAP, "mmu:val: %lx ptr: %lx val: %lx "
266 "ptr: %lx val: %lx ptr: %lx",
267 (XPQ_QUEUE[i-1].val & 0xffffffff),
268 (XPQ_QUEUE[i-1].ptr & 0xffffffff),
269 (XPQ_QUEUE[i-2].val & 0xffffffff),
270 (XPQ_QUEUE[i-2].ptr & 0xffffffff),
271 (XPQ_QUEUE[i-3].val & 0xffffffff),
272 (XPQ_QUEUE[i-3].ptr & 0xffffffff));
273 i -= 3;
274 } else if (i == 2) {
275 CTR4(KTR_PMAP, "mmu: val: %lx ptr: %lx val: %lx ptr: %lx",
276 (XPQ_QUEUE[i-1].val & 0xffffffff),
277 (XPQ_QUEUE[i-1].ptr & 0xffffffff),
278 (XPQ_QUEUE[i-2].val & 0xffffffff),
279 (XPQ_QUEUE[i-2].ptr & 0xffffffff));
280 i = 0;
281 } else {
282 CTR2(KTR_PMAP, "mmu: val: %lx ptr: %lx",
283 (XPQ_QUEUE[i-1].val & 0xffffffff),
284 (XPQ_QUEUE[i-1].ptr & 0xffffffff));
285 i = 0;
286 }
287 }
288 #endif
289 if (__predict_true(gdtset))
290 critical_exit();
291 if (__predict_false(error < 0)) {
292 for (i = 0; i < _xpq_idx; i++)
293 printf("val: %llx ptr: %llx\n",
294 XPQ_QUEUE[i].val, XPQ_QUEUE[i].ptr);
295 panic("Failed to execute MMU updates: %d", error);
296 }
297
298 }
299
300 void
301 xen_flush_queue(void)
302 {
303 SET_VCPU();
304 if (XPQ_IDX != 0) _xen_flush_queue();
305 }
306
307 static __inline void
308 xen_increment_idx(void)
309 {
310 SET_VCPU();
311
312 XPQ_IDX++;
313 if (__predict_false(XPQ_IDX == XPQUEUE_SIZE))
314 xen_flush_queue();
315 }
316
317 void
318 xen_check_queue(void)
319 {
320 #ifdef INVARIANTS
321 SET_VCPU();
322
323 KASSERT(XPQ_IDX == 0, ("pending operations XPQ_IDX=%d", XPQ_IDX));
324 #endif
325 }
326
327 void
328 xen_invlpg(vm_offset_t va)
329 {
330 struct mmuext_op op;
331 op.cmd = MMUEXT_INVLPG_ALL;
332 op.arg1.linear_addr = va & ~PAGE_MASK;
333 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
334 }
335
336 void
337 xen_load_cr3(u_int val)
338 {
339 struct mmuext_op op;
340 #ifdef INVARIANTS
341 SET_VCPU();
342
343 KASSERT(XPQ_IDX == 0, ("pending operations XPQ_IDX=%d", XPQ_IDX));
344 #endif
345 op.cmd = MMUEXT_NEW_BASEPTR;
346 op.arg1.mfn = xpmap_ptom(val) >> PAGE_SHIFT;
347 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
348 }
349
350 #ifdef KTR
351 static __inline u_int
352 rebp(void)
353 {
354 u_int data;
355
356 __asm __volatile("movl 4(%%ebp),%0" : "=r" (data));
357 return (data);
358 }
359 #endif
360
361 u_int
362 read_eflags(void)
363 {
364 vcpu_info_t *_vcpu;
365 u_int eflags;
366
367 eflags = _read_eflags();
368 _vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
369 if (_vcpu->evtchn_upcall_mask)
370 eflags &= ~PSL_I;
371
372 return (eflags);
373 }
374
375 void
376 write_eflags(u_int eflags)
377 {
378 u_int intr;
379
380 CTR2(KTR_SPARE2, "%x xen_restore_flags eflags %x", rebp(), eflags);
381 intr = ((eflags & PSL_I) == 0);
382 __restore_flags(intr);
383 _write_eflags(eflags);
384 }
385
386 void
387 xen_cli(void)
388 {
389 CTR1(KTR_SPARE2, "%x xen_cli disabling interrupts", rebp());
390 __cli();
391 }
392
393 void
394 xen_sti(void)
395 {
396 CTR1(KTR_SPARE2, "%x xen_sti enabling interrupts", rebp());
397 __sti();
398 }
399
400 u_int
401 xen_rcr2(void)
402 {
403
404 return (HYPERVISOR_shared_info->vcpu_info[curcpu].arch.cr2);
405 }
406
407 void
408 _xen_machphys_update(vm_paddr_t mfn, vm_paddr_t pfn, char *file, int line)
409 {
410 SET_VCPU();
411
412 if (__predict_true(gdtset))
413 critical_enter();
414 XPQ_QUEUE[XPQ_IDX].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
415 XPQ_QUEUE[XPQ_IDX].val = pfn;
416 #ifdef INVARIANTS
417 XPQ_QUEUE_LOG[XPQ_IDX].file = file;
418 XPQ_QUEUE_LOG[XPQ_IDX].line = line;
419 #endif
420 xen_increment_idx();
421 if (__predict_true(gdtset))
422 critical_exit();
423 }
424
425 void
426 _xen_queue_pt_update(vm_paddr_t ptr, vm_paddr_t val, char *file, int line)
427 {
428 SET_VCPU();
429
430 if (__predict_true(gdtset))
431 mtx_assert(&vm_page_queue_mtx, MA_OWNED);
432
433 KASSERT((ptr & 7) == 0, ("misaligned update"));
434
435 if (__predict_true(gdtset))
436 critical_enter();
437
438 XPQ_QUEUE[XPQ_IDX].ptr = ((uint64_t)ptr) | MMU_NORMAL_PT_UPDATE;
439 XPQ_QUEUE[XPQ_IDX].val = (uint64_t)val;
440 #ifdef INVARIANTS
441 XPQ_QUEUE_LOG[XPQ_IDX].file = file;
442 XPQ_QUEUE_LOG[XPQ_IDX].line = line;
443 #endif
444 xen_increment_idx();
445 if (__predict_true(gdtset))
446 critical_exit();
447 }
448
449 void
450 xen_pgdpt_pin(vm_paddr_t ma)
451 {
452 struct mmuext_op op;
453 op.cmd = MMUEXT_PIN_L3_TABLE;
454 op.arg1.mfn = ma >> PAGE_SHIFT;
455 xen_flush_queue();
456 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
457 }
458
459 void
460 xen_pgd_pin(vm_paddr_t ma)
461 {
462 struct mmuext_op op;
463 op.cmd = MMUEXT_PIN_L2_TABLE;
464 op.arg1.mfn = ma >> PAGE_SHIFT;
465 xen_flush_queue();
466 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
467 }
468
469 void
470 xen_pgd_unpin(vm_paddr_t ma)
471 {
472 struct mmuext_op op;
473 op.cmd = MMUEXT_UNPIN_TABLE;
474 op.arg1.mfn = ma >> PAGE_SHIFT;
475 xen_flush_queue();
476 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
477 }
478
479 void
480 xen_pt_pin(vm_paddr_t ma)
481 {
482 struct mmuext_op op;
483 op.cmd = MMUEXT_PIN_L1_TABLE;
484 op.arg1.mfn = ma >> PAGE_SHIFT;
485 xen_flush_queue();
486 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
487 }
488
489 void
490 xen_pt_unpin(vm_paddr_t ma)
491 {
492 struct mmuext_op op;
493 op.cmd = MMUEXT_UNPIN_TABLE;
494 op.arg1.mfn = ma >> PAGE_SHIFT;
495 xen_flush_queue();
496 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
497 }
498
499 void
500 xen_set_ldt(vm_paddr_t ptr, unsigned long len)
501 {
502 struct mmuext_op op;
503 op.cmd = MMUEXT_SET_LDT;
504 op.arg1.linear_addr = ptr;
505 op.arg2.nr_ents = len;
506 xen_flush_queue();
507 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
508 }
509
510 void xen_tlb_flush(void)
511 {
512 struct mmuext_op op;
513 op.cmd = MMUEXT_TLB_FLUSH_LOCAL;
514 xen_flush_queue();
515 PANIC_IF(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
516 }
517
518 void
519 xen_update_descriptor(union descriptor *table, union descriptor *entry)
520 {
521 vm_paddr_t pa;
522 pt_entry_t *ptp;
523
524 ptp = vtopte((vm_offset_t)table);
525 pa = (*ptp & PG_FRAME) | ((vm_offset_t)table & PAGE_MASK);
526 if (HYPERVISOR_update_descriptor(pa, *(uint64_t *)entry))
527 panic("HYPERVISOR_update_descriptor failed\n");
528 }
529
530
531 #if 0
532 /*
533 * Bitmap is indexed by page number. If bit is set, the page is part of a
534 * xen_create_contiguous_region() area of memory.
535 */
536 unsigned long *contiguous_bitmap;
537
538 static void
539 contiguous_bitmap_set(unsigned long first_page, unsigned long nr_pages)
540 {
541 unsigned long start_off, end_off, curr_idx, end_idx;
542
543 curr_idx = first_page / BITS_PER_LONG;
544 start_off = first_page & (BITS_PER_LONG-1);
545 end_idx = (first_page + nr_pages) / BITS_PER_LONG;
546 end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
547
548 if (curr_idx == end_idx) {
549 contiguous_bitmap[curr_idx] |=
550 ((1UL<<end_off)-1) & -(1UL<<start_off);
551 } else {
552 contiguous_bitmap[curr_idx] |= -(1UL<<start_off);
553 while ( ++curr_idx < end_idx )
554 contiguous_bitmap[curr_idx] = ~0UL;
555 contiguous_bitmap[curr_idx] |= (1UL<<end_off)-1;
556 }
557 }
558
559 static void
560 contiguous_bitmap_clear(unsigned long first_page, unsigned long nr_pages)
561 {
562 unsigned long start_off, end_off, curr_idx, end_idx;
563
564 curr_idx = first_page / BITS_PER_LONG;
565 start_off = first_page & (BITS_PER_LONG-1);
566 end_idx = (first_page + nr_pages) / BITS_PER_LONG;
567 end_off = (first_page + nr_pages) & (BITS_PER_LONG-1);
568
569 if (curr_idx == end_idx) {
570 contiguous_bitmap[curr_idx] &=
571 -(1UL<<end_off) | ((1UL<<start_off)-1);
572 } else {
573 contiguous_bitmap[curr_idx] &= (1UL<<start_off)-1;
574 while ( ++curr_idx != end_idx )
575 contiguous_bitmap[curr_idx] = 0;
576 contiguous_bitmap[curr_idx] &= -(1UL<<end_off);
577 }
578 }
579 #endif
580
581 /* Ensure multi-page extents are contiguous in machine memory. */
582 int
583 xen_create_contiguous_region(vm_page_t pages, int npages)
584 {
585 unsigned long mfn, i, flags;
586 int order;
587 struct xen_memory_reservation reservation = {
588 .nr_extents = 1,
589 .extent_order = 0,
590 .domid = DOMID_SELF
591 };
592 set_xen_guest_handle(reservation.extent_start, &mfn);
593
594 balloon_lock(flags);
595
596 /* can currently only handle power of two allocation */
597 PANIC_IF(ffs(npages) != fls(npages));
598
599 /* 0. determine order */
600 order = (ffs(npages) == fls(npages)) ? fls(npages) - 1 : fls(npages);
601
602 /* 1. give away machine pages. */
603 for (i = 0; i < (1 << order); i++) {
604 int pfn;
605 pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
606 mfn = PFNTOMFN(pfn);
607 PFNTOMFN(pfn) = INVALID_P2M_ENTRY;
608 PANIC_IF(HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation) != 1);
609 }
610
611
612 /* 2. Get a new contiguous memory extent. */
613 reservation.extent_order = order;
614 /* xenlinux hardcodes this because of aacraid - maybe set to 0 if we're not
615 * running with a broxen driver XXXEN
616 */
617 reservation.address_bits = 31;
618 if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation) != 1)
619 goto fail;
620
621 /* 3. Map the new extent in place of old pages. */
622 for (i = 0; i < (1 << order); i++) {
623 int pfn;
624 pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
625 xen_machphys_update(mfn+i, pfn);
626 PFNTOMFN(pfn) = mfn+i;
627 }
628
629 xen_tlb_flush();
630
631 #if 0
632 contiguous_bitmap_set(VM_PAGE_TO_PHYS(&pages[0]) >> PAGE_SHIFT, 1UL << order);
633 #endif
634
635 balloon_unlock(flags);
636
637 return 0;
638
639 fail:
640 reservation.extent_order = 0;
641 reservation.address_bits = 0;
642
643 for (i = 0; i < (1 << order); i++) {
644 int pfn;
645 pfn = VM_PAGE_TO_PHYS(&pages[i]) >> PAGE_SHIFT;
646 PANIC_IF(HYPERVISOR_memory_op(
647 XENMEM_increase_reservation, &reservation) != 1);
648 xen_machphys_update(mfn, pfn);
649 PFNTOMFN(pfn) = mfn;
650 }
651
652 xen_tlb_flush();
653
654 balloon_unlock(flags);
655
656 return ENOMEM;
657 }
658
659 void
660 xen_destroy_contiguous_region(void *addr, int npages)
661 {
662 unsigned long mfn, i, flags, order, pfn0;
663 struct xen_memory_reservation reservation = {
664 .nr_extents = 1,
665 .extent_order = 0,
666 .domid = DOMID_SELF
667 };
668 set_xen_guest_handle(reservation.extent_start, &mfn);
669
670 pfn0 = vtophys(addr) >> PAGE_SHIFT;
671 #if 0
672 scrub_pages(vstart, 1 << order);
673 #endif
674 /* can currently only handle power of two allocation */
675 PANIC_IF(ffs(npages) != fls(npages));
676
677 /* 0. determine order */
678 order = (ffs(npages) == fls(npages)) ? fls(npages) - 1 : fls(npages);
679
680 balloon_lock(flags);
681
682 #if 0
683 contiguous_bitmap_clear(vtophys(addr) >> PAGE_SHIFT, 1UL << order);
684 #endif
685
686 /* 1. Zap current PTEs, giving away the underlying pages. */
687 for (i = 0; i < (1 << order); i++) {
688 int pfn;
689 uint64_t new_val = 0;
690 pfn = vtomach((char *)addr + i*PAGE_SIZE) >> PAGE_SHIFT;
691
692 PANIC_IF(HYPERVISOR_update_va_mapping((vm_offset_t)((char *)addr + (i * PAGE_SIZE)), new_val, 0));
693 PFNTOMFN(pfn) = INVALID_P2M_ENTRY;
694 PANIC_IF(HYPERVISOR_memory_op(
695 XENMEM_decrease_reservation, &reservation) != 1);
696 }
697
698 /* 2. Map new pages in place of old pages. */
699 for (i = 0; i < (1 << order); i++) {
700 int pfn;
701 uint64_t new_val;
702 pfn = pfn0 + i;
703 PANIC_IF(HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation) != 1);
704
705 new_val = mfn << PAGE_SHIFT;
706 PANIC_IF(HYPERVISOR_update_va_mapping((vm_offset_t)addr + (i * PAGE_SIZE),
707 new_val, PG_KERNEL));
708 xen_machphys_update(mfn, pfn);
709 PFNTOMFN(pfn) = mfn;
710 }
711
712 xen_tlb_flush();
713
714 balloon_unlock(flags);
715 }
716
717 extern unsigned long cpu0prvpage;
718 extern unsigned long *SMPpt;
719 extern struct user *proc0uarea;
720 extern vm_offset_t proc0kstack;
721 extern int vm86paddr, vm86phystk;
722 char *bootmem_start, *bootmem_current, *bootmem_end;
723
724 pteinfo_t *pteinfo_list;
725 void initvalues(start_info_t *startinfo);
726
727 struct xenstore_domain_interface;
728 extern struct xenstore_domain_interface *xen_store;
729
730 char *console_page;
731
732 void *
733 bootmem_alloc(unsigned int size)
734 {
735 char *retptr;
736
737 retptr = bootmem_current;
738 PANIC_IF(retptr + size > bootmem_end);
739 bootmem_current += size;
740
741 return retptr;
742 }
743
744 void
745 bootmem_free(void *ptr, unsigned int size)
746 {
747 char *tptr;
748
749 tptr = ptr;
750 PANIC_IF(tptr != bootmem_current - size ||
751 bootmem_current - size < bootmem_start);
752
753 bootmem_current -= size;
754 }
755
756 #if 0
757 static vm_paddr_t
758 xpmap_mtop2(vm_paddr_t mpa)
759 {
760 return ((machine_to_phys_mapping[mpa >> PAGE_SHIFT] << PAGE_SHIFT)
761 ) | (mpa & ~PG_FRAME);
762 }
763
764 static pd_entry_t
765 xpmap_get_bootpde(vm_paddr_t va)
766 {
767
768 return ((pd_entry_t *)xen_start_info->pt_base)[va >> 22];
769 }
770
771 static pd_entry_t
772 xpmap_get_vbootpde(vm_paddr_t va)
773 {
774 pd_entry_t pde;
775
776 pde = xpmap_get_bootpde(va);
777 if ((pde & PG_V) == 0)
778 return (pde & ~PG_FRAME);
779 return (pde & ~PG_FRAME) |
780 (xpmap_mtop2(pde & PG_FRAME) + KERNBASE);
781 }
782
783 static pt_entry_t 8*
784 xpmap_get_bootptep(vm_paddr_t va)
785 {
786 pd_entry_t pde;
787
788 pde = xpmap_get_vbootpde(va);
789 if ((pde & PG_V) == 0)
790 return (void *)-1;
791 #define PT_MASK 0x003ff000 /* page table address bits */
792 return &(((pt_entry_t *)(pde & PG_FRAME))[(va & PT_MASK) >> PAGE_SHIFT]);
793 }
794
795 static pt_entry_t
796 xpmap_get_bootpte(vm_paddr_t va)
797 {
798
799 return xpmap_get_bootptep(va)[0];
800 }
801 #endif
802
803
804 #ifdef ADD_ISA_HOLE
805 static void
806 shift_phys_machine(unsigned long *phys_machine, int nr_pages)
807 {
808
809 unsigned long *tmp_page, *current_page, *next_page;
810 int i;
811
812 tmp_page = bootmem_alloc(PAGE_SIZE);
813 current_page = phys_machine + nr_pages - (PAGE_SIZE/sizeof(unsigned long));
814 next_page = current_page - (PAGE_SIZE/sizeof(unsigned long));
815 bcopy(phys_machine, tmp_page, PAGE_SIZE);
816
817 while (current_page > phys_machine) {
818 /* save next page */
819 bcopy(next_page, tmp_page, PAGE_SIZE);
820 /* shift down page */
821 bcopy(current_page, next_page, PAGE_SIZE);
822 /* finish swap */
823 bcopy(tmp_page, current_page, PAGE_SIZE);
824
825 current_page -= (PAGE_SIZE/sizeof(unsigned long));
826 next_page -= (PAGE_SIZE/sizeof(unsigned long));
827 }
828 bootmem_free(tmp_page, PAGE_SIZE);
829
830 for (i = 0; i < nr_pages; i++) {
831 xen_machphys_update(phys_machine[i], i);
832 }
833 memset(phys_machine, INVALID_P2M_ENTRY, PAGE_SIZE);
834
835 }
836 #endif /* ADD_ISA_HOLE */
837
838 /*
839 * Build a directory of the pages that make up our Physical to Machine
840 * mapping table. The Xen suspend/restore code uses this to find our
841 * mapping table.
842 */
843 static void
844 init_frame_list_list(void *arg)
845 {
846 unsigned long nr_pages = xen_start_info->nr_pages;
847 #define FPP (PAGE_SIZE/sizeof(xen_pfn_t))
848 int i, j, k;
849
850 xen_pfn_to_mfn_frame_list_list = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
851 for (i = 0, j = 0, k = -1; i < nr_pages;
852 i += FPP, j++) {
853 if ((j & (FPP - 1)) == 0) {
854 k++;
855 xen_pfn_to_mfn_frame_list[k] =
856 malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
857 xen_pfn_to_mfn_frame_list_list[k] =
858 VTOMFN(xen_pfn_to_mfn_frame_list[k]);
859 j = 0;
860 }
861 xen_pfn_to_mfn_frame_list[k][j] =
862 VTOMFN(&xen_phys_machine[i]);
863 }
864
865 HYPERVISOR_shared_info->arch.max_pfn = nr_pages;
866 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list
867 = VTOMFN(xen_pfn_to_mfn_frame_list_list);
868 }
869 SYSINIT(init_fll, SI_SUB_DEVFS, SI_ORDER_ANY, init_frame_list_list, NULL);
870
871 extern unsigned long physfree;
872
873 int pdir, curoffset;
874 extern int nkpt;
875
876 void
877 initvalues(start_info_t *startinfo)
878 {
879 int l3_pages, l2_pages, l1_pages, offset;
880 vm_offset_t cur_space, cur_space_pt;
881 struct physdev_set_iopl set_iopl;
882
883 vm_paddr_t KPTphys, IdlePTDma;
884 vm_paddr_t console_page_ma, xen_store_ma;
885 vm_offset_t KPTphysoff, tmpva;
886 vm_paddr_t shinfo;
887 #ifdef PAE
888 vm_paddr_t IdlePDPTma, IdlePDPTnewma;
889 vm_paddr_t IdlePTDnewma[4];
890 pd_entry_t *IdlePDPTnew, *IdlePTDnew;
891 #else
892 vm_paddr_t pdir_shadow_ma;
893 #endif
894 unsigned long i;
895 int ncpus = MAXCPU;
896
897 nkpt = min(
898 min(
899 max((startinfo->nr_pages >> NPGPTD_SHIFT), nkpt),
900 NPGPTD*NPDEPG - KPTDI),
901 (HYPERVISOR_VIRT_START - KERNBASE) >> PDRSHIFT);
902
903 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
904 #ifdef notyet
905 /*
906 * need to install handler
907 */
908 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify);
909 #endif
910 xen_start_info = startinfo;
911 xen_phys_machine = (xen_pfn_t *)startinfo->mfn_list;
912
913 IdlePTD = (pd_entry_t *)((uint8_t *)startinfo->pt_base + PAGE_SIZE);
914 l1_pages = 0;
915
916 #ifdef PAE
917 l3_pages = 1;
918 l2_pages = 0;
919 IdlePDPT = (pd_entry_t *)startinfo->pt_base;
920 IdlePDPTma = xpmap_ptom(VTOP(startinfo->pt_base));
921 for (i = (KERNBASE >> 30);
922 (i < 4) && (IdlePDPT[i] != 0); i++)
923 l2_pages++;
924 /*
925 * Note that only one page directory has been allocated at this point.
926 * Thus, if KERNBASE
927 */
928 #if 0
929 for (i = 0; i < l2_pages; i++)
930 IdlePTDma[i] = xpmap_ptom(VTOP(IdlePTD + i*PAGE_SIZE));
931 #endif
932
933 l2_pages = (l2_pages == 0) ? 1 : l2_pages;
934 #else
935 l3_pages = 0;
936 l2_pages = 1;
937 #endif
938 for (i = (((KERNBASE>>18) & PAGE_MASK)>>PAGE_SHIFT);
939 (i<l2_pages*NPDEPG) && (i<(VM_MAX_KERNEL_ADDRESS>>PDRSHIFT)); i++) {
940
941 if (IdlePTD[i] == 0)
942 break;
943 l1_pages++;
944 }
945
946 /* number of pages allocated after the pts + 1*/;
947 cur_space = xen_start_info->pt_base +
948 ((xen_start_info->nr_pt_frames) + 3 )*PAGE_SIZE;
949 printk("initvalues(): wooh - availmem=%x,%x\n", avail_space, cur_space);
950
951 printk("KERNBASE=%x,pt_base=%x, VTOPFN(base)=%x, nr_pt_frames=%x\n",
952 KERNBASE,xen_start_info->pt_base, VTOPFN(xen_start_info->pt_base),
953 xen_start_info->nr_pt_frames);
954 xendebug_flags = 0; /* 0xffffffff; */
955
956 /* allocate 4 pages for bootmem allocator */
957 bootmem_start = bootmem_current = (char *)cur_space;
958 cur_space += (4 * PAGE_SIZE);
959 bootmem_end = (char *)cur_space;
960
961 /* allocate page for gdt */
962 gdt = (union descriptor *)cur_space;
963 cur_space += PAGE_SIZE*ncpus;
964
965 /* allocate page for ldt */
966 ldt = (union descriptor *)cur_space; cur_space += PAGE_SIZE;
967 cur_space += PAGE_SIZE;
968
969 HYPERVISOR_shared_info = (shared_info_t *)cur_space;
970 cur_space += PAGE_SIZE;
971
972 xen_store = (struct xenstore_domain_interface *)cur_space;
973 cur_space += PAGE_SIZE;
974
975 console_page = (char *)cur_space;
976 cur_space += PAGE_SIZE;
977
978 #ifdef ADD_ISA_HOLE
979 shift_phys_machine(xen_phys_machine, xen_start_info->nr_pages);
980 #endif
981 /*
982 * pre-zero unused mapped pages - mapped on 4MB boundary
983 */
984 #ifdef PAE
985 IdlePDPT = (pd_entry_t *)startinfo->pt_base;
986 IdlePDPTma = xpmap_ptom(VTOP(startinfo->pt_base));
987 /*
988 * Note that only one page directory has been allocated at this point.
989 * Thus, if KERNBASE
990 */
991 IdlePTD = (pd_entry_t *)((uint8_t *)startinfo->pt_base + PAGE_SIZE);
992 IdlePTDma = xpmap_ptom(VTOP(IdlePTD));
993 l3_pages = 1;
994 #else
995 IdlePTD = (pd_entry_t *)startinfo->pt_base;
996 IdlePTDma = xpmap_ptom(VTOP(startinfo->pt_base));
997 l3_pages = 0;
998 #endif
999 l2_pages = 1;
1000 l1_pages = xen_start_info->nr_pt_frames - l2_pages - l3_pages;
1001
1002 KPTphysoff = (l2_pages + l3_pages)*PAGE_SIZE;
1003
1004 KPTphys = xpmap_ptom(VTOP(startinfo->pt_base + KPTphysoff));
1005 XENPRINTF("IdlePTD %p\n", IdlePTD);
1006 XENPRINTF("nr_pages: %ld shared_info: 0x%lx flags: 0x%lx pt_base: 0x%lx "
1007 "mod_start: 0x%lx mod_len: 0x%lx\n",
1008 xen_start_info->nr_pages, xen_start_info->shared_info,
1009 xen_start_info->flags, xen_start_info->pt_base,
1010 xen_start_info->mod_start, xen_start_info->mod_len);
1011 /* Map proc0's KSTACK */
1012
1013 proc0kstack = cur_space; cur_space += (KSTACK_PAGES * PAGE_SIZE);
1014 printk("proc0kstack=%u\n", proc0kstack);
1015
1016 /* vm86/bios stack */
1017 cur_space += PAGE_SIZE;
1018
1019 /* Map space for the vm86 region */
1020 vm86paddr = (vm_offset_t)cur_space;
1021 cur_space += (PAGE_SIZE * 3);
1022
1023 #ifdef PAE
1024 IdlePDPTnew = (pd_entry_t *)cur_space; cur_space += PAGE_SIZE;
1025 bzero(IdlePDPTnew, PAGE_SIZE);
1026
1027 IdlePDPTnewma = xpmap_ptom(VTOP(IdlePDPTnew));
1028 IdlePTDnew = (pd_entry_t *)cur_space; cur_space += 4*PAGE_SIZE;
1029 bzero(IdlePTDnew, 4*PAGE_SIZE);
1030
1031 for (i = 0; i < 4; i++)
1032 IdlePTDnewma[i] =
1033 xpmap_ptom(VTOP((uint8_t *)IdlePTDnew + i*PAGE_SIZE));
1034 /*
1035 * L3
1036 *
1037 * Copy the 4 machine addresses of the new PTDs in to the PDPT
1038 *
1039 */
1040 for (i = 0; i < 4; i++)
1041 IdlePDPTnew[i] = IdlePTDnewma[i] | PG_V;
1042
1043 __asm__("nop;");
1044 /*
1045 *
1046 * re-map the new PDPT read-only
1047 */
1048 PT_SET_MA(IdlePDPTnew, IdlePDPTnewma | PG_V);
1049 /*
1050 *
1051 * Unpin the current PDPT
1052 */
1053 xen_pt_unpin(IdlePDPTma);
1054
1055 for (i = 0; i < 20; i++) {
1056 int startidx = ((KERNBASE >> 18) & PAGE_MASK) >> 3;
1057
1058 if (IdlePTD[startidx + i] == 0) {
1059 l1_pages = i;
1060 break;
1061 }
1062 }
1063
1064 #endif /* PAE */
1065
1066 /* unmap remaining pages from initial 4MB chunk
1067 *
1068 */
1069 for (tmpva = cur_space; (tmpva & ((1<<22)-1)) != 0; tmpva += PAGE_SIZE) {
1070 bzero((char *)tmpva, PAGE_SIZE);
1071 PT_SET_MA(tmpva, (vm_paddr_t)0);
1072 }
1073
1074 PT_UPDATES_FLUSH();
1075
1076 memcpy(((uint8_t *)IdlePTDnew) + ((unsigned int)(KERNBASE >> 18)),
1077 ((uint8_t *)IdlePTD) + ((KERNBASE >> 18) & PAGE_MASK),
1078 l1_pages*sizeof(pt_entry_t));
1079
1080 for (i = 0; i < 4; i++) {
1081 PT_SET_MA((uint8_t *)IdlePTDnew + i*PAGE_SIZE,
1082 IdlePTDnewma[i] | PG_V);
1083 }
1084 xen_load_cr3(VTOP(IdlePDPTnew));
1085 xen_pgdpt_pin(xpmap_ptom(VTOP(IdlePDPTnew)));
1086
1087 /* allocate remainder of nkpt pages */
1088 cur_space_pt = cur_space;
1089 for (offset = (KERNBASE >> PDRSHIFT), i = l1_pages; i < nkpt;
1090 i++, cur_space += PAGE_SIZE) {
1091 pdir = (offset + i) / NPDEPG;
1092 curoffset = ((offset + i) % NPDEPG);
1093 if (((offset + i) << PDRSHIFT) == VM_MAX_KERNEL_ADDRESS)
1094 break;
1095
1096 /*
1097 * make sure that all the initial page table pages
1098 * have been zeroed
1099 */
1100 PT_SET_MA(cur_space_pt,
1101 xpmap_ptom(VTOP(cur_space)) | PG_V | PG_RW);
1102 bzero((char *)cur_space_pt, PAGE_SIZE);
1103 PT_SET_MA(cur_space_pt, (vm_paddr_t)0);
1104 xen_pt_pin(xpmap_ptom(VTOP(cur_space)));
1105 xen_queue_pt_update((vm_paddr_t)(IdlePTDnewma[pdir] +
1106 curoffset*sizeof(vm_paddr_t)),
1107 xpmap_ptom(VTOP(cur_space)) | PG_KERNEL);
1108 PT_UPDATES_FLUSH();
1109 }
1110
1111 for (i = 0; i < 4; i++) {
1112 pdir = (PTDPTDI + i) / NPDEPG;
1113 curoffset = (PTDPTDI + i) % NPDEPG;
1114
1115 xen_queue_pt_update((vm_paddr_t)(IdlePTDnewma[pdir] +
1116 curoffset*sizeof(vm_paddr_t)),
1117 IdlePTDnewma[i] | PG_V);
1118 }
1119
1120 PT_UPDATES_FLUSH();
1121
1122 IdlePTD = IdlePTDnew;
1123 IdlePDPT = IdlePDPTnew;
1124 IdlePDPTma = IdlePDPTnewma;
1125
1126 /*
1127 * shared_info is an unsigned long so this will randomly break if
1128 * it is allocated above 4GB - I guess people are used to that
1129 * sort of thing with Xen ... sigh
1130 */
1131 shinfo = xen_start_info->shared_info;
1132 PT_SET_MA(HYPERVISOR_shared_info, shinfo | PG_KERNEL);
1133
1134 printk("#4\n");
1135
1136 xen_store_ma = (((vm_paddr_t)xen_start_info->store_mfn) << PAGE_SHIFT);
1137 PT_SET_MA(xen_store, xen_store_ma | PG_KERNEL);
1138 console_page_ma = (((vm_paddr_t)xen_start_info->console.domU.mfn) << PAGE_SHIFT);
1139 PT_SET_MA(console_page, console_page_ma | PG_KERNEL);
1140
1141 printk("#5\n");
1142
1143 set_iopl.iopl = 1;
1144 PANIC_IF(HYPERVISOR_physdev_op(PHYSDEVOP_SET_IOPL, &set_iopl));
1145 printk("#6\n");
1146 #if 0
1147 /* add page table for KERNBASE */
1148 xen_queue_pt_update(IdlePTDma + KPTDI*sizeof(vm_paddr_t),
1149 xpmap_ptom(VTOP(cur_space) | PG_KERNEL));
1150 xen_flush_queue();
1151 #ifdef PAE
1152 xen_queue_pt_update(pdir_shadow_ma[3] + KPTDI*sizeof(vm_paddr_t),
1153 xpmap_ptom(VTOP(cur_space) | PG_V | PG_A));
1154 #else
1155 xen_queue_pt_update(pdir_shadow_ma + KPTDI*sizeof(vm_paddr_t),
1156 xpmap_ptom(VTOP(cur_space) | PG_V | PG_A));
1157 #endif
1158 xen_flush_queue();
1159 cur_space += PAGE_SIZE;
1160 printk("#6\n");
1161 #endif /* 0 */
1162 #ifdef notyet
1163 if (xen_start_info->flags & SIF_INITDOMAIN) {
1164 /* Map first megabyte */
1165 for (i = 0; i < (256 << PAGE_SHIFT); i += PAGE_SIZE)
1166 PT_SET_MA(KERNBASE + i, i | PG_KERNEL | PG_NC_PCD);
1167 xen_flush_queue();
1168 }
1169 #endif
1170 /*
1171 * re-map kernel text read-only
1172 *
1173 */
1174 for (i = (((vm_offset_t)&btext) & ~PAGE_MASK);
1175 i < (((vm_offset_t)&etext) & ~PAGE_MASK); i += PAGE_SIZE)
1176 PT_SET_MA(i, xpmap_ptom(VTOP(i)) | PG_V | PG_A);
1177
1178 printk("#7\n");
1179 physfree = VTOP(cur_space);
1180 init_first = physfree >> PAGE_SHIFT;
1181 IdlePTD = (pd_entry_t *)VTOP(IdlePTD);
1182 IdlePDPT = (pd_entry_t *)VTOP(IdlePDPT);
1183 setup_xen_features();
1184 printk("#8, proc0kstack=%u\n", proc0kstack);
1185 }
1186
1187
1188 trap_info_t trap_table[] = {
1189 { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)},
1190 { 1, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)},
1191 { 3, 3|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)},
1192 { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)},
1193 /* This is UPL on Linux and KPL on BSD */
1194 { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)},
1195 { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)},
1196 { 7, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)},
1197 /*
1198 * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)},
1199 * no handler for double fault
1200 */
1201 { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)},
1202 {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)},
1203 {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)},
1204 {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)},
1205 {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)},
1206 {14, 0|4, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)},
1207 {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)},
1208 {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)},
1209 {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)},
1210 {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)},
1211 {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)},
1212 {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)},
1213 { 0, 0, 0, 0 }
1214 };
1215
1216
1217 /********** CODE WORTH KEEPING ABOVE HERE *****************/
1218
1219 void xen_failsafe_handler(void);
1220
1221 void
1222 xen_failsafe_handler(void)
1223 {
1224
1225 panic("xen_failsafe_handler called!\n");
1226 }
1227
1228 void xen_handle_thread_switch(struct pcb *pcb);
1229
1230 /* This is called by cpu_switch() when switching threads. */
1231 /* The pcb arg refers to the process control block of the */
1232 /* next thread which is to run */
1233 void
1234 xen_handle_thread_switch(struct pcb *pcb)
1235 {
1236 uint32_t *a = (uint32_t *)&PCPU_GET(fsgs_gdt)[0];
1237 uint32_t *b = (uint32_t *)&pcb->pcb_fsd;
1238 multicall_entry_t mcl[3];
1239 int i = 0;
1240
1241 /* Notify Xen of task switch */
1242 mcl[i].op = __HYPERVISOR_stack_switch;
1243 mcl[i].args[0] = GSEL(GDATA_SEL, SEL_KPL);
1244 mcl[i++].args[1] = (unsigned long)pcb;
1245
1246 /* Check for update of fsd */
1247 if (*a != *b || *(a+1) != *(b+1)) {
1248 mcl[i].op = __HYPERVISOR_update_descriptor;
1249 *(uint64_t *)&mcl[i].args[0] = vtomach((vm_offset_t)a);
1250 *(uint64_t *)&mcl[i++].args[2] = *(uint64_t *)b;
1251 }
1252
1253 a += 2;
1254 b += 2;
1255
1256 /* Check for update of gsd */
1257 if (*a != *b || *(a+1) != *(b+1)) {
1258 mcl[i].op = __HYPERVISOR_update_descriptor;
1259 *(uint64_t *)&mcl[i].args[0] = vtomach((vm_offset_t)a);
1260 *(uint64_t *)&mcl[i++].args[2] = *(uint64_t *)b;
1261 }
1262
1263 (void)HYPERVISOR_multicall(mcl, i);
1264 }
Cache object: 59d649cac5c6d67b701d4adb1f7ece52
|