ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 9769:d23c088eac6d

[IA64] smp boot speed-up (sal cache flush, itc/itv messages)

Use sal_cache_flush to emulate SAL_CACHE_FLUSH instead of fc.
Only prints one vcpu_set_itc message, do not print set itv message.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Tue Apr 25 22:32:14 2006 -0600 (2006-04-25)
parents ae0d41bd3bba
children ddcd9c267612
line source
1 /*
2 * Xen domain firmware emulation support
3 * Copyright (C) 2004 Hewlett-Packard Co.
4 * Dan Magenheimer (dan.magenheimer@hp.com)
5 *
6 */
8 #include <xen/config.h>
9 #include <asm/system.h>
10 #include <asm/pgalloc.h>
12 #include <linux/efi.h>
13 #include <linux/sort.h>
14 #include <asm/io.h>
15 #include <asm/pal.h>
16 #include <asm/sal.h>
17 #include <asm/meminit.h>
18 #include <xen/compile.h>
19 #include <xen/acpi.h>
21 #include <asm/dom_fw.h>
22 #include <public/sched.h>
24 static struct ia64_boot_param *dom_fw_init(struct domain *, const char *,int,char *,int);
25 extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr);
26 extern struct domain *dom0;
27 extern unsigned long dom0_start;
29 extern unsigned long running_on_sim;
32 unsigned long dom_fw_base_mpa = -1;
33 unsigned long imva_fw_base = -1;
35 // return domain (meta)physical address for a given imva
36 // this function is a call-back from dom_fw_init
37 static unsigned long
38 dom_pa(unsigned long imva)
39 {
40 if (dom_fw_base_mpa == -1 || imva_fw_base == -1) {
41 printf("dom_pa: uninitialized! (spinning...)\n");
42 while(1);
43 }
44 if (imva - imva_fw_base > PAGE_SIZE) {
45 printf("dom_pa: bad offset! imva=0x%lx, imva_fw_base=0x%lx (spinning...)\n",
46 imva, imva_fw_base);
47 while(1);
48 }
49 return dom_fw_base_mpa + (imva - imva_fw_base);
50 }
52 // allocate a page for fw
53 // build_physmap_table() which is called by new_thread()
54 // does for domU.
55 #define ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, mpaddr) \
56 do { \
57 if ((d) == dom0) { \
58 assign_new_domain0_page((d), (mpaddr)); \
59 } \
60 } while (0)
62 // builds a hypercall bundle at domain physical address
63 static void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall)
64 {
65 unsigned long *imva;
67 #ifndef CONFIG_XEN_IA64_DOM0_VP
68 if (d == dom0) paddr += dom0_start;
69 #endif
70 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
71 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
72 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, 1);
73 }
76 // builds a hypercall bundle at domain physical address
77 static void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret)
78 {
79 unsigned long *imva;
81 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
82 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
83 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, ret);
84 }
86 static void dom_fw_pal_hypercall_patch(struct domain *d, unsigned long paddr)
87 {
88 unsigned long *imva;
90 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
91 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
92 build_pal_hypercall_bundles(imva, d->arch.breakimm, FW_HYPERCALL_PAL_CALL);
93 }
96 // FIXME: This is really a hack: Forcing the boot parameter block
97 // at domain mpaddr 0 page, then grabbing only the low bits of the
98 // Xen imva, which is the offset into the page
99 unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen)
100 {
101 struct ia64_boot_param *bp;
103 dom_fw_base_mpa = 0;
104 #ifndef CONFIG_XEN_IA64_DOM0_VP
105 if (d == dom0) dom_fw_base_mpa += dom0_start;
106 #endif
107 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, dom_fw_base_mpa);
108 imva_fw_base = domain_mpa_to_imva(d, dom_fw_base_mpa);
109 bp = dom_fw_init(d, args, arglen, (char *) imva_fw_base, PAGE_SIZE);
110 return dom_pa((unsigned long) bp);
111 }
114 /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */
116 /* Set IP and GR1 of not yet initialized vcpu. */
117 static void
118 set_os_boot_rendez (struct domain *d, unsigned long pc, unsigned long gr1)
119 {
120 struct vcpu *v;
121 int i;
123 printf ("set_os_boot_rendez: %lx %lx\n", pc, gr1);
124 for (i = 1; i < MAX_VIRT_CPUS; i++) {
125 v = d->vcpu[i];
126 if (v != NULL
127 && !test_bit(_VCPUF_initialised, &v->vcpu_flags)) {
128 struct pt_regs *regs = vcpu_regs (v);
129 regs->cr_iip = pc;
130 regs->r1 = gr1;
131 }
132 }
133 }
135 struct sal_ret_values
136 sal_emulator (long index, unsigned long in1, unsigned long in2,
137 unsigned long in3, unsigned long in4, unsigned long in5,
138 unsigned long in6, unsigned long in7)
139 {
140 unsigned long r9 = 0;
141 unsigned long r10 = 0;
142 long r11 = 0;
143 long status;
145 status = 0;
146 switch (index) {
147 case SAL_FREQ_BASE:
148 if (!running_on_sim)
149 status = ia64_sal_freq_base(in1,&r9,&r10);
150 else switch (in1) {
151 case SAL_FREQ_BASE_PLATFORM:
152 r9 = 200000000;
153 break;
155 case SAL_FREQ_BASE_INTERVAL_TIMER:
156 r9 = 700000000;
157 break;
159 case SAL_FREQ_BASE_REALTIME_CLOCK:
160 r9 = 1;
161 break;
163 default:
164 status = -1;
165 break;
166 }
167 break;
168 case SAL_PCI_CONFIG_READ:
169 if (current->domain == dom0) {
170 u64 value;
171 // note that args 2&3 are swapped!!
172 status = ia64_sal_pci_config_read(in1,in3,in2,&value);
173 r9 = value;
174 }
175 else
176 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
177 break;
178 case SAL_PCI_CONFIG_WRITE:
179 if (current->domain == dom0) {
180 if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
181 (in4 > 1) ||
182 (in2 > 8) || (in2 & (in2-1)))
183 printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
184 in1,in4,in2,in3);
185 // note that args are in a different order!!
186 status = ia64_sal_pci_config_write(in1,in4,in2,in3);
187 }
188 else
189 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
190 break;
191 case SAL_SET_VECTORS:
192 if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) {
193 if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) {
194 /* Sanity check: cs_length1 must be 0,
195 second vector is reserved. */
196 status = -2;
197 }
198 else
199 set_os_boot_rendez (current->domain, in2, in3);
200 }
201 else
202 printf("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n",
203 in1);
204 break;
205 case SAL_GET_STATE_INFO:
206 /* No more info. */
207 status = -5;
208 r9 = 0;
209 break;
210 case SAL_GET_STATE_INFO_SIZE:
211 /* Return a dummy size. */
212 status = 0;
213 r9 = 128;
214 break;
215 case SAL_CLEAR_STATE_INFO:
216 /* Noop. */
217 break;
218 case SAL_MC_RENDEZ:
219 printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
220 break;
221 case SAL_MC_SET_PARAMS:
222 printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
223 break;
224 case SAL_CACHE_FLUSH:
225 if (1) {
226 /* Flush using SAL.
227 This method is faster but has a side effect on
228 other vcpu running on this cpu. */
229 status = ia64_sal_cache_flush (in1);
230 }
231 else {
232 /* Flush with fc all the domain.
233 This method is slower but has no side effects. */
234 domain_cache_flush (current->domain, in1 == 4 ? 1 : 0);
235 status = 0;
236 }
237 break;
238 case SAL_CACHE_INIT:
239 printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
240 break;
241 case SAL_UPDATE_PAL:
242 printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
243 break;
244 default:
245 printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
246 status = -1;
247 break;
248 }
249 return ((struct sal_ret_values) {status, r9, r10, r11});
250 }
252 struct ia64_pal_retval
253 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
254 {
255 unsigned long r9 = 0;
256 unsigned long r10 = 0;
257 unsigned long r11 = 0;
258 long status = PAL_STATUS_UNIMPLEMENTED;
260 if (running_on_sim)
261 return pal_emulator_static(index);
263 // pal code must be mapped by a TR when pal is called, however
264 // calls are rare enough that we will map it lazily rather than
265 // at every context switch
266 //efi_map_pal_code();
267 switch (index) {
268 case PAL_MEM_ATTRIB:
269 status = ia64_pal_mem_attrib(&r9);
270 break;
271 case PAL_FREQ_BASE:
272 status = ia64_pal_freq_base(&r9);
273 break;
274 case PAL_PROC_GET_FEATURES:
275 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
276 break;
277 case PAL_BUS_GET_FEATURES:
278 status = ia64_pal_bus_get_features(
279 (pal_bus_features_u_t *) &r9,
280 (pal_bus_features_u_t *) &r10,
281 (pal_bus_features_u_t *) &r11);
282 break;
283 case PAL_FREQ_RATIOS:
284 status = ia64_pal_freq_ratios(
285 (struct pal_freq_ratio *) &r9,
286 (struct pal_freq_ratio *) &r10,
287 (struct pal_freq_ratio *) &r11);
288 break;
289 case PAL_PTCE_INFO:
290 {
291 // return hard-coded xen-specific values because ptc.e
292 // is emulated on xen to always flush everything
293 // these values result in only one ptc.e instruction
294 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
295 }
296 break;
297 case PAL_VERSION:
298 status = ia64_pal_version(
299 (pal_version_u_t *) &r9,
300 (pal_version_u_t *) &r10);
301 break;
302 case PAL_VM_PAGE_SIZE:
303 status = ia64_pal_vm_page_size(&r9,&r10);
304 break;
305 case PAL_DEBUG_INFO:
306 status = ia64_pal_debug_info(&r9,&r10);
307 break;
308 case PAL_CACHE_SUMMARY:
309 status = ia64_pal_cache_summary(&r9,&r10);
310 break;
311 case PAL_VM_SUMMARY:
312 {
313 /* Use xen-specific values.
314 hash_tag_id is somewhat random! */
315 const pal_vm_info_1_u_t v1 =
316 {.pal_vm_info_1_s =
317 { .vw = 1,
318 .phys_add_size = 44,
319 .key_size = 16,
320 .max_pkr = 15,
321 .hash_tag_id = 0x30,
322 .max_dtr_entry = NDTRS - 1,
323 .max_itr_entry = NITRS - 1,
324 #ifdef VHPT_GLOBAL
325 .max_unique_tcs = 3,
326 .num_tc_levels = 2
327 #else
328 .max_unique_tcs = 2,
329 .num_tc_levels = 1
330 #endif
331 }};
332 const pal_vm_info_2_u_t v2 =
333 { .pal_vm_info_2_s =
334 { .impl_va_msb = 50,
335 .rid_size = current->domain->arch.rid_bits,
336 .reserved = 0 }};
337 r9 = v1.pvi1_val;
338 r10 = v2.pvi2_val;
339 status = PAL_STATUS_SUCCESS;
340 }
341 break;
342 case PAL_VM_INFO:
343 #ifdef VHPT_GLOBAL
344 if (in1 == 0 && in2 == 2) {
345 /* Level 1: VHPT */
346 const pal_tc_info_u_t v =
347 { .pal_tc_info_s = {.num_sets = 128,
348 .associativity = 1,
349 .num_entries = 128,
350 .pf = 1,
351 .unified = 1,
352 .reduce_tr = 0,
353 .reserved = 0}};
354 r9 = v.pti_val;
355 /* Only support PAGE_SIZE tc. */
356 r10 = PAGE_SIZE;
357 status = PAL_STATUS_SUCCESS;
358 }
359 #endif
360 else if (
361 #ifdef VHPT_GLOBAL
362 in1 == 1 /* Level 2. */
363 #else
364 in1 == 0 /* Level 1. */
365 #endif
366 && (in2 == 1 || in2 == 2))
367 {
368 /* itlb/dtlb, 1 entry. */
369 const pal_tc_info_u_t v =
370 { .pal_tc_info_s = {.num_sets = 1,
371 .associativity = 1,
372 .num_entries = 1,
373 .pf = 1,
374 .unified = 0,
375 .reduce_tr = 0,
376 .reserved = 0}};
377 r9 = v.pti_val;
378 /* Only support PAGE_SIZE tc. */
379 r10 = PAGE_SIZE;
380 status = PAL_STATUS_SUCCESS;
381 }
382 else
383 status = PAL_STATUS_EINVAL;
384 break;
385 case PAL_RSE_INFO:
386 status = ia64_pal_rse_info(
387 &r9,
388 (pal_hints_u_t *) &r10);
389 break;
390 case PAL_REGISTER_INFO:
391 status = ia64_pal_register_info(in1, &r9, &r10);
392 break;
393 case PAL_CACHE_FLUSH:
394 /* FIXME */
395 printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
396 BUG();
397 break;
398 case PAL_PERF_MON_INFO:
399 {
400 unsigned long pm_buffer[16];
401 status = ia64_pal_perf_mon_info(
402 pm_buffer,
403 (pal_perf_mon_info_u_t *) &r9);
404 if (status != 0) {
405 while(1)
406 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
407 break;
408 }
409 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
410 while(1)
411 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
412 "can't copy to user!!!!\n");
413 status = PAL_STATUS_UNIMPLEMENTED;
414 break;
415 }
416 }
417 break;
418 case PAL_CACHE_INFO:
419 {
420 pal_cache_config_info_t ci;
421 status = ia64_pal_cache_config_info(in1,in2,&ci);
422 if (status != 0) break;
423 r9 = ci.pcci_info_1.pcci1_data;
424 r10 = ci.pcci_info_2.pcci2_data;
425 }
426 break;
427 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
428 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
429 break;
430 case PAL_HALT_INFO:
431 {
432 /* 1000 cycles to enter/leave low power state,
433 consumes 10 mW, implemented and cache/TLB coherent. */
434 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
435 | (1UL << 61) | (1UL << 60);
436 if (copy_to_user ((void *)in1, &res, sizeof (res)))
437 status = PAL_STATUS_EINVAL;
438 else
439 status = PAL_STATUS_SUCCESS;
440 }
441 break;
442 case PAL_HALT:
443 if (current->domain == dom0) {
444 printf ("Domain0 halts the machine\n");
445 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
446 }
447 else
448 domain_shutdown (current->domain,
449 SHUTDOWN_poweroff);
450 break;
451 default:
452 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
453 index);
454 break;
455 }
456 return ((struct ia64_pal_retval) {status, r9, r10, r11});
457 }
460 #define NFUNCPTRS 20
462 static void print_md(efi_memory_desc_t *md)
463 {
464 #if 1
465 printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
466 md->type, md->attribute, md->phys_addr,
467 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
468 md->num_pages >> (20 - EFI_PAGE_SHIFT));
469 #endif
470 }
473 static u32 lsapic_nbr;
475 /* Modify lsapic table. Provides LPs. */
476 static int
477 acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
478 {
479 struct acpi_table_lsapic *lsapic;
480 int enable;
482 lsapic = (struct acpi_table_lsapic *) header;
483 if (!lsapic)
484 return -EINVAL;
486 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
487 enable = 1;
488 else
489 enable = 0;
490 if (lsapic->flags.enabled && enable) {
491 printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
492 lsapic_nbr++;
493 } else if (lsapic->flags.enabled) {
494 printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
495 lsapic->flags.enabled = 0;
496 }
497 return 0;
498 }
500 static u8
501 generate_acpi_checksum(void *tbl, unsigned long len)
502 {
503 u8 *ptr, sum = 0;
505 for (ptr = tbl; len > 0 ; len--, ptr++)
506 sum += *ptr;
508 return 0 - sum;
509 }
511 static int
512 acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
513 {
514 struct acpi_table_madt* acpi_madt;
516 if (!phys_addr || !size)
517 return -EINVAL;
519 acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
520 acpi_madt->header.checksum = 0;
521 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
523 return 0;
524 }
526 /* base is physical address of acpi table */
527 static void touch_acpi_table(void)
528 {
529 lsapic_nbr = 0;
530 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
531 printk("Error parsing MADT - no LAPIC entires\n");
532 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
534 return;
535 }
537 struct fake_acpi_tables {
538 struct acpi20_table_rsdp rsdp;
539 struct xsdt_descriptor_rev2 xsdt;
540 u64 madt_ptr;
541 struct fadt_descriptor_rev2 fadt;
542 struct facs_descriptor_rev2 facs;
543 struct acpi_table_header dsdt;
544 u8 aml[16];
545 struct acpi_table_madt madt;
546 struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
547 u8 pm1a_evt_blk[4];
548 u8 pm1a_cnt_blk[1];
549 u8 pm_tmr_blk[4];
550 };
552 /* Create enough of an ACPI structure to make the guest OS ACPI happy. */
553 static void
554 dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
555 {
556 struct acpi20_table_rsdp *rsdp = &tables->rsdp;
557 struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
558 struct fadt_descriptor_rev2 *fadt = &tables->fadt;
559 struct facs_descriptor_rev2 *facs = &tables->facs;
560 struct acpi_table_header *dsdt = &tables->dsdt;
561 struct acpi_table_madt *madt = &tables->madt;
562 struct acpi_table_lsapic *lsapic = tables->lsapic;
563 int i;
565 memset(tables, 0, sizeof(struct fake_acpi_tables));
567 /* setup XSDT (64bit version of RSDT) */
568 strncpy(xsdt->signature, XSDT_SIG, 4);
569 /* XSDT points to both the FADT and the MADT, so add one entry */
570 xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
571 xsdt->revision = 1;
572 strcpy(xsdt->oem_id, "XEN");
573 strcpy(xsdt->oem_table_id, "Xen/ia64");
574 strcpy(xsdt->asl_compiler_id, "XEN");
575 xsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
577 xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt);
578 tables->madt_ptr = dom_pa((unsigned long) madt);
580 xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
582 /* setup FADT */
583 strncpy(fadt->signature, FADT_SIG, 4);
584 fadt->length = sizeof(struct fadt_descriptor_rev2);
585 fadt->revision = FADT2_REVISION_ID;
586 strcpy(fadt->oem_id, "XEN");
587 strcpy(fadt->oem_table_id, "Xen/ia64");
588 strcpy(fadt->asl_compiler_id, "XEN");
589 fadt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
591 strncpy(facs->signature, FACS_SIG, 4);
592 facs->version = 1;
593 facs->length = sizeof(struct facs_descriptor_rev2);
595 fadt->xfirmware_ctrl = dom_pa((unsigned long) facs);
596 fadt->Xdsdt = dom_pa((unsigned long) dsdt);
598 /*
599 * All of the below FADT entries are filled it to prevent warnings
600 * from sanity checks in the ACPI CA. Emulate required ACPI hardware
601 * registers in system memory.
602 */
603 fadt->pm1_evt_len = 4;
604 fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
605 fadt->xpm1a_evt_blk.register_bit_width = 8;
606 fadt->xpm1a_evt_blk.address = dom_pa((unsigned long) &tables->pm1a_evt_blk);
607 fadt->pm1_cnt_len = 1;
608 fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
609 fadt->xpm1a_cnt_blk.register_bit_width = 8;
610 fadt->xpm1a_cnt_blk.address = dom_pa((unsigned long) &tables->pm1a_cnt_blk);
611 fadt->pm_tm_len = 4;
612 fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
613 fadt->xpm_tmr_blk.register_bit_width = 8;
614 fadt->xpm_tmr_blk.address = dom_pa((unsigned long) &tables->pm_tmr_blk);
616 fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
618 /* setup RSDP */
619 strncpy(rsdp->signature, RSDP_SIG, 8);
620 strcpy(rsdp->oem_id, "XEN");
621 rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
622 rsdp->length = sizeof(struct acpi20_table_rsdp);
623 rsdp->xsdt_address = dom_pa((unsigned long) xsdt);
625 rsdp->checksum = generate_acpi_checksum(rsdp,
626 ACPI_RSDP_CHECKSUM_LENGTH);
627 rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
629 /* setup DSDT with trivial namespace. */
630 strncpy(dsdt->signature, DSDT_SIG, 4);
631 dsdt->revision = 1;
632 dsdt->length = sizeof(struct acpi_table_header) + sizeof(tables->aml);
633 strcpy(dsdt->oem_id, "XEN");
634 strcpy(dsdt->oem_table_id, "Xen/ia64");
635 strcpy(dsdt->asl_compiler_id, "XEN");
636 dsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
638 /* Trivial namespace, avoids ACPI CA complaints */
639 tables->aml[0] = 0x10; /* Scope */
640 tables->aml[1] = 0x12; /* length/offset to next object */
641 strncpy((char *)&tables->aml[2], "_SB_", 4);
643 /* The processor object isn't absolutely necessary, revist for SMP */
644 tables->aml[6] = 0x5b; /* processor object */
645 tables->aml[7] = 0x83;
646 tables->aml[8] = 0x0b; /* next */
647 strncpy((char *)&tables->aml[9], "CPU0", 4);
649 dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
651 /* setup MADT */
652 strncpy(madt->header.signature, APIC_SIG, 4);
653 madt->header.revision = 2;
654 madt->header.length = sizeof(struct acpi_table_madt) +
655 MAX_VIRT_CPUS * sizeof(struct acpi_table_lsapic);
656 strcpy(madt->header.oem_id, "XEN");
657 strcpy(madt->header.oem_table_id, "Xen/ia64");
658 strcpy(madt->header.asl_compiler_id, "XEN");
659 madt->header.asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
661 /* An LSAPIC entry describes a CPU. */
662 for (i = 0; i < MAX_VIRT_CPUS; i++) {
663 lsapic[i].header.type = ACPI_MADT_LSAPIC;
664 lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
665 lsapic[i].id = i;
666 lsapic[i].eid = 0;
667 lsapic[i].flags.enabled = (d->vcpu[i] != NULL);
668 }
670 madt->header.checksum = generate_acpi_checksum(madt,
671 madt->header.length);
672 return;
673 }
675 #define NUM_EFI_SYS_TABLES 6
676 #define NUM_MEM_DESCS 64 //large enough
678 struct dom0_passthrough_arg {
679 #ifdef CONFIG_XEN_IA64_DOM0_VP
680 struct domain* d;
681 #endif
682 efi_memory_desc_t *md;
683 int* i;
684 };
686 static int
687 dom_fw_dom0_passthrough(efi_memory_desc_t *md, void *arg__)
688 {
689 struct dom0_passthrough_arg* arg = (struct dom0_passthrough_arg*)arg__;
690 unsigned long paddr;
692 #ifdef CONFIG_XEN_IA64_DOM0_VP
693 struct domain* d = arg->d;
694 u64 start = md->phys_addr;
695 u64 end = start + (md->num_pages << EFI_PAGE_SHIFT);
697 if (md->type == EFI_MEMORY_MAPPED_IO ||
698 md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
700 //XXX some machine has large mmio area whose size is about several TB.
701 // It requires impractical memory to map such a huge region
702 // to a domain.
703 // For now we don't map it, but later we must fix this.
704 if (md->type == EFI_MEMORY_MAPPED_IO &&
705 ((md->num_pages << EFI_PAGE_SHIFT) > 0x100000000UL))
706 return 0;
708 paddr = assign_domain_mmio_page(d, start, end - start);
709 } else
710 paddr = assign_domain_mach_page(d, start, end - start);
711 #else
712 paddr = md->phys_addr;
713 #endif
715 BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
716 md->type != EFI_RUNTIME_SERVICES_DATA &&
717 md->type != EFI_ACPI_RECLAIM_MEMORY &&
718 md->type != EFI_MEMORY_MAPPED_IO &&
719 md->type != EFI_MEMORY_MAPPED_IO_PORT_SPACE);
721 arg->md->type = md->type;
722 arg->md->pad = 0;
723 arg->md->phys_addr = paddr;
724 arg->md->virt_addr = 0;
725 arg->md->num_pages = md->num_pages;
726 arg->md->attribute = md->attribute;
727 print_md(arg->md);
729 (*arg->i)++;
730 arg->md++;
731 return 0;
732 }
734 static int
735 efi_mdt_cmp(const void *a, const void *b)
736 {
737 const efi_memory_desc_t *x = a, *y = b;
739 if (x->phys_addr > y->phys_addr)
740 return 1;
741 if (x->phys_addr < y->phys_addr)
742 return -1;
743 return 0;
744 }
746 static struct ia64_boot_param *
747 dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size)
748 {
749 efi_system_table_t *efi_systab;
750 efi_runtime_services_t *efi_runtime;
751 efi_config_table_t *efi_tables;
752 struct ia64_sal_systab *sal_systab;
753 struct ia64_sal_desc_entry_point *sal_ed;
754 struct ia64_sal_desc_ap_wakeup *sal_wakeup;
755 efi_memory_desc_t *efi_memmap, *md;
756 struct ia64_boot_param *bp;
757 unsigned long *pfn;
758 unsigned char checksum = 0;
759 char *cp, *cmd_line, *fw_vendor;
760 int i = 0;
761 unsigned long maxmem = (d->max_pages - d->arch.sys_pgnr) * PAGE_SIZE;
762 #ifdef CONFIG_XEN_IA64_DOM0_VP
763 const unsigned long start_mpaddr = 0;
764 #else
765 const unsigned long start_mpaddr = ((d==dom0)?dom0_start:0);
766 #endif
768 # define MAKE_MD(typ, attr, start, end, abs) \
769 do { \
770 md = efi_memmap + i++; \
771 md->type = typ; \
772 md->pad = 0; \
773 md->phys_addr = abs ? start : start_mpaddr + start; \
774 md->virt_addr = 0; \
775 md->num_pages = (end - start) >> 12; \
776 md->attribute = attr; \
777 print_md(md); \
778 } while (0)
780 /* FIXME: should check size but for now we have a whole MB to play with.
781 And if stealing code from fw-emu.c, watch out for new fw_vendor on the end!
782 if (fw_mem_size < sizeof(fw_mem_proto)) {
783 printf("sys_fw_init: insufficient space for fw_mem\n");
784 return 0;
785 }
786 */
787 memset(fw_mem, 0, fw_mem_size);
789 cp = fw_mem;
790 efi_systab = (void *) cp; cp += sizeof(*efi_systab);
791 efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
792 efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
793 sal_systab = (void *) cp; cp += sizeof(*sal_systab);
794 sal_ed = (void *) cp; cp += sizeof(*sal_ed);
795 sal_wakeup = (void *) cp; cp += sizeof(*sal_wakeup);
796 efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
797 bp = (void *) cp; cp += sizeof(*bp);
798 pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
799 cmd_line = (void *) cp;
801 if (args) {
802 if (arglen >= 1024)
803 arglen = 1023;
804 memcpy(cmd_line, args, arglen);
805 } else {
806 arglen = 0;
807 }
808 cmd_line[arglen] = '\0';
810 memset(efi_systab, 0, sizeof(efi_systab));
811 efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
812 efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
813 efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
814 cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary
815 #define FW_VENDOR "X\0e\0n\0/\0i\0a\0\066\0\064\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
816 cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary
818 memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
819 efi_systab->fw_vendor = dom_pa((unsigned long) fw_vendor);
821 efi_systab->fw_revision = 1;
822 efi_systab->runtime = (void *) dom_pa((unsigned long) efi_runtime);
823 efi_systab->nr_tables = NUM_EFI_SYS_TABLES;
824 efi_systab->tables = dom_pa((unsigned long) efi_tables);
826 efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
827 efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
828 efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
829 #define EFI_HYPERCALL_PATCH(tgt,call) do { \
830 dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \
831 tgt = dom_pa((unsigned long) pfn); \
832 *pfn++ = FW_HYPERCALL_##call##_PADDR + start_mpaddr; \
833 *pfn++ = 0; \
834 } while (0)
836 EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME);
837 EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME);
838 EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
839 EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
840 EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
841 EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE);
842 EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
843 EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE);
844 EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
845 EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM);
847 efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
848 efi_tables[0].table = dom_pa((unsigned long) sal_systab);
849 for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
850 efi_tables[i].guid = NULL_GUID;
851 efi_tables[i].table = 0;
852 }
853 if (d == dom0) {
854 #ifdef CONFIG_XEN_IA64_DOM0_VP
855 # define ASSIGN_DOMAIN_MACH_PAGE(d, p) assign_domain_mach_page(d, p, PAGE_SIZE)
856 #else
857 # define ASSIGN_DOMAIN_MACH_PAGE(d, p) ({p;})
858 #endif
860 printf("Domain0 EFI passthrough:");
861 i = 1;
862 if (efi.mps) {
863 efi_tables[i].guid = MPS_TABLE_GUID;
864 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.mps));
865 printf(" MPS=0x%lx",efi_tables[i].table);
866 i++;
867 }
869 touch_acpi_table();
871 if (efi.acpi20) {
872 efi_tables[i].guid = ACPI_20_TABLE_GUID;
873 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.acpi20));
874 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
875 i++;
876 }
877 if (efi.acpi) {
878 efi_tables[i].guid = ACPI_TABLE_GUID;
879 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.acpi));
880 printf(" ACPI=0x%lx",efi_tables[i].table);
881 i++;
882 }
883 if (efi.smbios) {
884 efi_tables[i].guid = SMBIOS_TABLE_GUID;
885 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.smbios));
886 printf(" SMBIOS=0x%lx",efi_tables[i].table);
887 i++;
888 }
889 if (efi.hcdp) {
890 efi_tables[i].guid = HCDP_TABLE_GUID;
891 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.hcdp));
892 printf(" HCDP=0x%lx",efi_tables[i].table);
893 i++;
894 }
895 printf("\n");
896 } else {
897 i = 1;
899 if ((unsigned long)fw_mem + fw_mem_size - (unsigned long)cp >=
900 sizeof(struct fake_acpi_tables)) {
901 struct fake_acpi_tables *acpi_tables;
903 acpi_tables = (void *)cp;
904 cp += sizeof(struct fake_acpi_tables);
905 dom_fw_fake_acpi(d, acpi_tables);
907 efi_tables[i].guid = ACPI_20_TABLE_GUID;
908 efi_tables[i].table = dom_pa((unsigned long) acpi_tables);
909 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
910 i++;
911 }
912 }
914 /* fill in the SAL system table: */
915 memcpy(sal_systab->signature, "SST_", 4);
916 sal_systab->size = sizeof(*sal_systab);
917 sal_systab->sal_rev_minor = 1;
918 sal_systab->sal_rev_major = 0;
919 sal_systab->entry_count = 2;
921 strcpy((char *)sal_systab->oem_id, "Xen/ia64");
922 strcpy((char *)sal_systab->product_id, "Xen/ia64");
924 /* fill in an entry point: */
925 sal_ed->type = SAL_DESC_ENTRY_POINT;
926 sal_ed->pal_proc = FW_HYPERCALL_PAL_CALL_PADDR + start_mpaddr;
927 dom_fw_pal_hypercall_patch (d, sal_ed->pal_proc);
928 sal_ed->sal_proc = FW_HYPERCALL_SAL_CALL_PADDR + start_mpaddr;
929 dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
930 sal_ed->gp = 0; // will be ignored
932 /* Fill an AP wakeup descriptor. */
933 sal_wakeup->type = SAL_DESC_AP_WAKEUP;
934 sal_wakeup->mechanism = IA64_SAL_AP_EXTERNAL_INT;
935 sal_wakeup->vector = XEN_SAL_BOOT_RENDEZ_VEC;
937 for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
938 checksum += *cp;
940 sal_systab->checksum = -checksum;
942 i = 0;
943 if (d == dom0) {
944 #ifndef CONFIG_XEN_IA64_DOM0_VP
945 /*
946 * This is a bad hack. Dom0 may share other domains' memory
947 * through a dom0 physical address. Unfortunately, this
948 * address may be used in maddr_to_page (e.g. in the loopback
949 * driver) but when Linux initializes memory it only creates
950 * page structs for the physical memory it knows about. And
951 * on ia64, only for full writeback granules. So, we reserve
952 * the last full granule of Xen's memory for dom0 (in
953 * start_kernel) to ensure dom0 creates a large enough memmap
954 */
955 unsigned long last_start = max_page << PAGE_SHIFT;
956 unsigned long last_end = last_start + IA64_GRANULE_SIZE;
958 /* simulate 1MB free memory at physical address zero */
959 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0);//XXX
960 #endif
961 /* hypercall patches live here, masquerade as reserved PAL memory */
962 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0);
963 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem-IA64_GRANULE_SIZE, 0);//XXX make sure this doesn't overlap on i/o, runtime area.
964 #ifndef CONFIG_XEN_IA64_DOM0_VP
965 /* hack */ MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,last_start,last_end,1);
966 #endif
968 /* pass through the I/O port space */
969 if (!running_on_sim) {
970 struct dom0_passthrough_arg arg;
971 #ifdef CONFIG_XEN_IA64_DOM0_VP
972 arg.d = d;
973 #endif
974 arg.md = &efi_memmap[i];
975 arg.i = &i;
976 //XXX Is this needed?
977 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_CODE,
978 dom_fw_dom0_passthrough, &arg);
979 // for ACPI table.
980 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_DATA,
981 dom_fw_dom0_passthrough, &arg);
982 efi_memmap_walk_type(EFI_ACPI_RECLAIM_MEMORY,
983 dom_fw_dom0_passthrough, &arg);
984 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO,
985 dom_fw_dom0_passthrough, &arg);
986 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO_PORT_SPACE,
987 dom_fw_dom0_passthrough, &arg);
988 }
989 else MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
990 }
991 else {
992 #ifndef CONFIG_XEN_IA64_DOM0_VP
993 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 1);
994 #endif
995 /* hypercall patches live here, masquerade as reserved PAL memory */
996 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 1);
997 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 1);
998 /* Create a dummy entry for IO ports, so that IO accesses are
999 trapped by Xen. */
1000 MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE,EFI_MEMORY_UC,
1001 0x00000ffffc000000, 0x00000fffffffffff, 1);
1002 MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
1005 sort(efi_memmap, i, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);
1007 bp->efi_systab = dom_pa((unsigned long) fw_mem);
1008 bp->efi_memmap = dom_pa((unsigned long) efi_memmap);
1009 BUG_ON(i > NUM_MEM_DESCS);
1010 bp->efi_memmap_size = i * sizeof(efi_memory_desc_t);
1011 bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
1012 bp->efi_memdesc_version = 1;
1013 bp->command_line = dom_pa((unsigned long) cmd_line);
1014 bp->console_info.num_cols = 80;
1015 bp->console_info.num_rows = 25;
1016 bp->console_info.orig_x = 0;
1017 bp->console_info.orig_y = 24;
1018 bp->fpswa = 0;
1019 if (d == dom0) {
1020 // XXX CONFIG_XEN_IA64_DOM0_VP
1021 // initrd_start address is hard coded in start_kernel()
1022 bp->initrd_start = (dom0_start+dom0_size) -
1023 (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024);
1024 bp->initrd_size = ia64_boot_param->initrd_size;
1026 else {
1027 bp->initrd_start = d->arch.initrd_start;
1028 bp->initrd_size = d->arch.initrd_len;
1030 printf(" initrd start 0x%lx", bp->initrd_start);
1031 printf(" initrd size 0x%lx\n", bp->initrd_size);
1032 return bp;