ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw_dom0.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 3f6e855d218b
children 239b44eeb2d6
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 */
21 /*
22 * Xen domain firmware emulation support
23 * Copyright (C) 2004 Hewlett-Packard Co.
24 * Dan Magenheimer (dan.magenheimer@hp.com)
25 */
27 #include <xen/config.h>
28 #include <xen/acpi.h>
29 #include <xen/errno.h>
30 #include <xen/sched.h>
31 #include <xen/list.h>
33 #include <asm/dom_fw.h>
34 #include <asm/dom_fw_common.h>
35 #include <asm/dom_fw_dom0.h>
36 #include <asm/dom_fw_utils.h>
38 #include <linux/sort.h>
40 struct acpi_backup_table_entry {
41 struct list_head list;
42 unsigned long pa;
43 unsigned long size;
44 unsigned char data[0];
45 };
47 static LIST_HEAD(acpi_backup_table_list);
49 static u32 lsapic_nbr;
51 /* Modify lsapic table. Provides LPs. */
52 static int __init
53 acpi_update_lsapic(acpi_table_entry_header * header, const unsigned long end)
54 {
55 struct acpi_table_lsapic *lsapic;
56 int enable;
58 lsapic = (struct acpi_table_lsapic *)header;
59 if (!lsapic)
60 return -EINVAL;
62 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
63 enable = 1;
64 else
65 enable = 0;
67 if (lsapic->flags.enabled && enable) {
68 printk("enable lsapic entry: 0x%lx\n", (u64) lsapic);
69 lsapic->id = lsapic_nbr;
70 lsapic->eid = 0;
71 lsapic_nbr++;
72 } else if (lsapic->flags.enabled) {
73 printk("DISABLE lsapic entry: 0x%lx\n", (u64) lsapic);
74 lsapic->flags.enabled = 0;
75 lsapic->id = 0;
76 lsapic->eid = 0;
77 }
78 return 0;
79 }
81 static int __init
82 acpi_patch_plat_int_src(acpi_table_entry_header * header,
83 const unsigned long end)
84 {
85 struct acpi_table_plat_int_src *plintsrc;
87 plintsrc = (struct acpi_table_plat_int_src *)header;
88 if (!plintsrc)
89 return -EINVAL;
91 if (plintsrc->type == ACPI_INTERRUPT_CPEI) {
92 printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n");
93 plintsrc->type = -1;
94 }
95 return 0;
96 }
98 static int __init
99 acpi_update_madt_checksum(unsigned long phys_addr, unsigned long size)
100 {
101 struct acpi_table_madt *acpi_madt;
103 if (!phys_addr || !size)
104 return -EINVAL;
106 acpi_madt = (struct acpi_table_madt *)__va(phys_addr);
107 acpi_madt->header.checksum = 0;
108 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
110 return 0;
111 }
113 static int __init
114 acpi_backup_table(unsigned long phys_addr, unsigned long size)
115 {
116 struct acpi_backup_table_entry *entry;
117 void *vaddr = __va(phys_addr);
119 if (!phys_addr || !size)
120 return -EINVAL;
122 entry = xmalloc_bytes(sizeof(*entry) + size);
123 if (!entry) {
124 dprintk(XENLOG_WARNING, "Failed to allocate memory for "
125 "%.4s table backup\n",
126 ((struct acpi_table_header *)vaddr)->signature);
127 return -ENOMEM;
128 }
130 entry->pa = phys_addr;
131 entry->size = size;
133 memcpy(entry->data, vaddr, size);
135 list_add(&entry->list, &acpi_backup_table_list);
137 printk(XENLOG_INFO "Backup %.4s table stored @0x%p\n",
138 ((struct acpi_table_header *)entry->data)->signature,
139 entry->data);
141 return 0;
142 }
144 void
145 acpi_restore_tables()
146 {
147 struct acpi_backup_table_entry *entry;
149 list_for_each_entry(entry, &acpi_backup_table_list, list) {
150 printk(XENLOG_INFO "Restoring backup %.4s table @0x%p\n",
151 ((struct acpi_table_header *)entry->data)->signature,
152 entry->data);
154 memcpy(__va(entry->pa), entry->data, entry->size);
155 /* Only called from kexec path, no need to free entries */
156 }
157 }
159 /* base is physical address of acpi table */
160 static void __init touch_acpi_table(void)
161 {
162 int result;
163 lsapic_nbr = 0;
165 /*
166 * Modify dom0 MADT:
167 * - Disable CPUs that would exceed max vCPUs for the domain
168 * - Virtualize id/eid for indexing into domain vCPU array
169 * - Hide CPEI interrupt source
170 *
171 * ACPI tables must be backed-up before modification!
172 */
173 acpi_table_parse(ACPI_APIC, acpi_backup_table);
175 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
176 printk("Error parsing MADT - no LAPIC entries\n");
177 if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,
178 acpi_patch_plat_int_src, 0) < 0)
179 printk("Error parsing MADT - no PLAT_INT_SRC entries\n");
181 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
183 /*
184 * SRAT & SLIT tables aren't useful for Dom0 until
185 * we support more NUMA configuration information in Xen.
186 *
187 * NB - backup ACPI tables first.
188 */
189 acpi_table_parse(ACPI_SRAT, acpi_backup_table);
190 acpi_table_parse(ACPI_SLIT, acpi_backup_table);
192 result = acpi_table_disable(ACPI_SRAT);
193 if ( result == 0 )
194 printk("Success Disabling SRAT\n");
195 else if ( result != -ENOENT )
196 printk("ERROR: Failed Disabling SRAT\n");
198 result = acpi_table_disable(ACPI_SLIT);
199 if ( result == 0 )
200 printk("Success Disabling SLIT\n");
201 else if ( result != -ENOENT )
202 printk("ERROR: Failed Disabling SLIT\n");
204 return;
205 }
207 void __init efi_systable_init_dom0(struct fw_tables *tables)
208 {
209 int i = 1;
211 touch_acpi_table();
213 /* Write messages to the console. */
214 printk("Domain0 EFI passthrough:");
215 if (efi.mps) {
216 tables->efi_tables[i].guid = MPS_TABLE_GUID;
217 tables->efi_tables[i].table = __pa(efi.mps);
218 printk(" MPS=0x%lx", tables->efi_tables[i].table);
219 i++;
220 }
221 if (efi.acpi20) {
222 tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;
223 tables->efi_tables[i].table = __pa(efi.acpi20);
224 printk(" ACPI 2.0=0x%lx", tables->efi_tables[i].table);
225 i++;
226 }
227 if (efi.acpi) {
228 tables->efi_tables[i].guid = ACPI_TABLE_GUID;
229 tables->efi_tables[i].table = __pa(efi.acpi);
230 printk(" ACPI=0x%lx", tables->efi_tables[i].table);
231 i++;
232 }
233 if (efi.smbios) {
234 tables->efi_tables[i].guid = SMBIOS_TABLE_GUID;
235 tables->efi_tables[i].table = __pa(efi.smbios);
236 printk(" SMBIOS=0x%lx", tables->efi_tables[i].table);
237 i++;
238 }
239 if (efi.hcdp) {
240 tables->efi_tables[i].guid = HCDP_TABLE_GUID;
241 tables->efi_tables[i].table = __pa(efi.hcdp);
242 printk(" HCDP=0x%lx", tables->efi_tables[i].table);
243 i++;
244 }
245 printk("\n");
246 BUG_ON(i > NUM_EFI_SYS_TABLES);
247 }
249 static void __init
250 setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables)
251 {
252 int i;
253 size_t size;
254 unsigned int num_pages;
255 efi_memory_desc_t *md;
256 efi_memory_desc_t *last_mem_md = NULL;
257 xen_ia64_memmap_info_t *memmap_info;
258 unsigned long paddr_start;
259 unsigned long paddr_end;
261 size = sizeof(*memmap_info) +
262 (tables->num_mds + 1) * sizeof(tables->efi_memmap[0]);
263 num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
264 for (i = tables->num_mds - 1; i >= 0; i--) {
265 md = &tables->efi_memmap[i];
266 if (md->attribute == EFI_MEMORY_WB &&
267 md->type == EFI_CONVENTIONAL_MEMORY &&
268 md->num_pages >
269 ((num_pages + 1) << (PAGE_SHIFT - EFI_PAGE_SHIFT))) {
270 last_mem_md = md;
271 break;
272 }
273 }
275 if (last_mem_md == NULL) {
276 printk("%s: warning: "
277 "no dom0 contiguous memory to hold memory map\n",
278 __func__);
279 return;
280 }
281 paddr_end = last_mem_md->phys_addr +
282 (last_mem_md->num_pages << EFI_PAGE_SHIFT);
283 paddr_start = (paddr_end - (num_pages << PAGE_SHIFT)) & PAGE_MASK;
284 last_mem_md->num_pages -= (paddr_end - paddr_start) >> EFI_PAGE_SHIFT;
286 md = &tables->efi_memmap[tables->num_mds];
287 tables->num_mds++;
288 md->type = EFI_RUNTIME_SERVICES_DATA;
289 md->phys_addr = paddr_start;
290 md->virt_addr = 0;
291 md->num_pages = num_pages << (PAGE_SHIFT - EFI_PAGE_SHIFT);
292 md->attribute = EFI_MEMORY_WB;
294 BUG_ON(tables->fw_tables_size <
295 sizeof(*tables) +
296 sizeof(tables->efi_memmap[0]) * tables->num_mds);
297 /* with this sort, md doesn't point memmap table */
298 sort(tables->efi_memmap, tables->num_mds,
299 sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);
301 memmap_info = domain_mpa_to_imva(d, paddr_start);
302 memmap_info->efi_memdesc_size = sizeof(md[0]);
303 memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION;
304 memmap_info->efi_memmap_size = tables->num_mds * sizeof(md[0]);
305 dom_fw_copy_to(d,
306 paddr_start + offsetof(xen_ia64_memmap_info_t, memdesc),
307 &tables->efi_memmap[0], memmap_info->efi_memmap_size);
308 d->shared_info->arch.memmap_info_num_pages = num_pages;
309 d->shared_info->arch.memmap_info_pfn = paddr_start >> PAGE_SHIFT;
310 }
312 /* setup_guest() @ libxc/xc_linux_build() arranges memory for domU.
313 * however no one arranges memory for dom0,
314 * instead we allocate pages manually.
315 */
316 static void
317 assign_new_domain0_range(struct domain *d, const efi_memory_desc_t * md)
318 {
319 if (md->type == EFI_PAL_CODE ||
320 md->type == EFI_RUNTIME_SERVICES_DATA ||
321 md->type == EFI_CONVENTIONAL_MEMORY) {
322 unsigned long start = md->phys_addr & PAGE_MASK;
323 unsigned long end =
324 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
325 unsigned long addr;
327 if (end == start) {
328 /* md->num_pages = 0 is allowed. */
329 return;
330 }
332 for (addr = start; addr < end; addr += PAGE_SIZE)
333 assign_new_domain0_page(d, addr);
334 }
335 }
337 /* Complete the dom0 memmap. */
338 int __init
339 complete_dom0_memmap(struct domain *d, struct fw_tables *tables)
340 {
341 u64 addr;
342 void *efi_map_start, *efi_map_end, *p;
343 u64 efi_desc_size;
344 int i;
346 for (i = 0; i < tables->num_mds; i++)
347 assign_new_domain0_range(d, &tables->efi_memmap[i]);
349 /* Walk through all MDT entries.
350 Copy all interesting entries. */
351 efi_map_start = __va(ia64_boot_param->efi_memmap);
352 efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
353 efi_desc_size = ia64_boot_param->efi_memdesc_size;
355 for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
356 const efi_memory_desc_t *md = p;
357 efi_memory_desc_t *dom_md = &tables->efi_memmap[tables->num_mds];
358 u64 start = md->phys_addr;
359 u64 size = md->num_pages << EFI_PAGE_SHIFT;
360 u64 end = start + size;
361 u64 mpaddr;
362 unsigned long flags;
364 switch (md->type) {
365 case EFI_RUNTIME_SERVICES_CODE:
366 case EFI_RUNTIME_SERVICES_DATA:
367 case EFI_ACPI_RECLAIM_MEMORY:
368 case EFI_ACPI_MEMORY_NVS:
369 case EFI_RESERVED_TYPE:
370 /*
371 * Map into dom0 - We must respect protection
372 * and cache attributes. Not all of these pages
373 * are writable!!!
374 */
375 flags = ASSIGN_writable; /* dummy - zero */
376 if (md->attribute & EFI_MEMORY_WP)
377 flags |= ASSIGN_readonly;
378 if ((md->attribute & EFI_MEMORY_UC) &&
379 !(md->attribute & EFI_MEMORY_WB))
380 flags |= ASSIGN_nocache;
382 assign_domain_mach_page(d, start, size, flags);
384 /* Fall-through. */
385 case EFI_MEMORY_MAPPED_IO:
386 /* Will be mapped with ioremap. */
387 /* Copy descriptor. */
388 *dom_md = *md;
389 dom_md->virt_addr = 0;
390 tables->num_mds++;
391 break;
393 case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
394 flags = ASSIGN_writable; /* dummy - zero */
395 if (md->attribute & EFI_MEMORY_UC)
396 flags |= ASSIGN_nocache;
398 if (start > 0x1ffffffff0000000UL) {
399 mpaddr = 0x4000000000000UL - size;
400 printk(XENLOG_INFO "Remapping IO ports from "
401 "%lx to %lx\n", start, mpaddr);
402 } else
403 mpaddr = start;
405 /* Map into dom0. */
406 assign_domain_mmio_page(d, mpaddr, start, size, flags);
407 /* Copy descriptor. */
408 *dom_md = *md;
409 dom_md->phys_addr = mpaddr;
410 dom_md->virt_addr = 0;
411 tables->num_mds++;
412 break;
414 case EFI_CONVENTIONAL_MEMORY:
415 case EFI_LOADER_CODE:
416 case EFI_LOADER_DATA:
417 case EFI_BOOT_SERVICES_CODE:
418 case EFI_BOOT_SERVICES_DATA: {
419 u64 dom_md_start;
420 u64 dom_md_end;
421 unsigned long left_mem =
422 (unsigned long)(d->max_pages - d->tot_pages) <<
423 PAGE_SHIFT;
425 if (!(md->attribute & EFI_MEMORY_WB))
426 break;
428 dom_md_start = max(tables->fw_end_paddr, start);
429 dom_md_end = dom_md_start;
430 do {
431 dom_md_end = min(dom_md_end + left_mem, end);
432 if (dom_md_end < dom_md_start + PAGE_SIZE)
433 break;
435 dom_md->type = EFI_CONVENTIONAL_MEMORY;
436 dom_md->phys_addr = dom_md_start;
437 dom_md->virt_addr = 0;
438 dom_md->num_pages =
439 (dom_md_end - dom_md_start) >>
440 EFI_PAGE_SHIFT;
441 dom_md->attribute = EFI_MEMORY_WB;
443 assign_new_domain0_range(d, dom_md);
444 /*
445 * recalculate left_mem.
446 * we might already allocated memory in
447 * this region because of kernel loader.
448 * So we might consumed less than
449 * (dom_md_end - dom_md_start) above.
450 */
451 left_mem = (unsigned long)
452 (d->max_pages - d->tot_pages) <<
453 PAGE_SHIFT;
454 } while (left_mem > 0 && dom_md_end < end);
456 if (!(dom_md_end < dom_md_start + PAGE_SIZE))
457 tables->num_mds++;
458 break;
459 }
461 case EFI_UNUSABLE_MEMORY:
462 case EFI_PAL_CODE:
463 /*
464 * We don't really need these, but holes in the
465 * memory map may cause Linux to assume there are
466 * uncacheable ranges within a granule.
467 */
468 dom_md->type = EFI_UNUSABLE_MEMORY;
469 dom_md->phys_addr = start;
470 dom_md->virt_addr = 0;
471 dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
472 dom_md->attribute = EFI_MEMORY_WB;
473 tables->num_mds++;
474 break;
476 default:
477 /* Print a warning but continue. */
478 printk("complete_dom0_memmap: warning: "
479 "unhandled MDT entry type %u\n", md->type);
480 }
481 }
482 BUG_ON(tables->fw_tables_size <
483 sizeof(*tables) +
484 sizeof(tables->efi_memmap[0]) * tables->num_mds);
486 sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t),
487 efi_mdt_cmp, NULL);
489 // Map low-memory holes & unmapped MMIO for legacy drivers
490 for (addr = 0; addr < ONE_MB; addr += PAGE_SIZE) {
491 if (domain_page_mapped(d, addr))
492 continue;
494 if (efi_mmio(addr, PAGE_SIZE)) {
495 unsigned long flags;
496 flags = ASSIGN_writable | ASSIGN_nocache;
497 assign_domain_mmio_page(d, addr, addr, PAGE_SIZE,
498 flags);
499 }
500 }
501 setup_dom0_memmap_info(d, tables);
502 return tables->num_mds;
503 }
505 /*
506 * Local variables:
507 * mode: C
508 * c-set-style: "linux"
509 * c-basic-offset: 8
510 * tab-width: 8
511 * indent-tabs-mode: t
512 * End:
513 */