ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw_utils.c @ 16785:af3550f53874

[IA64] domheap: Don't pin xenheap down. Now it's unnecessary.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Thu Jan 17 12:05:43 2008 -0700 (2008-01-17)
parents c5f735271e22
children
line source
1 /******************************************************************************
2 *
3 * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp>
4 * VA Linux Systems Japan K.K.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
22 #include <xen/types.h>
23 #include <xen/version.h>
24 #include <xen/errno.h>
25 #include <xen/sched.h>
27 #include <asm/fpswa.h>
28 #include <asm/dom_fw.h>
29 #include <asm/dom_fw_common.h>
30 #include <asm/dom_fw_utils.h>
32 #include <linux/sort.h>
34 uint32_t xen_ia64_version(struct domain *unused)
35 {
36 return (xen_major_version() << 16) | xen_minor_version();
37 }
39 int xen_ia64_fpswa_revision(struct domain *d, unsigned int *revision)
40 {
41 if (fpswa_interface == NULL)
42 return -ENOSYS;
44 *revision = fpswa_interface->revision;
45 return 0;
46 }
48 int xen_ia64_is_vcpu_allocated(struct domain *d, uint32_t vcpu)
49 {
50 return d->vcpu[vcpu] != NULL;
51 }
53 int xen_ia64_is_running_on_sim(struct domain *unused)
54 {
55 return running_on_sim;
56 }
58 int xen_ia64_is_dom0(struct domain *d)
59 {
60 return d == dom0;
61 }
63 void xen_ia64_set_convmem_end(struct domain *d, uint64_t convmem_end)
64 {
65 d->arch.convmem_end = convmem_end;
66 }
68 static void dom_fw_domain_init(struct domain *d, struct fw_tables *tables)
69 {
70 /* Initialise for EFI_SET_VIRTUAL_ADDRESS_MAP emulation */
71 d->arch.efi_runtime = &tables->efi_runtime;
72 d->arch.fpswa_inf = &tables->fpswa_inf;
73 d->arch.sal_data = &tables->sal_data;
74 }
76 static int dom_fw_set_convmem_end(struct domain *d)
77 {
78 unsigned long gpaddr;
79 size_t size;
80 xen_ia64_memmap_info_t *memmap_info;
81 efi_memory_desc_t *md;
82 void *p;
83 void *memmap_start;
84 void *memmap_end;
86 if (d->shared_info->arch.memmap_info_pfn == 0)
87 return -EINVAL;
89 gpaddr = d->shared_info->arch.memmap_info_pfn << PAGE_SHIFT;
90 size = d->shared_info->arch.memmap_info_num_pages << PAGE_SHIFT;
91 memmap_info = _xmalloc(size, __alignof__(*memmap_info));
92 if (memmap_info == NULL)
93 return -ENOMEM;
94 dom_fw_copy_from(memmap_info, d, gpaddr, size);
95 if (memmap_info->efi_memmap_size == 0 ||
96 memmap_info->efi_memdesc_size != sizeof(*md) ||
97 memmap_info->efi_memdesc_version != EFI_MEMORY_DESCRIPTOR_VERSION ||
98 sizeof(*memmap_info) + memmap_info->efi_memmap_size > size ||
99 memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size == 0) {
100 xfree(memmap_info);
101 return -EINVAL;
102 }
104 memmap_start = &memmap_info->memdesc;
105 memmap_end = memmap_start + memmap_info->efi_memmap_size;
107 /* sort it bofore use
108 * XXX: this is created by user space domain builder so that
109 * we should check its integrity */
110 sort(&memmap_info->memdesc,
111 memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size,
112 memmap_info->efi_memdesc_size, efi_mdt_cmp, NULL);
114 if (d->arch.convmem_end == 0)
115 xen_ia64_set_convmem_end(d, d->max_pages << PAGE_SHIFT);
117 for (p = memmap_start; p < memmap_end;
118 p += memmap_info->efi_memdesc_size) {
119 unsigned long end;
121 md = p;
122 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
124 if (md->attribute == EFI_MEMORY_WB &&
125 md->type == EFI_CONVENTIONAL_MEMORY &&
126 md->num_pages > 0 && d->arch.convmem_end < end)
127 xen_ia64_set_convmem_end(d, end);
128 }
130 dom_fw_copy_to(d, gpaddr, memmap_info, size);
131 xfree(memmap_info);
132 return 0;
133 }
135 /* allocate a page for fw
136 * guest_setup() @ libxc/xc_linux_build.c does for domU
137 */
138 static inline void
139 assign_new_domain_page_if_dom0(struct domain *d, unsigned long mpaddr)
140 {
141 if (d == dom0)
142 assign_new_domain0_page(d, mpaddr);
143 }
145 static void dom_fw_setup_for_domain_restore(domain_t * d, unsigned long maxmem)
146 {
147 assign_new_domain_page(d, FW_HYPERCALL_BASE_PADDR);
148 dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR));
149 xen_ia64_set_convmem_end(d, maxmem);
150 }
152 /* copy memory range to domain pseudo physical address space */
153 void
154 dom_fw_copy_to(struct domain *d, unsigned long dest_gpaddr,
155 void *src, size_t size)
156 {
157 while (size > 0) {
158 unsigned long page_offset = dest_gpaddr & ~PAGE_MASK;
159 size_t copy_size = size;
160 void *dest;
162 if (page_offset + copy_size > PAGE_SIZE)
163 copy_size = PAGE_SIZE - page_offset;
164 dest = domain_mpa_to_imva(d, dest_gpaddr);
165 memcpy(dest, src, copy_size);
167 src += copy_size;
168 dest_gpaddr += copy_size;
169 size -= copy_size;
170 }
171 }
173 /* copy memory range from domain pseudo physical address space */
174 void
175 dom_fw_copy_from(void *dest, struct domain *d, unsigned long src_gpaddr,
176 size_t size)
177 {
178 while (size > 0) {
179 unsigned long page_offset = src_gpaddr & ~PAGE_MASK;
180 size_t copy_size = size;
181 void *src;
183 if (page_offset + copy_size > PAGE_SIZE)
184 copy_size = PAGE_SIZE - page_offset;
185 src = domain_mpa_to_imva(d, src_gpaddr);
186 memcpy(dest, src, copy_size);
188 dest += copy_size;
189 src_gpaddr += copy_size;
190 size -= copy_size;
191 }
192 }
194 int dom_fw_setup(domain_t * d, unsigned long bp_mpa, unsigned long maxmem)
195 {
196 int old_domu_builder = 0;
197 struct xen_ia64_boot_param *bp;
199 BUILD_BUG_ON(sizeof(struct fw_tables) >
200 (FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR));
202 if (bp_mpa == 0) {
203 /* bp_mpa == 0 means this is domain restore case. */
204 dom_fw_setup_for_domain_restore(d, maxmem);
205 return 0;
206 }
208 /* Create page for boot_param. */
209 assign_new_domain_page_if_dom0(d, bp_mpa);
210 bp = domain_mpa_to_imva(d, bp_mpa);
211 if (d != dom0) {
212 /*
213 * XXX kludge.
214 * when XEN_DOMCTL_arch_setup is called, shared_info can't
215 * be accessed by libxc so that memmap_info_pfn isn't
216 * initialized. But dom_fw_set_convmem_end() requires it,
217 * so here we initialize it.
218 * note: domain builder may overwrite memmap_info_num_pages,
219 * memmap_info_pfns later.
220 */
221 if (bp->efi_memmap_size == 0 ||
222 XEN_IA64_MEMMAP_INFO_NUM_PAGES(bp) == 0 ||
223 XEN_IA64_MEMMAP_INFO_PFN(bp) == 0) {
224 /* old domain builder compatibility */
225 d->shared_info->arch.memmap_info_num_pages = 1;
226 d->shared_info->arch.memmap_info_pfn =
227 (maxmem >> PAGE_SHIFT) - 1;
228 old_domu_builder = 1;
229 } else {
230 d->shared_info->arch.memmap_info_num_pages =
231 XEN_IA64_MEMMAP_INFO_NUM_PAGES(bp);
232 d->shared_info->arch.memmap_info_pfn =
233 XEN_IA64_MEMMAP_INFO_PFN(bp);
234 /* currently multi page memmap isn't supported */
235 if (d->shared_info->arch.memmap_info_num_pages != 1)
236 return -ENOSYS;
237 }
238 }
240 /* Create page for acpi tables. */
241 if (d != dom0 && old_domu_builder) {
242 struct fake_acpi_tables *imva;
243 imva = domain_mpa_to_imva(d, FW_ACPI_BASE_PADDR);
244 dom_fw_fake_acpi(d, imva);
245 }
246 if (d == dom0 || old_domu_builder) {
247 int ret;
248 unsigned long imva_hypercall_base;
249 size_t fw_tables_size;
250 struct fw_tables *fw_tables;
251 unsigned long gpaddr;
253 /* Create page for hypercalls. */
254 assign_new_domain_page_if_dom0(d, FW_HYPERCALL_BASE_PADDR);
255 imva_hypercall_base = (unsigned long)domain_mpa_to_imva
256 (d, FW_HYPERCALL_BASE_PADDR);
258 /*
259 * dom_fw_init()
260 * - [FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR)
261 * - [FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR)
262 * - [FW_TABLES_BASE_PADDR, tables->fw_tables_end_paddr)
263 *
264 * complete_dom0_memmap() for dom0
265 * - real machine memory map
266 * - memmap_info by setup_dom0_memmap_info()
267 *
268 * complete_domu_memmap() for old domu builder
269 * - I/O port
270 * - conventional memory
271 * - memmap_info
272 */
273 #define NUM_EXTRA_MEM_DESCS 4
275 /* Estimate necessary efi memmap size and allocate memory */
276 fw_tables_size = sizeof(*fw_tables) +
277 (ia64_boot_param->efi_memmap_size /
278 ia64_boot_param->efi_memdesc_size +
279 NUM_EXTRA_MEM_DESCS) *
280 sizeof(fw_tables->efi_memmap[0]);
281 if (fw_tables_size <
282 FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR)
283 fw_tables_size =
284 FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR;
285 fw_tables_size = (fw_tables_size + ((1UL << EFI_PAGE_SHIFT) - 1))
286 & ~((1UL << EFI_PAGE_SHIFT) - 1);
287 fw_tables =
288 (struct fw_tables *)_xmalloc(fw_tables_size,
289 __alignof__(*fw_tables));
290 if (fw_tables == NULL) {
291 dprintk(XENLOG_INFO,
292 "can't allocate fw_tables memory size = %ld\n",
293 fw_tables_size);
294 return -ENOMEM;
295 }
296 memset(fw_tables, 0, fw_tables_size);
297 BUILD_BUG_ON(FW_END_PADDR_MIN != FW_TABLES_END_PADDR_MIN);
298 fw_tables->fw_tables_size = fw_tables_size;
299 fw_tables->fw_end_paddr = FW_TABLES_BASE_PADDR + fw_tables_size;
300 fw_tables->fw_tables_end_paddr =
301 FW_TABLES_BASE_PADDR + fw_tables_size;
302 fw_tables->num_mds = 0;
304 /* It is necessary to allocate pages before dom_fw_init()
305 * dom_fw_init() uses up page to d->max_pages.
306 */
307 for (gpaddr = FW_TABLES_BASE_PADDR;
308 gpaddr < fw_tables->fw_end_paddr; gpaddr += PAGE_SIZE)
309 assign_new_domain_page_if_dom0(d, gpaddr);
311 ret = dom_fw_init(d, d->arch.breakimm, bp,
312 fw_tables, imva_hypercall_base, maxmem);
313 if (ret < 0) {
314 xfree(fw_tables);
315 return ret;
316 }
318 ret = platform_fw_init(d, bp, fw_tables);
319 if (ret < 0) {
320 xfree(fw_tables);
321 return ret;
322 }
324 if (sizeof(*fw_tables) +
325 fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]) >
326 fw_tables_size) {
327 panic("EFI memmap too large. "
328 "Increase NUM_EXTRA_MEM_DESCS.\n"
329 "fw_table_size %ld > %ld num_mds %ld "
330 "NUM_EXTRA_MEM_DESCS %d.\n",
331 fw_tables_size, fw_tables->fw_tables_size,
332 fw_tables->num_mds, NUM_EXTRA_MEM_DESCS);
333 }
334 fw_tables_size = sizeof(*fw_tables) +
335 fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]);
337 /* clear domain builder internal use member */
338 fw_tables->fw_tables_size = 0;
339 fw_tables->fw_end_paddr = 0;
340 fw_tables->fw_tables_end_paddr = 0;
341 fw_tables->num_mds = 0;
343 /* copy fw_tables into domain pseudo physical address space */
344 dom_fw_copy_to(d, FW_TABLES_BASE_PADDR, fw_tables,
345 fw_tables_size);
346 xfree(fw_tables);
347 }
349 dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR));
350 return dom_fw_set_convmem_end(d);
351 }
353 /*
354 * Local variables:
355 * mode: C
356 * c-set-style: "linux"
357 * c-basic-offset: 8
358 * tab-width: 8
359 * indent-tabs-mode: t
360 * End:
361 */