1 /* 2 * Machine specific setup for xen 3 * 4 * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 5 */ 6 7 #include <linux/module.h> 8 #include <linux/sched.h> 9 #include <linux/mm.h> 10 #include <linux/pm.h> 11 12 #include <asm/elf.h> 13 #include <asm/vdso.h> 14 #include <asm/e820.h> 15 #include <asm/setup.h> 16 #include <asm/acpi.h> 17 #include <asm/xen/hypervisor.h> 18 #include <asm/xen/hypercall.h> 19 20 #include <xen/page.h> 21 #include <xen/interface/callback.h> 22 #include <xen/interface/physdev.h> 23 #include <xen/features.h> 24 25 #include "xen-ops.h" 26 #include "vdso.h" 27 28 /* These are code, but not functions. Defined in entry.S */ 29 extern const char xen_hypervisor_callback[]; 30 extern const char xen_failsafe_callback[]; 31 32 33 /** 34 * machine_specific_memory_setup - Hook for machine specific memory setup. 35 **/ 36 37 char * __init xen_memory_setup(void) 38 { 39 unsigned long max_pfn = xen_start_info->nr_pages; 40 41 max_pfn = min(MAX_DOMAIN_PAGES, max_pfn); 42 43 e820.nr_map = 0; 44 45 e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM); 46 47 /* 48 * Even though this is normal, usable memory under Xen, reserve 49 * ISA memory anyway because too many things think they can poke 50 * about in there. 51 */ 52 e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS, 53 E820_RESERVED); 54 55 /* 56 * Reserve Xen bits: 57 * - mfn_list 58 * - xen_start_info 59 * See comment above "struct start_info" in <xen/interface/xen.h> 60 */ 61 e820_add_region(__pa(xen_start_info->mfn_list), 62 xen_start_info->pt_base - xen_start_info->mfn_list, 63 E820_RESERVED); 64 65 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); 66 67 return "Xen"; 68 } 69 70 static void xen_idle(void) 71 { 72 local_irq_disable(); 73 74 if (need_resched()) 75 local_irq_enable(); 76 else { 77 current_thread_info()->status &= ~TS_POLLING; 78 smp_mb__after_clear_bit(); 79 safe_halt(); 80 current_thread_info()->status |= TS_POLLING; 81 } 82 } 83 84 /* 85 * Set the bit indicating "nosegneg" library variants should be used. 86 * We only need to bother in pure 32-bit mode; compat 32-bit processes 87 * can have un-truncated segments, so wrapping around is allowed. 88 */ 89 static void __init fiddle_vdso(void) 90 { 91 #ifdef CONFIG_X86_32 92 u32 *mask; 93 mask = VDSO32_SYMBOL(&vdso32_int80_start, NOTE_MASK); 94 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; 95 mask = VDSO32_SYMBOL(&vdso32_sysenter_start, NOTE_MASK); 96 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; 97 #endif 98 } 99 100 static __cpuinit int register_callback(unsigned type, const void *func) 101 { 102 struct callback_register callback = { 103 .type = type, 104 .address = XEN_CALLBACK(__KERNEL_CS, func), 105 .flags = CALLBACKF_mask_events, 106 }; 107 108 return HYPERVISOR_callback_op(CALLBACKOP_register, &callback); 109 } 110 111 void __cpuinit xen_enable_sysenter(void) 112 { 113 extern void xen_sysenter_target(void); 114 int ret; 115 unsigned sysenter_feature; 116 117 #ifdef CONFIG_X86_32 118 sysenter_feature = X86_FEATURE_SEP; 119 #else 120 sysenter_feature = X86_FEATURE_SYSENTER32; 121 #endif 122 123 if (!boot_cpu_has(sysenter_feature)) 124 return; 125 126 ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target); 127 if(ret != 0) 128 setup_clear_cpu_cap(sysenter_feature); 129 } 130 131 void __cpuinit xen_enable_syscall(void) 132 { 133 #ifdef CONFIG_X86_64 134 int ret; 135 extern void xen_syscall_target(void); 136 extern void xen_syscall32_target(void); 137 138 ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target); 139 if (ret != 0) { 140 printk(KERN_ERR "Failed to set syscall callback: %d\n", ret); 141 /* Pretty fatal; 64-bit userspace has no other 142 mechanism for syscalls. */ 143 } 144 145 if (boot_cpu_has(X86_FEATURE_SYSCALL32)) { 146 ret = register_callback(CALLBACKTYPE_syscall32, 147 xen_syscall32_target); 148 if (ret != 0) 149 setup_clear_cpu_cap(X86_FEATURE_SYSCALL32); 150 } 151 #endif /* CONFIG_X86_64 */ 152 } 153 154 void __init xen_arch_setup(void) 155 { 156 struct physdev_set_iopl set_iopl; 157 int rc; 158 159 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); 160 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); 161 162 if (!xen_feature(XENFEAT_auto_translated_physmap)) 163 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3); 164 165 if (register_callback(CALLBACKTYPE_event, xen_hypervisor_callback) || 166 register_callback(CALLBACKTYPE_failsafe, xen_failsafe_callback)) 167 BUG(); 168 169 xen_enable_sysenter(); 170 xen_enable_syscall(); 171 172 set_iopl.iopl = 1; 173 rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); 174 if (rc != 0) 175 printk(KERN_INFO "physdev_op failed %d\n", rc); 176 177 #ifdef CONFIG_ACPI 178 if (!(xen_start_info->flags & SIF_INITDOMAIN)) { 179 printk(KERN_INFO "ACPI in unprivileged domain disabled\n"); 180 disable_acpi(); 181 } 182 #endif 183 184 memcpy(boot_command_line, xen_start_info->cmd_line, 185 MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ? 186 COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE); 187 188 pm_idle = xen_idle; 189 190 paravirt_disable_iospace(); 191 192 fiddle_vdso(); 193 } 194