Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / head-xen.c
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/memblock.h>
4 #include <linux/pci.h>
5
6 #include <asm/setup.h>
7 #ifndef CONFIG_XEN
8 #include <asm/bios_ebda.h>
9
10 #define BIOS_LOWMEM_KILOBYTES 0x413
11
12 /*
13  * The BIOS places the EBDA/XBDA at the top of conventional
14  * memory, and usually decreases the reported amount of
15  * conventional memory (int 0x12) too. This also contains a
16  * workaround for Dell systems that neglect to reserve EBDA.
17  * The same workaround also avoids a problem with the AMD768MPX
18  * chipset: reserve a page before VGA to prevent PCI prefetch
19  * into it (errata #56). Usually the page is reserved anyways,
20  * unless you have no PS/2 mouse plugged in.
21  */
22 void __init reserve_ebda_region(void)
23 {
24         unsigned int lowmem, ebda_addr;
25
26         /* To determine the position of the EBDA and the */
27         /* end of conventional memory, we need to look at */
28         /* the BIOS data area. In a paravirtual environment */
29         /* that area is absent. We'll just have to assume */
30         /* that the paravirt case can handle memory setup */
31         /* correctly, without our help. */
32         if (paravirt_enabled())
33                 return;
34
35         /* end of low (conventional) memory */
36         lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES);
37         lowmem <<= 10;
38
39         /* start of EBDA area */
40         ebda_addr = get_bios_ebda();
41
42         /* Fixup: bios puts an EBDA in the top 64K segment */
43         /* of conventional memory, but does not adjust lowmem. */
44         if ((lowmem - ebda_addr) <= 0x10000)
45                 lowmem = ebda_addr;
46
47         /* Fixup: bios does not report an EBDA at all. */
48         /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
49         if ((ebda_addr == 0) && (lowmem >= 0x9f000))
50                 lowmem = 0x9f000;
51
52         /* Paranoia: should never happen, but... */
53         if ((lowmem == 0) || (lowmem >= 0x100000))
54                 lowmem = 0x9f000;
55
56         /* reserve all memory between lowmem and the 1MB mark */
57         memblock_reserve(lowmem, 0x100000 - lowmem);
58 }
59 #else /* CONFIG_XEN */
60 #include <linux/export.h>
61 #include <asm/fixmap.h>
62 #include <asm/mc146818rtc.h>
63 #include <asm/pgtable.h>
64 #include <asm/sections.h>
65 #include <xen/interface/callback.h>
66 #include <xen/interface/memory.h>
67
68 extern void hypervisor_callback(void);
69 extern void failsafe_callback(void);
70 extern void nmi(void);
71
72 #ifdef CONFIG_X86_64
73 #include <asm/proto.h>
74 #define CALLBACK_ADDR(fn) ((unsigned long)(fn))
75 #else
76 #define CALLBACK_ADDR(fn) { __KERNEL_CS, (unsigned long)(fn) }
77 #endif
78
79 unsigned long __initdata xen_initrd_start;
80
81 unsigned long *__read_mostly machine_to_phys_mapping =
82         (void *)MACH2PHYS_VIRT_START;
83 EXPORT_SYMBOL(machine_to_phys_mapping);
84 unsigned long __read_mostly machine_to_phys_nr;
85 EXPORT_SYMBOL(machine_to_phys_nr);
86
87 void __init xen_start_kernel(void)
88 {
89         unsigned int i;
90         struct xen_machphys_mapping mapping;
91
92         xen_setup_features();
93
94         if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
95                 machine_to_phys_mapping = (unsigned long *)mapping.v_start;
96                 machine_to_phys_nr = mapping.max_mfn + 1;
97         } else
98                 machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
99 #ifdef CONFIG_X86_32
100         WARN_ON(machine_to_phys_mapping + (machine_to_phys_nr - 1)
101                 < machine_to_phys_mapping);
102 #endif
103
104         if (!xen_feature(XENFEAT_auto_translated_physmap))
105                 phys_to_machine_mapping =
106                         (unsigned long *)xen_start_info->mfn_list;
107
108         WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable,
109                                      VMASST_TYPE_writable_pagetables));
110
111         memblock_reserve(ALIGN(__pa_symbol(&_end), PAGE_SIZE),
112                          __pa(xen_start_info->pt_base)
113                          + PFN_PHYS(xen_start_info->nr_pt_frames));
114
115 #ifdef CONFIG_X86_32
116 {
117         extern pte_t swapper_pg_fixmap[PTRS_PER_PTE];
118         unsigned long addr;
119
120         /* Do an early initialization of the fixmap area */
121         make_lowmem_page_readonly(swapper_pg_fixmap, XENFEAT_writable_page_tables);
122         addr = __fix_to_virt(FIX_EARLYCON_MEM_BASE);
123         set_pmd(pmd_offset(pud_offset(swapper_pg_dir + pgd_index(addr),
124                                       addr),
125                            addr),
126                 __pmd(__pa_symbol(swapper_pg_fixmap) | _PAGE_TABLE));
127 }
128 #else
129         x86_configure_nx();
130         xen_init_pt();
131 #endif
132
133 #define __FIXADDR_TOP (-PAGE_SIZE)
134 #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
135 #define FIX_BUG_ON(fix) BUILD_BUG_ON(pmd_index(__fix_to_virt(FIX_##fix)) \
136                         != pmd_index(__fix_to_virt(FIX_EARLYCON_MEM_BASE)))
137         FIX_BUG_ON(SHARED_INFO);
138         FIX_BUG_ON(ISAMAP_BEGIN);
139         FIX_BUG_ON(ISAMAP_END);
140 #undef pmd_index
141 #undef __FIXADDR_TOP
142
143         /* Switch to the real shared_info page, and clear the dummy page. */
144         set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
145         HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
146         clear_page(empty_zero_page);
147
148         setup_vcpu_info(0);
149
150         /* Set up mapping of lowest 1MB of physical memory. */
151         for (i = 0; i < NR_FIX_ISAMAPS; i++)
152                 if (is_initial_xendomain())
153                         set_fixmap(FIX_ISAMAP_BEGIN - i, i * PAGE_SIZE);
154                 else
155                         __set_fixmap(FIX_ISAMAP_BEGIN - i,
156                                      virt_to_machine(empty_zero_page),
157                                      PAGE_KERNEL_RO);
158
159         if (is_initial_xendomain()) {
160                 x86_platform.get_wallclock = mach_get_cmos_time;
161                 x86_platform.set_wallclock = mach_set_rtc_mmss;
162
163                 pci_request_acs();
164         } else
165                 x86_init.resources.probe_roms = x86_init_noop;
166 }
167
168 void __init xen_arch_setup(void)
169 {
170         int ret;
171         static const struct callback_register __initconst event = {
172                 .type = CALLBACKTYPE_event,
173                 .address = CALLBACK_ADDR(hypervisor_callback)
174         };
175         static const struct callback_register __initconst failsafe = {
176                 .type = CALLBACKTYPE_failsafe,
177                 .address = CALLBACK_ADDR(failsafe_callback)
178         };
179 #ifdef CONFIG_X86_64
180         static const struct callback_register __initconst syscall = {
181                 .type = CALLBACKTYPE_syscall,
182                 .address = CALLBACK_ADDR(system_call)
183         };
184 #endif
185         static const struct callback_register __initconst nmi_cb = {
186                 .type = CALLBACKTYPE_nmi,
187                 .address = CALLBACK_ADDR(nmi)
188         };
189
190         ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
191         if (ret == 0)
192                 ret = HYPERVISOR_callback_op(CALLBACKOP_register, &failsafe);
193 #ifdef CONFIG_X86_64
194         if (ret == 0)
195                 ret = HYPERVISOR_callback_op(CALLBACKOP_register, &syscall);
196 #endif
197 #if CONFIG_XEN_COMPAT <= 0x030002
198 #ifdef CONFIG_X86_32
199         if (ret == -ENOSYS)
200                 ret = HYPERVISOR_set_callbacks(
201                         event.address.cs, event.address.eip,
202                         failsafe.address.cs, failsafe.address.eip);
203 #else
204                 ret = HYPERVISOR_set_callbacks(
205                         event.address,
206                         failsafe.address,
207                         syscall.address);
208 #endif
209 #endif
210         BUG_ON(ret);
211
212         ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
213 #if CONFIG_XEN_COMPAT <= 0x030002
214         if (ret == -ENOSYS) {
215                 static struct xennmi_callback __initdata cb = {
216                         .handler_address = (unsigned long)nmi
217                 };
218
219                 HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
220         }
221 #endif
222 }
223 #endif /* CONFIG_XEN */