diff options
-rw-r--r-- | arch/x86/xen/Kconfig | 2 | ||||
-rw-r--r-- | arch/x86/xen/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 124 | ||||
-rw-r--r-- | arch/x86/xen/xen-pvh.S | 161 | ||||
-rw-r--r-- | include/xen/xen.h | 5 |
5 files changed, 282 insertions, 11 deletions
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index c7b15f3e2cf3..76b6dbd627df 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
@@ -53,5 +53,5 @@ config XEN_DEBUG_FS | |||
53 | 53 | ||
54 | config XEN_PVH | 54 | config XEN_PVH |
55 | bool "Support for running as a PVH guest" | 55 | bool "Support for running as a PVH guest" |
56 | depends on X86_64 && XEN && XEN_PVHVM | 56 | depends on XEN && XEN_PVHVM && ACPI |
57 | def_bool n | 57 | def_bool n |
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile index e47e52787d32..cb0164aee156 100644 --- a/arch/x86/xen/Makefile +++ b/arch/x86/xen/Makefile | |||
@@ -23,3 +23,4 @@ obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o | |||
23 | obj-$(CONFIG_XEN_DOM0) += vga.o | 23 | obj-$(CONFIG_XEN_DOM0) += vga.o |
24 | obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o | 24 | obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o |
25 | obj-$(CONFIG_XEN_EFI) += efi.o | 25 | obj-$(CONFIG_XEN_EFI) += efi.o |
26 | obj-$(CONFIG_XEN_PVH) += xen-pvh.o | ||
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 828f1b226f56..d2144f7c8fab 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <xen/interface/memory.h> | 45 | #include <xen/interface/memory.h> |
46 | #include <xen/interface/nmi.h> | 46 | #include <xen/interface/nmi.h> |
47 | #include <xen/interface/xen-mca.h> | 47 | #include <xen/interface/xen-mca.h> |
48 | #include <xen/interface/hvm/start_info.h> | ||
48 | #include <xen/features.h> | 49 | #include <xen/features.h> |
49 | #include <xen/page.h> | 50 | #include <xen/page.h> |
50 | #include <xen/hvm.h> | 51 | #include <xen/hvm.h> |
@@ -176,6 +177,20 @@ struct tls_descs { | |||
176 | */ | 177 | */ |
177 | static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc); | 178 | static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc); |
178 | 179 | ||
180 | #ifdef CONFIG_XEN_PVH | ||
181 | /* | ||
182 | * PVH variables. | ||
183 | * | ||
184 | * xen_pvh and pvh_bootparams need to live in data segment since they | ||
185 | * are used after startup_{32|64}, which clear .bss, are invoked. | ||
186 | */ | ||
187 | bool xen_pvh __attribute__((section(".data"))) = 0; | ||
188 | struct boot_params pvh_bootparams __attribute__((section(".data"))); | ||
189 | |||
190 | struct hvm_start_info pvh_start_info; | ||
191 | unsigned int pvh_start_info_sz = sizeof(pvh_start_info); | ||
192 | #endif | ||
193 | |||
179 | static void clamp_max_cpus(void) | 194 | static void clamp_max_cpus(void) |
180 | { | 195 | { |
181 | #ifdef CONFIG_SMP | 196 | #ifdef CONFIG_SMP |
@@ -1656,6 +1671,90 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
1656 | #endif | 1671 | #endif |
1657 | } | 1672 | } |
1658 | 1673 | ||
1674 | #ifdef CONFIG_XEN_PVH | ||
1675 | static void __init init_pvh_bootparams(void) | ||
1676 | { | ||
1677 | struct xen_memory_map memmap; | ||
1678 | unsigned int i; | ||
1679 | int rc; | ||
1680 | |||
1681 | memset(&pvh_bootparams, 0, sizeof(pvh_bootparams)); | ||
1682 | |||
1683 | memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_map); | ||
1684 | set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_map); | ||
1685 | rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); | ||
1686 | if (rc) { | ||
1687 | xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc); | ||
1688 | BUG(); | ||
1689 | } | ||
1690 | |||
1691 | if (memmap.nr_entries < E820MAX - 1) { | ||
1692 | pvh_bootparams.e820_map[memmap.nr_entries].addr = | ||
1693 | ISA_START_ADDRESS; | ||
1694 | pvh_bootparams.e820_map[memmap.nr_entries].size = | ||
1695 | ISA_END_ADDRESS - ISA_START_ADDRESS; | ||
1696 | pvh_bootparams.e820_map[memmap.nr_entries].type = | ||
1697 | E820_RESERVED; | ||
1698 | memmap.nr_entries++; | ||
1699 | } else | ||
1700 | xen_raw_printk("Warning: Can fit ISA range into e820\n"); | ||
1701 | |||
1702 | sanitize_e820_map(pvh_bootparams.e820_map, | ||
1703 | ARRAY_SIZE(pvh_bootparams.e820_map), | ||
1704 | &memmap.nr_entries); | ||
1705 | |||
1706 | pvh_bootparams.e820_entries = memmap.nr_entries; | ||
1707 | for (i = 0; i < pvh_bootparams.e820_entries; i++) | ||
1708 | e820_add_region(pvh_bootparams.e820_map[i].addr, | ||
1709 | pvh_bootparams.e820_map[i].size, | ||
1710 | pvh_bootparams.e820_map[i].type); | ||
1711 | |||
1712 | pvh_bootparams.hdr.cmd_line_ptr = | ||
1713 | pvh_start_info.cmdline_paddr; | ||
1714 | |||
1715 | /* The first module is always ramdisk. */ | ||
1716 | if (pvh_start_info.nr_modules) { | ||
1717 | struct hvm_modlist_entry *modaddr = | ||
1718 | __va(pvh_start_info.modlist_paddr); | ||
1719 | pvh_bootparams.hdr.ramdisk_image = modaddr->paddr; | ||
1720 | pvh_bootparams.hdr.ramdisk_size = modaddr->size; | ||
1721 | } | ||
1722 | |||
1723 | /* | ||
1724 | * See Documentation/x86/boot.txt. | ||
1725 | * | ||
1726 | * Version 2.12 supports Xen entry point but we will use default x86/PC | ||
1727 | * environment (i.e. hardware_subarch 0). | ||
1728 | */ | ||
1729 | pvh_bootparams.hdr.version = 0x212; | ||
1730 | pvh_bootparams.hdr.type_of_loader = (9 << 4) | 0; /* Xen loader */ | ||
1731 | } | ||
1732 | |||
1733 | /* | ||
1734 | * This routine (and those that it might call) should not use | ||
1735 | * anything that lives in .bss since that segment will be cleared later. | ||
1736 | */ | ||
1737 | void __init xen_prepare_pvh(void) | ||
1738 | { | ||
1739 | u32 msr; | ||
1740 | u64 pfn; | ||
1741 | |||
1742 | if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) { | ||
1743 | xen_raw_printk("Error: Unexpected magic value (0x%08x)\n", | ||
1744 | pvh_start_info.magic); | ||
1745 | BUG(); | ||
1746 | } | ||
1747 | |||
1748 | xen_pvh = 1; | ||
1749 | |||
1750 | msr = cpuid_ebx(xen_cpuid_base() + 2); | ||
1751 | pfn = __pa(hypercall_page); | ||
1752 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
1753 | |||
1754 | init_pvh_bootparams(); | ||
1755 | } | ||
1756 | #endif | ||
1757 | |||
1659 | void __ref xen_hvm_init_shared_info(void) | 1758 | void __ref xen_hvm_init_shared_info(void) |
1660 | { | 1759 | { |
1661 | int cpu; | 1760 | int cpu; |
@@ -1695,20 +1794,29 @@ void __ref xen_hvm_init_shared_info(void) | |||
1695 | static void __init init_hvm_pv_info(void) | 1794 | static void __init init_hvm_pv_info(void) |
1696 | { | 1795 | { |
1697 | int major, minor; | 1796 | int major, minor; |
1698 | uint32_t eax, ebx, ecx, edx, pages, msr, base; | 1797 | uint32_t eax, ebx, ecx, edx, base; |
1699 | u64 pfn; | ||
1700 | 1798 | ||
1701 | base = xen_cpuid_base(); | 1799 | base = xen_cpuid_base(); |
1702 | cpuid(base + 1, &eax, &ebx, &ecx, &edx); | 1800 | eax = cpuid_eax(base + 1); |
1703 | 1801 | ||
1704 | major = eax >> 16; | 1802 | major = eax >> 16; |
1705 | minor = eax & 0xffff; | 1803 | minor = eax & 0xffff; |
1706 | printk(KERN_INFO "Xen version %d.%d.\n", major, minor); | 1804 | printk(KERN_INFO "Xen version %d.%d.\n", major, minor); |
1707 | 1805 | ||
1708 | cpuid(base + 2, &pages, &msr, &ecx, &edx); | 1806 | xen_domain_type = XEN_HVM_DOMAIN; |
1709 | 1807 | ||
1710 | pfn = __pa(hypercall_page); | 1808 | /* PVH set up hypercall page in xen_prepare_pvh(). */ |
1711 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | 1809 | if (xen_pvh_domain()) |
1810 | pv_info.name = "Xen PVH"; | ||
1811 | else { | ||
1812 | u64 pfn; | ||
1813 | uint32_t msr; | ||
1814 | |||
1815 | pv_info.name = "Xen HVM"; | ||
1816 | msr = cpuid_ebx(base + 2); | ||
1817 | pfn = __pa(hypercall_page); | ||
1818 | wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); | ||
1819 | } | ||
1712 | 1820 | ||
1713 | xen_setup_features(); | 1821 | xen_setup_features(); |
1714 | 1822 | ||
@@ -1717,10 +1825,6 @@ static void __init init_hvm_pv_info(void) | |||
1717 | this_cpu_write(xen_vcpu_id, ebx); | 1825 | this_cpu_write(xen_vcpu_id, ebx); |
1718 | else | 1826 | else |
1719 | this_cpu_write(xen_vcpu_id, smp_processor_id()); | 1827 | this_cpu_write(xen_vcpu_id, smp_processor_id()); |
1720 | |||
1721 | pv_info.name = "Xen HVM"; | ||
1722 | |||
1723 | xen_domain_type = XEN_HVM_DOMAIN; | ||
1724 | } | 1828 | } |
1725 | #endif | 1829 | #endif |
1726 | 1830 | ||
diff --git a/arch/x86/xen/xen-pvh.S b/arch/x86/xen/xen-pvh.S new file mode 100644 index 000000000000..5e246716d58f --- /dev/null +++ b/arch/x86/xen/xen-pvh.S | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Copyright C 2016, Oracle and/or its affiliates. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | .code32 | ||
19 | .text | ||
20 | #define _pa(x) ((x) - __START_KERNEL_map) | ||
21 | |||
22 | #include <linux/elfnote.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/linkage.h> | ||
25 | #include <asm/segment.h> | ||
26 | #include <asm/asm.h> | ||
27 | #include <asm/boot.h> | ||
28 | #include <asm/processor-flags.h> | ||
29 | #include <asm/msr.h> | ||
30 | #include <xen/interface/elfnote.h> | ||
31 | |||
32 | __HEAD | ||
33 | |||
34 | /* | ||
35 | * Entry point for PVH guests. | ||
36 | * | ||
37 | * Xen ABI specifies the following register state when we come here: | ||
38 | * | ||
39 | * - `ebx`: contains the physical memory address where the loader has placed | ||
40 | * the boot start info structure. | ||
41 | * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared. | ||
42 | * - `cr4`: all bits are cleared. | ||
43 | * - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’ | ||
44 | * and a limit of ‘0xFFFFFFFF’. The selector value is unspecified. | ||
45 | * - `ds`, `es`: must be a 32-bit read/write data segment with a base of | ||
46 | * ‘0’ and a limit of ‘0xFFFFFFFF’. The selector values are all | ||
47 | * unspecified. | ||
48 | * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit | ||
49 | * of '0x67'. | ||
50 | * - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared. | ||
51 | * Bit 8 (TF) must be cleared. Other bits are all unspecified. | ||
52 | * | ||
53 | * All other processor registers and flag bits are unspecified. The OS is in | ||
54 | * charge of setting up it's own stack, GDT and IDT. | ||
55 | */ | ||
56 | |||
57 | ENTRY(pvh_start_xen) | ||
58 | cld | ||
59 | |||
60 | lgdt (_pa(gdt)) | ||
61 | |||
62 | mov $(__BOOT_DS),%eax | ||
63 | mov %eax,%ds | ||
64 | mov %eax,%es | ||
65 | mov %eax,%ss | ||
66 | |||
67 | /* Stash hvm_start_info. */ | ||
68 | mov $_pa(pvh_start_info), %edi | ||
69 | mov %ebx, %esi | ||
70 | mov _pa(pvh_start_info_sz), %ecx | ||
71 | shr $2,%ecx | ||
72 | rep | ||
73 | movsl | ||
74 | |||
75 | mov $_pa(early_stack_end), %esp | ||
76 | |||
77 | /* Enable PAE mode. */ | ||
78 | mov %cr4, %eax | ||
79 | orl $X86_CR4_PAE, %eax | ||
80 | mov %eax, %cr4 | ||
81 | |||
82 | #ifdef CONFIG_X86_64 | ||
83 | /* Enable Long mode. */ | ||
84 | mov $MSR_EFER, %ecx | ||
85 | rdmsr | ||
86 | btsl $_EFER_LME, %eax | ||
87 | wrmsr | ||
88 | |||
89 | /* Enable pre-constructed page tables. */ | ||
90 | mov $_pa(init_level4_pgt), %eax | ||
91 | mov %eax, %cr3 | ||
92 | mov $(X86_CR0_PG | X86_CR0_PE), %eax | ||
93 | mov %eax, %cr0 | ||
94 | |||
95 | /* Jump to 64-bit mode. */ | ||
96 | ljmp $__KERNEL_CS, $_pa(1f) | ||
97 | |||
98 | /* 64-bit entry point. */ | ||
99 | .code64 | ||
100 | 1: | ||
101 | call xen_prepare_pvh | ||
102 | |||
103 | /* startup_64 expects boot_params in %rsi. */ | ||
104 | mov $_pa(pvh_bootparams), %rsi | ||
105 | mov $_pa(startup_64), %rax | ||
106 | jmp *%rax | ||
107 | |||
108 | #else /* CONFIG_X86_64 */ | ||
109 | |||
110 | call mk_early_pgtbl_32 | ||
111 | |||
112 | mov $_pa(initial_page_table), %eax | ||
113 | mov %eax, %cr3 | ||
114 | |||
115 | mov %cr0, %eax | ||
116 | or $(X86_CR0_PG | X86_CR0_PE), %eax | ||
117 | mov %eax, %cr0 | ||
118 | |||
119 | ljmp $__BOOT_CS, $1f | ||
120 | 1: | ||
121 | call xen_prepare_pvh | ||
122 | mov $_pa(pvh_bootparams), %esi | ||
123 | |||
124 | /* startup_32 doesn't expect paging and PAE to be on. */ | ||
125 | ljmp $__BOOT_CS, $_pa(2f) | ||
126 | 2: | ||
127 | mov %cr0, %eax | ||
128 | and $~X86_CR0_PG, %eax | ||
129 | mov %eax, %cr0 | ||
130 | mov %cr4, %eax | ||
131 | and $~X86_CR4_PAE, %eax | ||
132 | mov %eax, %cr4 | ||
133 | |||
134 | ljmp $__BOOT_CS, $_pa(startup_32) | ||
135 | #endif | ||
136 | END(pvh_start_xen) | ||
137 | |||
138 | .section ".init.data","aw" | ||
139 | .balign 8 | ||
140 | gdt: | ||
141 | .word gdt_end - gdt_start | ||
142 | .long _pa(gdt_start) | ||
143 | .word 0 | ||
144 | gdt_start: | ||
145 | .quad 0x0000000000000000 /* NULL descriptor */ | ||
146 | .quad 0x0000000000000000 /* reserved */ | ||
147 | #ifdef CONFIG_X86_64 | ||
148 | .quad GDT_ENTRY(0xa09a, 0, 0xfffff) /* __KERNEL_CS */ | ||
149 | #else | ||
150 | .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* __KERNEL_CS */ | ||
151 | #endif | ||
152 | .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* __KERNEL_DS */ | ||
153 | gdt_end: | ||
154 | |||
155 | .balign 4 | ||
156 | early_stack: | ||
157 | .fill 256, 1, 0 | ||
158 | early_stack_end: | ||
159 | |||
160 | ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, | ||
161 | _ASM_PTR (pvh_start_xen - __START_KERNEL_map)) | ||
diff --git a/include/xen/xen.h b/include/xen/xen.h index d0f96840f71f..6e8b7fc79801 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h | |||
@@ -29,6 +29,11 @@ extern enum xen_domain_type xen_domain_type; | |||
29 | #define xen_initial_domain() (0) | 29 | #define xen_initial_domain() (0) |
30 | #endif /* CONFIG_XEN_DOM0 */ | 30 | #endif /* CONFIG_XEN_DOM0 */ |
31 | 31 | ||
32 | #ifdef CONFIG_XEN_PVH | ||
33 | extern bool xen_pvh; | ||
34 | #define xen_pvh_domain() (xen_hvm_domain() && xen_pvh) | ||
35 | #else | ||
32 | #define xen_pvh_domain() (0) | 36 | #define xen_pvh_domain() (0) |
37 | #endif | ||
33 | 38 | ||
34 | #endif /* _XEN_XEN_H */ | 39 | #endif /* _XEN_XEN_H */ |