diff options
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 201 |
1 files changed, 184 insertions, 17 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 65d8d79b46a8..7d46c8441418 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 | 11 | * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/cpu.h> | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
@@ -35,8 +36,10 @@ | |||
35 | #include <xen/interface/version.h> | 36 | #include <xen/interface/version.h> |
36 | #include <xen/interface/physdev.h> | 37 | #include <xen/interface/physdev.h> |
37 | #include <xen/interface/vcpu.h> | 38 | #include <xen/interface/vcpu.h> |
39 | #include <xen/interface/memory.h> | ||
38 | #include <xen/features.h> | 40 | #include <xen/features.h> |
39 | #include <xen/page.h> | 41 | #include <xen/page.h> |
42 | #include <xen/hvm.h> | ||
40 | #include <xen/hvc-console.h> | 43 | #include <xen/hvc-console.h> |
41 | 44 | ||
42 | #include <asm/paravirt.h> | 45 | #include <asm/paravirt.h> |
@@ -55,7 +58,9 @@ | |||
55 | #include <asm/pgtable.h> | 58 | #include <asm/pgtable.h> |
56 | #include <asm/tlbflush.h> | 59 | #include <asm/tlbflush.h> |
57 | #include <asm/reboot.h> | 60 | #include <asm/reboot.h> |
61 | #include <asm/setup.h> | ||
58 | #include <asm/stackprotector.h> | 62 | #include <asm/stackprotector.h> |
63 | #include <asm/hypervisor.h> | ||
59 | 64 | ||
60 | #include "xen-ops.h" | 65 | #include "xen-ops.h" |
61 | #include "mmu.h" | 66 | #include "mmu.h" |
@@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info; | |||
76 | 81 | ||
77 | void *xen_initial_gdt; | 82 | void *xen_initial_gdt; |
78 | 83 | ||
84 | RESERVE_BRK(shared_info_page_brk, PAGE_SIZE); | ||
85 | __read_mostly int xen_have_vector_callback; | ||
86 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); | ||
87 | |||
79 | /* | 88 | /* |
80 | * Point at some empty memory to start with. We map the real shared_info | 89 | * Point at some empty memory to start with. We map the real shared_info |
81 | * page as soon as fixmap is up and running. | 90 | * page as soon as fixmap is up and running. |
@@ -97,6 +106,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; | |||
97 | */ | 106 | */ |
98 | static int have_vcpu_info_placement = 1; | 107 | static int have_vcpu_info_placement = 1; |
99 | 108 | ||
109 | static void clamp_max_cpus(void) | ||
110 | { | ||
111 | #ifdef CONFIG_SMP | ||
112 | if (setup_max_cpus > MAX_VIRT_CPUS) | ||
113 | setup_max_cpus = MAX_VIRT_CPUS; | ||
114 | #endif | ||
115 | } | ||
116 | |||
100 | static void xen_vcpu_setup(int cpu) | 117 | static void xen_vcpu_setup(int cpu) |
101 | { | 118 | { |
102 | struct vcpu_register_vcpu_info info; | 119 | struct vcpu_register_vcpu_info info; |
@@ -104,13 +121,17 @@ static void xen_vcpu_setup(int cpu) | |||
104 | struct vcpu_info *vcpup; | 121 | struct vcpu_info *vcpup; |
105 | 122 | ||
106 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 123 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
107 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
108 | 124 | ||
109 | if (!have_vcpu_info_placement) | 125 | if (cpu < MAX_VIRT_CPUS) |
110 | return; /* already tested, not available */ | 126 | per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; |
111 | 127 | ||
112 | vcpup = &per_cpu(xen_vcpu_info, cpu); | 128 | if (!have_vcpu_info_placement) { |
129 | if (cpu >= MAX_VIRT_CPUS) | ||
130 | clamp_max_cpus(); | ||
131 | return; | ||
132 | } | ||
113 | 133 | ||
134 | vcpup = &per_cpu(xen_vcpu_info, cpu); | ||
114 | info.mfn = arbitrary_virt_to_mfn(vcpup); | 135 | info.mfn = arbitrary_virt_to_mfn(vcpup); |
115 | info.offset = offset_in_page(vcpup); | 136 | info.offset = offset_in_page(vcpup); |
116 | 137 | ||
@@ -125,6 +146,7 @@ static void xen_vcpu_setup(int cpu) | |||
125 | if (err) { | 146 | if (err) { |
126 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); | 147 | printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); |
127 | have_vcpu_info_placement = 0; | 148 | have_vcpu_info_placement = 0; |
149 | clamp_max_cpus(); | ||
128 | } else { | 150 | } else { |
129 | /* This cpu is using the registered vcpu info, even if | 151 | /* This cpu is using the registered vcpu info, even if |
130 | later ones fail to. */ | 152 | later ones fail to. */ |
@@ -731,7 +753,6 @@ static void set_xen_basic_apic_ops(void) | |||
731 | 753 | ||
732 | #endif | 754 | #endif |
733 | 755 | ||
734 | |||
735 | static void xen_clts(void) | 756 | static void xen_clts(void) |
736 | { | 757 | { |
737 | struct multicall_space mcs; | 758 | struct multicall_space mcs; |
@@ -926,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = { | |||
926 | .patch = xen_patch, | 947 | .patch = xen_patch, |
927 | }; | 948 | }; |
928 | 949 | ||
929 | static const struct pv_time_ops xen_time_ops __initdata = { | ||
930 | .sched_clock = xen_sched_clock, | ||
931 | }; | ||
932 | |||
933 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { | 950 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { |
934 | .cpuid = xen_cpuid, | 951 | .cpuid = xen_cpuid, |
935 | 952 | ||
@@ -1028,6 +1045,23 @@ static void xen_crash_shutdown(struct pt_regs *regs) | |||
1028 | xen_reboot(SHUTDOWN_crash); | 1045 | xen_reboot(SHUTDOWN_crash); |
1029 | } | 1046 | } |
1030 | 1047 | ||
1048 | static int | ||
1049 | xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) | ||
1050 | { | ||
1051 | xen_reboot(SHUTDOWN_crash); | ||
1052 | return NOTIFY_DONE; | ||
1053 | } | ||
1054 | |||
1055 | static struct notifier_block xen_panic_block = { | ||
1056 | .notifier_call= xen_panic_event, | ||
1057 | }; | ||
1058 | |||
1059 | int xen_panic_handler_init(void) | ||
1060 | { | ||
1061 | atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block); | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1031 | static const struct machine_ops __initdata xen_machine_ops = { | 1065 | static const struct machine_ops __initdata xen_machine_ops = { |
1032 | .restart = xen_restart, | 1066 | .restart = xen_restart, |
1033 | .halt = xen_machine_halt, | 1067 | .halt = xen_machine_halt, |
@@ -1067,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void) | |||
1067 | /* Install Xen paravirt ops */ | 1101 | /* Install Xen paravirt ops */ |
1068 | pv_info = xen_info; | 1102 | pv_info = xen_info; |
1069 | pv_init_ops = xen_init_ops; | 1103 | pv_init_ops = xen_init_ops; |
1070 | pv_time_ops = xen_time_ops; | ||
1071 | pv_cpu_ops = xen_cpu_ops; | 1104 | pv_cpu_ops = xen_cpu_ops; |
1072 | pv_apic_ops = xen_apic_ops; | 1105 | pv_apic_ops = xen_apic_ops; |
1073 | 1106 | ||
@@ -1075,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
1075 | x86_init.oem.arch_setup = xen_arch_setup; | 1108 | x86_init.oem.arch_setup = xen_arch_setup; |
1076 | x86_init.oem.banner = xen_banner; | 1109 | x86_init.oem.banner = xen_banner; |
1077 | 1110 | ||
1078 | x86_init.timers.timer_init = xen_time_init; | 1111 | xen_init_time_ops(); |
1079 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
1080 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
1081 | |||
1082 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
1083 | x86_platform.get_wallclock = xen_get_wallclock; | ||
1084 | x86_platform.set_wallclock = xen_set_wallclock; | ||
1085 | 1112 | ||
1086 | /* | 1113 | /* |
1087 | * Set up some pagetable state before starting to set any ptes. | 1114 | * Set up some pagetable state before starting to set any ptes. |
@@ -1145,6 +1172,10 @@ asmlinkage void __init xen_start_kernel(void) | |||
1145 | 1172 | ||
1146 | pgd = (pgd_t *)xen_start_info->pt_base; | 1173 | pgd = (pgd_t *)xen_start_info->pt_base; |
1147 | 1174 | ||
1175 | if (!xen_initial_domain()) | ||
1176 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); | ||
1177 | |||
1178 | __supported_pte_mask |= _PAGE_IOMAP; | ||
1148 | /* Don't do the full vcpu_info placement stuff until we have a | 1179 | /* Don't do the full vcpu_info placement stuff until we have a |
1149 | possible map and a non-dummy shared_info. */ | 1180 | possible map and a non-dummy shared_info. */ |
1150 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; | 1181 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; |
@@ -1206,3 +1237,139 @@ asmlinkage void __init xen_start_kernel(void) | |||
1206 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); | 1237 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); |
1207 | #endif | 1238 | #endif |
1208 | } | 1239 | } |
1240 | |||
1241 | static uint32_t xen_cpuid_base(void) | ||
1242 | { | ||
1243 | uint32_t base, eax, ebx, ecx, edx; | ||
1244 | char signature[13]; | ||
1245 | |||
1246 | for (base = 0x40000000; base < 0x40010000; base += 0x100) { | ||
1247 | cpuid(base, &eax, &ebx, &ecx, &edx); | ||
1248 | *(uint32_t *)(signature + 0) = ebx; | ||
1249 | *(uint32_t *)(signature + 4) = ecx; | ||
1250 | *(uint32_t *)(signature + 8) = edx; | ||
1251 | signature[12] = 0; | ||
1252 | |||
1253 | if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) | ||
1254 | return base; | ||
1255 | } | ||
1256 | |||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | static int init_hvm_pv_info(int *major, int *minor) | ||
1261 | { | ||
1262 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | ||
1263 | u64 pfn; | ||
1264 | |||
1265 | base = xen_cpuid_base(); | ||
1266 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
1267 | |||
1268 | *major = eax >> 16; | ||
1269 | *minor = eax & 0xffff; | ||
1270 | printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor); | ||
1271 | |||
1272 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | ||
1273 | |||
1274 | pfn = __pa(hypercall_page); | ||
1275 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
1276 | |||
1277 | xen_setup_features(); | ||
1278 | |||
1279 | pv_info = xen_info; | ||
1280 | pv_info.kernel_rpl = 0; | ||
1281 | |||
1282 | xen_domain_type = XEN_HVM_DOMAIN; | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | void xen_hvm_init_shared_info(void) | ||
1288 | { | ||
1289 | int cpu; | ||
1290 | struct xen_add_to_physmap xatp; | ||
1291 | static struct shared_info *shared_info_page = 0; | ||
1292 | |||
1293 | if (!shared_info_page) | ||
1294 | shared_info_page = (struct shared_info *) | ||
1295 | extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
1296 | xatp.domid = DOMID_SELF; | ||
1297 | xatp.idx = 0; | ||
1298 | xatp.space = XENMAPSPACE_shared_info; | ||
1299 | xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; | ||
1300 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) | ||
1301 | BUG(); | ||
1302 | |||
1303 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; | ||
1304 | |||
1305 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
1306 | * page, we use it in the event channel upcall and in some pvclock | ||
1307 | * related functions. We don't need the vcpu_info placement | ||
1308 | * optimizations because we don't use any pv_mmu or pv_irq op on | ||
1309 | * HVM. | ||
1310 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is | ||
1311 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
1312 | * in that case multiple vcpus might be online. */ | ||
1313 | for_each_online_cpu(cpu) { | ||
1314 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1315 | } | ||
1316 | } | ||
1317 | |||
1318 | #ifdef CONFIG_XEN_PVHVM | ||
1319 | static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | ||
1320 | unsigned long action, void *hcpu) | ||
1321 | { | ||
1322 | int cpu = (long)hcpu; | ||
1323 | switch (action) { | ||
1324 | case CPU_UP_PREPARE: | ||
1325 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1326 | break; | ||
1327 | default: | ||
1328 | break; | ||
1329 | } | ||
1330 | return NOTIFY_OK; | ||
1331 | } | ||
1332 | |||
1333 | static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { | ||
1334 | .notifier_call = xen_hvm_cpu_notify, | ||
1335 | }; | ||
1336 | |||
1337 | static void __init xen_hvm_guest_init(void) | ||
1338 | { | ||
1339 | int r; | ||
1340 | int major, minor; | ||
1341 | |||
1342 | r = init_hvm_pv_info(&major, &minor); | ||
1343 | if (r < 0) | ||
1344 | return; | ||
1345 | |||
1346 | xen_hvm_init_shared_info(); | ||
1347 | |||
1348 | if (xen_feature(XENFEAT_hvm_callback_vector)) | ||
1349 | xen_have_vector_callback = 1; | ||
1350 | register_cpu_notifier(&xen_hvm_cpu_notifier); | ||
1351 | xen_unplug_emulated_devices(); | ||
1352 | have_vcpu_info_placement = 0; | ||
1353 | x86_init.irqs.intr_init = xen_init_IRQ; | ||
1354 | xen_hvm_init_time_ops(); | ||
1355 | xen_hvm_init_mmu_ops(); | ||
1356 | } | ||
1357 | |||
1358 | static bool __init xen_hvm_platform(void) | ||
1359 | { | ||
1360 | if (xen_pv_domain()) | ||
1361 | return false; | ||
1362 | |||
1363 | if (!xen_cpuid_base()) | ||
1364 | return false; | ||
1365 | |||
1366 | return true; | ||
1367 | } | ||
1368 | |||
1369 | const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { | ||
1370 | .name = "Xen HVM", | ||
1371 | .detect = xen_hvm_platform, | ||
1372 | .init_platform = xen_hvm_guest_init, | ||
1373 | }; | ||
1374 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | ||
1375 | #endif | ||