diff options
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 158 |
1 files changed, 146 insertions, 12 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 3c4da8bee06f..d4ff5e83621d 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. |
@@ -938,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = { | |||
938 | .patch = xen_patch, | 947 | .patch = xen_patch, |
939 | }; | 948 | }; |
940 | 949 | ||
941 | static const struct pv_time_ops xen_time_ops __initdata = { | ||
942 | .sched_clock = xen_clocksource_read, | ||
943 | }; | ||
944 | |||
945 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { | 950 | static const struct pv_cpu_ops xen_cpu_ops __initdata = { |
946 | .cpuid = xen_cpuid, | 951 | .cpuid = xen_cpuid, |
947 | 952 | ||
@@ -1096,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void) | |||
1096 | /* Install Xen paravirt ops */ | 1101 | /* Install Xen paravirt ops */ |
1097 | pv_info = xen_info; | 1102 | pv_info = xen_info; |
1098 | pv_init_ops = xen_init_ops; | 1103 | pv_init_ops = xen_init_ops; |
1099 | pv_time_ops = xen_time_ops; | ||
1100 | pv_cpu_ops = xen_cpu_ops; | 1104 | pv_cpu_ops = xen_cpu_ops; |
1101 | pv_apic_ops = xen_apic_ops; | 1105 | pv_apic_ops = xen_apic_ops; |
1102 | 1106 | ||
@@ -1104,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void) | |||
1104 | x86_init.oem.arch_setup = xen_arch_setup; | 1108 | x86_init.oem.arch_setup = xen_arch_setup; |
1105 | x86_init.oem.banner = xen_banner; | 1109 | x86_init.oem.banner = xen_banner; |
1106 | 1110 | ||
1107 | x86_init.timers.timer_init = xen_time_init; | 1111 | xen_init_time_ops(); |
1108 | x86_init.timers.setup_percpu_clockev = x86_init_noop; | ||
1109 | x86_cpuinit.setup_percpu_clockev = x86_init_noop; | ||
1110 | |||
1111 | x86_platform.calibrate_tsc = xen_tsc_khz; | ||
1112 | x86_platform.get_wallclock = xen_get_wallclock; | ||
1113 | x86_platform.set_wallclock = xen_set_wallclock; | ||
1114 | 1112 | ||
1115 | /* | 1113 | /* |
1116 | * Set up some pagetable state before starting to set any ptes. | 1114 | * Set up some pagetable state before starting to set any ptes. |
@@ -1235,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void) | |||
1235 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); | 1233 | x86_64_start_reservations((char *)__pa_symbol(&boot_params)); |
1236 | #endif | 1234 | #endif |
1237 | } | 1235 | } |
1236 | |||
1237 | static uint32_t xen_cpuid_base(void) | ||
1238 | { | ||
1239 | uint32_t base, eax, ebx, ecx, edx; | ||
1240 | char signature[13]; | ||
1241 | |||
1242 | for (base = 0x40000000; base < 0x40010000; base += 0x100) { | ||
1243 | cpuid(base, &eax, &ebx, &ecx, &edx); | ||
1244 | *(uint32_t *)(signature + 0) = ebx; | ||
1245 | *(uint32_t *)(signature + 4) = ecx; | ||
1246 | *(uint32_t *)(signature + 8) = edx; | ||
1247 | signature[12] = 0; | ||
1248 | |||
1249 | if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2)) | ||
1250 | return base; | ||
1251 | } | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int init_hvm_pv_info(int *major, int *minor) | ||
1257 | { | ||
1258 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | ||
1259 | u64 pfn; | ||
1260 | |||
1261 | base = xen_cpuid_base(); | ||
1262 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | ||
1263 | |||
1264 | *major = eax >> 16; | ||
1265 | *minor = eax & 0xffff; | ||
1266 | printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor); | ||
1267 | |||
1268 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | ||
1269 | |||
1270 | pfn = __pa(hypercall_page); | ||
1271 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
1272 | |||
1273 | xen_setup_features(); | ||
1274 | |||
1275 | pv_info = xen_info; | ||
1276 | pv_info.kernel_rpl = 0; | ||
1277 | |||
1278 | xen_domain_type = XEN_HVM_DOMAIN; | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | void xen_hvm_init_shared_info(void) | ||
1284 | { | ||
1285 | int cpu; | ||
1286 | struct xen_add_to_physmap xatp; | ||
1287 | static struct shared_info *shared_info_page = 0; | ||
1288 | |||
1289 | if (!shared_info_page) | ||
1290 | shared_info_page = (struct shared_info *) | ||
1291 | extend_brk(PAGE_SIZE, PAGE_SIZE); | ||
1292 | xatp.domid = DOMID_SELF; | ||
1293 | xatp.idx = 0; | ||
1294 | xatp.space = XENMAPSPACE_shared_info; | ||
1295 | xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; | ||
1296 | if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) | ||
1297 | BUG(); | ||
1298 | |||
1299 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; | ||
1300 | |||
1301 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
1302 | * page, we use it in the event channel upcall and in some pvclock | ||
1303 | * related functions. We don't need the vcpu_info placement | ||
1304 | * optimizations because we don't use any pv_mmu or pv_irq op on | ||
1305 | * HVM. | ||
1306 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is | ||
1307 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
1308 | * in that case multiple vcpus might be online. */ | ||
1309 | for_each_online_cpu(cpu) { | ||
1310 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | #ifdef CONFIG_XEN_PVHVM | ||
1315 | static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, | ||
1316 | unsigned long action, void *hcpu) | ||
1317 | { | ||
1318 | int cpu = (long)hcpu; | ||
1319 | switch (action) { | ||
1320 | case CPU_UP_PREPARE: | ||
1321 | per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; | ||
1322 | break; | ||
1323 | default: | ||
1324 | break; | ||
1325 | } | ||
1326 | return NOTIFY_OK; | ||
1327 | } | ||
1328 | |||
1329 | static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = { | ||
1330 | .notifier_call = xen_hvm_cpu_notify, | ||
1331 | }; | ||
1332 | |||
1333 | static void __init xen_hvm_guest_init(void) | ||
1334 | { | ||
1335 | int r; | ||
1336 | int major, minor; | ||
1337 | |||
1338 | r = init_hvm_pv_info(&major, &minor); | ||
1339 | if (r < 0) | ||
1340 | return; | ||
1341 | |||
1342 | xen_hvm_init_shared_info(); | ||
1343 | |||
1344 | if (xen_feature(XENFEAT_hvm_callback_vector)) | ||
1345 | xen_have_vector_callback = 1; | ||
1346 | register_cpu_notifier(&xen_hvm_cpu_notifier); | ||
1347 | xen_unplug_emulated_devices(); | ||
1348 | have_vcpu_info_placement = 0; | ||
1349 | x86_init.irqs.intr_init = xen_init_IRQ; | ||
1350 | xen_hvm_init_time_ops(); | ||
1351 | xen_hvm_init_mmu_ops(); | ||
1352 | } | ||
1353 | |||
1354 | static bool __init xen_hvm_platform(void) | ||
1355 | { | ||
1356 | if (xen_pv_domain()) | ||
1357 | return false; | ||
1358 | |||
1359 | if (!xen_cpuid_base()) | ||
1360 | return false; | ||
1361 | |||
1362 | return true; | ||
1363 | } | ||
1364 | |||
1365 | const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = { | ||
1366 | .name = "Xen HVM", | ||
1367 | .detect = xen_hvm_platform, | ||
1368 | .init_platform = xen_hvm_guest_init, | ||
1369 | }; | ||
1370 | EXPORT_SYMBOL(x86_hyper_xen_hvm); | ||
1371 | #endif | ||