summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-02-05 19:50:52 -0500
committerBoris Ostrovsky <boris.ostrovsky@oracle.com>2017-02-07 08:07:01 -0500
commit7243b93345f7f8de260e8f5b4670803e64fcbb00 (patch)
treec288ff735a3e39745b91a3870b2d956fcce5429b
parentcee2cfb7d18db1d7bcd0952b5e0e3f19c004023c (diff)
xen/pvh: Bootstrap PVH guest
Start PVH guest at XEN_ELFNOTE_PHYS32_ENTRY address. Setup hypercall page, initialize boot_params, enable early page tables. Since this stub is executed before kernel entry point we cannot use variables in .bss which is cleared by kernel. We explicitly place variables that are initialized here into .data. While adjusting xen_hvm_init_shared_info() make it use cpuid_e?x() instead of cpuid() (wherever possible). Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Reviewed-by: Juergen Gross <jgross@suse.com>
-rw-r--r--arch/x86/xen/Kconfig2
-rw-r--r--arch/x86/xen/Makefile1
-rw-r--r--arch/x86/xen/enlighten.c124
-rw-r--r--arch/x86/xen/xen-pvh.S161
-rw-r--r--include/xen/xen.h5
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
54config XEN_PVH 54config 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
23obj-$(CONFIG_XEN_DOM0) += vga.o 23obj-$(CONFIG_XEN_DOM0) += vga.o
24obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o 24obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
25obj-$(CONFIG_XEN_EFI) += efi.o 25obj-$(CONFIG_XEN_EFI) += efi.o
26obj-$(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 */
177static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc); 178static 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 */
187bool xen_pvh __attribute__((section(".data"))) = 0;
188struct boot_params pvh_bootparams __attribute__((section(".data")));
189
190struct hvm_start_info pvh_start_info;
191unsigned int pvh_start_info_sz = sizeof(pvh_start_info);
192#endif
193
179static void clamp_max_cpus(void) 194static 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
1675static 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 */
1737void __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
1659void __ref xen_hvm_init_shared_info(void) 1758void __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)
1695static void __init init_hvm_pv_info(void) 1794static 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
57ENTRY(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
1001:
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
1201:
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)
1262:
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
136END(pvh_start_xen)
137
138 .section ".init.data","aw"
139 .balign 8
140gdt:
141 .word gdt_end - gdt_start
142 .long _pa(gdt_start)
143 .word 0
144gdt_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 */
153gdt_end:
154
155 .balign 4
156early_stack:
157 .fill 256, 1, 0
158early_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
33extern 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 */