aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */