diff options
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 185 |
1 files changed, 70 insertions, 115 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index a4e201b47f64..b106e825d266 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <xen/interface/xen.h> | 30 | #include <xen/interface/xen.h> |
31 | #include <xen/interface/physdev.h> | 31 | #include <xen/interface/physdev.h> |
32 | #include <xen/interface/vcpu.h> | 32 | #include <xen/interface/vcpu.h> |
33 | #include <xen/interface/sched.h> | ||
34 | #include <xen/features.h> | 33 | #include <xen/features.h> |
35 | #include <xen/page.h> | 34 | #include <xen/page.h> |
36 | #include <xen/hvc-console.h> | 35 | #include <xen/hvc-console.h> |
@@ -57,6 +56,9 @@ EXPORT_SYMBOL_GPL(hypercall_page); | |||
57 | DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); | 56 | DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); |
58 | DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); | 57 | DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info); |
59 | 58 | ||
59 | enum xen_domain_type xen_domain_type = XEN_NATIVE; | ||
60 | EXPORT_SYMBOL_GPL(xen_domain_type); | ||
61 | |||
60 | /* | 62 | /* |
61 | * Identity map, in addition to plain kernel map. This needs to be | 63 | * Identity map, in addition to plain kernel map. This needs to be |
62 | * large enough to allocate page table pages to allocate the rest. | 64 | * large enough to allocate page table pages to allocate the rest. |
@@ -226,103 +228,68 @@ static unsigned long xen_get_debugreg(int reg) | |||
226 | return HYPERVISOR_get_debugreg(reg); | 228 | return HYPERVISOR_get_debugreg(reg); |
227 | } | 229 | } |
228 | 230 | ||
229 | static unsigned long xen_save_fl(void) | 231 | static void xen_leave_lazy(void) |
230 | { | 232 | { |
231 | struct vcpu_info *vcpu; | 233 | paravirt_leave_lazy(paravirt_get_lazy_mode()); |
232 | unsigned long flags; | 234 | xen_mc_flush(); |
233 | |||
234 | vcpu = x86_read_percpu(xen_vcpu); | ||
235 | |||
236 | /* flag has opposite sense of mask */ | ||
237 | flags = !vcpu->evtchn_upcall_mask; | ||
238 | |||
239 | /* convert to IF type flag | ||
240 | -0 -> 0x00000000 | ||
241 | -1 -> 0xffffffff | ||
242 | */ | ||
243 | return (-flags) & X86_EFLAGS_IF; | ||
244 | } | 235 | } |
245 | 236 | ||
246 | static void xen_restore_fl(unsigned long flags) | 237 | static unsigned long xen_store_tr(void) |
247 | { | 238 | { |
248 | struct vcpu_info *vcpu; | 239 | return 0; |
249 | |||
250 | /* convert from IF type flag */ | ||
251 | flags = !(flags & X86_EFLAGS_IF); | ||
252 | |||
253 | /* There's a one instruction preempt window here. We need to | ||
254 | make sure we're don't switch CPUs between getting the vcpu | ||
255 | pointer and updating the mask. */ | ||
256 | preempt_disable(); | ||
257 | vcpu = x86_read_percpu(xen_vcpu); | ||
258 | vcpu->evtchn_upcall_mask = flags; | ||
259 | preempt_enable_no_resched(); | ||
260 | |||
261 | /* Doesn't matter if we get preempted here, because any | ||
262 | pending event will get dealt with anyway. */ | ||
263 | |||
264 | if (flags == 0) { | ||
265 | preempt_check_resched(); | ||
266 | barrier(); /* unmask then check (avoid races) */ | ||
267 | if (unlikely(vcpu->evtchn_upcall_pending)) | ||
268 | force_evtchn_callback(); | ||
269 | } | ||
270 | } | 240 | } |
271 | 241 | ||
272 | static void xen_irq_disable(void) | 242 | /* |
243 | * Set the page permissions for a particular virtual address. If the | ||
244 | * address is a vmalloc mapping (or other non-linear mapping), then | ||
245 | * find the linear mapping of the page and also set its protections to | ||
246 | * match. | ||
247 | */ | ||
248 | static void set_aliased_prot(void *v, pgprot_t prot) | ||
273 | { | 249 | { |
274 | /* There's a one instruction preempt window here. We need to | 250 | int level; |
275 | make sure we're don't switch CPUs between getting the vcpu | 251 | pte_t *ptep; |
276 | pointer and updating the mask. */ | 252 | pte_t pte; |
277 | preempt_disable(); | 253 | unsigned long pfn; |
278 | x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1; | 254 | struct page *page; |
279 | preempt_enable_no_resched(); | ||
280 | } | ||
281 | 255 | ||
282 | static void xen_irq_enable(void) | 256 | ptep = lookup_address((unsigned long)v, &level); |
283 | { | 257 | BUG_ON(ptep == NULL); |
284 | struct vcpu_info *vcpu; | ||
285 | 258 | ||
286 | /* We don't need to worry about being preempted here, since | 259 | pfn = pte_pfn(*ptep); |
287 | either a) interrupts are disabled, so no preemption, or b) | 260 | page = pfn_to_page(pfn); |
288 | the caller is confused and is trying to re-enable interrupts | ||
289 | on an indeterminate processor. */ | ||
290 | 261 | ||
291 | vcpu = x86_read_percpu(xen_vcpu); | 262 | pte = pfn_pte(pfn, prot); |
292 | vcpu->evtchn_upcall_mask = 0; | ||
293 | 263 | ||
294 | /* Doesn't matter if we get preempted here, because any | 264 | if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0)) |
295 | pending event will get dealt with anyway. */ | 265 | BUG(); |
296 | 266 | ||
297 | barrier(); /* unmask then check (avoid races) */ | 267 | if (!PageHighMem(page)) { |
298 | if (unlikely(vcpu->evtchn_upcall_pending)) | 268 | void *av = __va(PFN_PHYS(pfn)); |
299 | force_evtchn_callback(); | ||
300 | } | ||
301 | 269 | ||
302 | static void xen_safe_halt(void) | 270 | if (av != v) |
303 | { | 271 | if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0)) |
304 | /* Blocking includes an implicit local_irq_enable(). */ | 272 | BUG(); |
305 | if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0) | 273 | } else |
306 | BUG(); | 274 | kmap_flush_unused(); |
307 | } | 275 | } |
308 | 276 | ||
309 | static void xen_halt(void) | 277 | static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries) |
310 | { | 278 | { |
311 | if (irqs_disabled()) | 279 | const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE; |
312 | HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); | 280 | int i; |
313 | else | ||
314 | xen_safe_halt(); | ||
315 | } | ||
316 | 281 | ||
317 | static void xen_leave_lazy(void) | 282 | for(i = 0; i < entries; i += entries_per_page) |
318 | { | 283 | set_aliased_prot(ldt + i, PAGE_KERNEL_RO); |
319 | paravirt_leave_lazy(paravirt_get_lazy_mode()); | ||
320 | xen_mc_flush(); | ||
321 | } | 284 | } |
322 | 285 | ||
323 | static unsigned long xen_store_tr(void) | 286 | static void xen_free_ldt(struct desc_struct *ldt, unsigned entries) |
324 | { | 287 | { |
325 | return 0; | 288 | const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE; |
289 | int i; | ||
290 | |||
291 | for(i = 0; i < entries; i += entries_per_page) | ||
292 | set_aliased_prot(ldt + i, PAGE_KERNEL); | ||
326 | } | 293 | } |
327 | 294 | ||
328 | static void xen_set_ldt(const void *addr, unsigned entries) | 295 | static void xen_set_ldt(const void *addr, unsigned entries) |
@@ -425,8 +392,7 @@ static void xen_load_gs_index(unsigned int idx) | |||
425 | static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | 392 | static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, |
426 | const void *ptr) | 393 | const void *ptr) |
427 | { | 394 | { |
428 | unsigned long lp = (unsigned long)&dt[entrynum]; | 395 | xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]); |
429 | xmaddr_t mach_lp = virt_to_machine(lp); | ||
430 | u64 entry = *(u64 *)ptr; | 396 | u64 entry = *(u64 *)ptr; |
431 | 397 | ||
432 | preempt_disable(); | 398 | preempt_disable(); |
@@ -559,7 +525,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry, | |||
559 | } | 525 | } |
560 | 526 | ||
561 | static void xen_load_sp0(struct tss_struct *tss, | 527 | static void xen_load_sp0(struct tss_struct *tss, |
562 | struct thread_struct *thread) | 528 | struct thread_struct *thread) |
563 | { | 529 | { |
564 | struct multicall_space mcs = xen_mc_entry(0); | 530 | struct multicall_space mcs = xen_mc_entry(0); |
565 | MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); | 531 | MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); |
@@ -803,6 +769,19 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) | |||
803 | ret = -EFAULT; | 769 | ret = -EFAULT; |
804 | break; | 770 | break; |
805 | #endif | 771 | #endif |
772 | |||
773 | case MSR_STAR: | ||
774 | case MSR_CSTAR: | ||
775 | case MSR_LSTAR: | ||
776 | case MSR_SYSCALL_MASK: | ||
777 | case MSR_IA32_SYSENTER_CS: | ||
778 | case MSR_IA32_SYSENTER_ESP: | ||
779 | case MSR_IA32_SYSENTER_EIP: | ||
780 | /* Fast syscall setup is all done in hypercalls, so | ||
781 | these are all ignored. Stub them out here to stop | ||
782 | Xen console noise. */ | ||
783 | break; | ||
784 | |||
806 | default: | 785 | default: |
807 | ret = native_write_msr_safe(msr, low, high); | 786 | ret = native_write_msr_safe(msr, low, high); |
808 | } | 787 | } |
@@ -846,7 +825,7 @@ static void xen_alloc_ptpage(struct mm_struct *mm, u32 pfn, unsigned level) | |||
846 | SetPagePinned(page); | 825 | SetPagePinned(page); |
847 | 826 | ||
848 | if (!PageHighMem(page)) { | 827 | if (!PageHighMem(page)) { |
849 | make_lowmem_page_readonly(__va(PFN_PHYS(pfn))); | 828 | make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn))); |
850 | if (level == PT_PTE) | 829 | if (level == PT_PTE) |
851 | pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); | 830 | pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn); |
852 | } else | 831 | } else |
@@ -1220,6 +1199,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
1220 | .load_gs_index = xen_load_gs_index, | 1199 | .load_gs_index = xen_load_gs_index, |
1221 | #endif | 1200 | #endif |
1222 | 1201 | ||
1202 | .alloc_ldt = xen_alloc_ldt, | ||
1203 | .free_ldt = xen_free_ldt, | ||
1204 | |||
1223 | .store_gdt = native_store_gdt, | 1205 | .store_gdt = native_store_gdt, |
1224 | .store_idt = native_store_idt, | 1206 | .store_idt = native_store_idt, |
1225 | .store_tr = xen_store_tr, | 1207 | .store_tr = xen_store_tr, |
@@ -1241,36 +1223,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
1241 | }, | 1223 | }, |
1242 | }; | 1224 | }; |
1243 | 1225 | ||
1244 | static void __init __xen_init_IRQ(void) | ||
1245 | { | ||
1246 | #ifdef CONFIG_X86_64 | ||
1247 | int i; | ||
1248 | |||
1249 | /* Create identity vector->irq map */ | ||
1250 | for(i = 0; i < NR_VECTORS; i++) { | ||
1251 | int cpu; | ||
1252 | |||
1253 | for_each_possible_cpu(cpu) | ||
1254 | per_cpu(vector_irq, cpu)[i] = i; | ||
1255 | } | ||
1256 | #endif /* CONFIG_X86_64 */ | ||
1257 | |||
1258 | xen_init_IRQ(); | ||
1259 | } | ||
1260 | |||
1261 | static const struct pv_irq_ops xen_irq_ops __initdata = { | ||
1262 | .init_IRQ = __xen_init_IRQ, | ||
1263 | .save_fl = xen_save_fl, | ||
1264 | .restore_fl = xen_restore_fl, | ||
1265 | .irq_disable = xen_irq_disable, | ||
1266 | .irq_enable = xen_irq_enable, | ||
1267 | .safe_halt = xen_safe_halt, | ||
1268 | .halt = xen_halt, | ||
1269 | #ifdef CONFIG_X86_64 | ||
1270 | .adjust_exception_frame = xen_adjust_exception_frame, | ||
1271 | #endif | ||
1272 | }; | ||
1273 | |||
1274 | static const struct pv_apic_ops xen_apic_ops __initdata = { | 1226 | static const struct pv_apic_ops xen_apic_ops __initdata = { |
1275 | #ifdef CONFIG_X86_LOCAL_APIC | 1227 | #ifdef CONFIG_X86_LOCAL_APIC |
1276 | .apic_write = xen_apic_write, | 1228 | .apic_write = xen_apic_write, |
@@ -1664,6 +1616,8 @@ asmlinkage void __init xen_start_kernel(void) | |||
1664 | if (!xen_start_info) | 1616 | if (!xen_start_info) |
1665 | return; | 1617 | return; |
1666 | 1618 | ||
1619 | xen_domain_type = XEN_PV_DOMAIN; | ||
1620 | |||
1667 | BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0); | 1621 | BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0); |
1668 | 1622 | ||
1669 | xen_setup_features(); | 1623 | xen_setup_features(); |
@@ -1673,10 +1627,11 @@ asmlinkage void __init xen_start_kernel(void) | |||
1673 | pv_init_ops = xen_init_ops; | 1627 | pv_init_ops = xen_init_ops; |
1674 | pv_time_ops = xen_time_ops; | 1628 | pv_time_ops = xen_time_ops; |
1675 | pv_cpu_ops = xen_cpu_ops; | 1629 | pv_cpu_ops = xen_cpu_ops; |
1676 | pv_irq_ops = xen_irq_ops; | ||
1677 | pv_apic_ops = xen_apic_ops; | 1630 | pv_apic_ops = xen_apic_ops; |
1678 | pv_mmu_ops = xen_mmu_ops; | 1631 | pv_mmu_ops = xen_mmu_ops; |
1679 | 1632 | ||
1633 | xen_init_irq_ops(); | ||
1634 | |||
1680 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { | 1635 | if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) { |
1681 | pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; | 1636 | pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start; |
1682 | pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; | 1637 | pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit; |
@@ -1700,7 +1655,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
1700 | 1655 | ||
1701 | /* Prevent unwanted bits from being set in PTEs. */ | 1656 | /* Prevent unwanted bits from being set in PTEs. */ |
1702 | __supported_pte_mask &= ~_PAGE_GLOBAL; | 1657 | __supported_pte_mask &= ~_PAGE_GLOBAL; |
1703 | if (!is_initial_xendomain()) | 1658 | if (!xen_initial_domain()) |
1704 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); | 1659 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); |
1705 | 1660 | ||
1706 | /* Don't do the full vcpu_info placement stuff until we have a | 1661 | /* Don't do the full vcpu_info placement stuff until we have a |
@@ -1735,7 +1690,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
1735 | boot_params.hdr.ramdisk_size = xen_start_info->mod_len; | 1690 | boot_params.hdr.ramdisk_size = xen_start_info->mod_len; |
1736 | boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line); | 1691 | boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line); |
1737 | 1692 | ||
1738 | if (!is_initial_xendomain()) { | 1693 | if (!xen_initial_domain()) { |
1739 | add_preferred_console("xenboot", 0, NULL); | 1694 | add_preferred_console("xenboot", 0, NULL); |
1740 | add_preferred_console("tty", 0, NULL); | 1695 | add_preferred_console("tty", 0, NULL); |
1741 | add_preferred_console("hvc", 0, NULL); | 1696 | add_preferred_console("hvc", 0, NULL); |