ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 9768:63af1c14fa18

[IA64] missed chunk of Kevin's hypercall cleanup patch

Missed this chunk of Kevin's patch when merging with dom0vp changes

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author awilliam@xenbuild.aw
date Tue Apr 25 22:30:07 2006 -0600 (2006-04-25)
parents ae0d41bd3bba
children d23c088eac6d
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 /* The best we can do is to flush with fc all the domain. */
226 domain_cache_flush (current->domain, in1 == 4 ? 1 : 0);
227 status = 0;
228 break;
229 case SAL_CACHE_INIT:
230 printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
231 break;
232 case SAL_UPDATE_PAL:
233 printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
234 break;
235 default:
236 printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
237 status = -1;
238 break;
239 }
240 return ((struct sal_ret_values) {status, r9, r10, r11});
241 }
243 struct ia64_pal_retval
244 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
245 {
246 unsigned long r9 = 0;
247 unsigned long r10 = 0;
248 unsigned long r11 = 0;
249 long status = PAL_STATUS_UNIMPLEMENTED;
251 if (running_on_sim)
252 return pal_emulator_static(index);
254 // pal code must be mapped by a TR when pal is called, however
255 // calls are rare enough that we will map it lazily rather than
256 // at every context switch
257 //efi_map_pal_code();
258 switch (index) {
259 case PAL_MEM_ATTRIB:
260 status = ia64_pal_mem_attrib(&r9);
261 break;
262 case PAL_FREQ_BASE:
263 status = ia64_pal_freq_base(&r9);
264 break;
265 case PAL_PROC_GET_FEATURES:
266 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
267 break;
268 case PAL_BUS_GET_FEATURES:
269 status = ia64_pal_bus_get_features(
270 (pal_bus_features_u_t *) &r9,
271 (pal_bus_features_u_t *) &r10,
272 (pal_bus_features_u_t *) &r11);
273 break;
274 case PAL_FREQ_RATIOS:
275 status = ia64_pal_freq_ratios(
276 (struct pal_freq_ratio *) &r9,
277 (struct pal_freq_ratio *) &r10,
278 (struct pal_freq_ratio *) &r11);
279 break;
280 case PAL_PTCE_INFO:
281 {
282 // return hard-coded xen-specific values because ptc.e
283 // is emulated on xen to always flush everything
284 // these values result in only one ptc.e instruction
285 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
286 }
287 break;
288 case PAL_VERSION:
289 status = ia64_pal_version(
290 (pal_version_u_t *) &r9,
291 (pal_version_u_t *) &r10);
292 break;
293 case PAL_VM_PAGE_SIZE:
294 status = ia64_pal_vm_page_size(&r9,&r10);
295 break;
296 case PAL_DEBUG_INFO:
297 status = ia64_pal_debug_info(&r9,&r10);
298 break;
299 case PAL_CACHE_SUMMARY:
300 status = ia64_pal_cache_summary(&r9,&r10);
301 break;
302 case PAL_VM_SUMMARY:
303 {
304 /* Use xen-specific values.
305 hash_tag_id is somewhat random! */
306 const pal_vm_info_1_u_t v1 =
307 {.pal_vm_info_1_s =
308 { .vw = 1,
309 .phys_add_size = 44,
310 .key_size = 16,
311 .max_pkr = 15,
312 .hash_tag_id = 0x30,
313 .max_dtr_entry = NDTRS - 1,
314 .max_itr_entry = NITRS - 1,
315 #ifdef VHPT_GLOBAL
316 .max_unique_tcs = 3,
317 .num_tc_levels = 2
318 #else
319 .max_unique_tcs = 2,
320 .num_tc_levels = 1
321 #endif
322 }};
323 const pal_vm_info_2_u_t v2 =
324 { .pal_vm_info_2_s =
325 { .impl_va_msb = 50,
326 .rid_size = current->domain->arch.rid_bits,
327 .reserved = 0 }};
328 r9 = v1.pvi1_val;
329 r10 = v2.pvi2_val;
330 status = PAL_STATUS_SUCCESS;
331 }
332 break;
333 case PAL_VM_INFO:
334 #ifdef VHPT_GLOBAL
335 if (in1 == 0 && in2 == 2) {
336 /* Level 1: VHPT */
337 const pal_tc_info_u_t v =
338 { .pal_tc_info_s = {.num_sets = 128,
339 .associativity = 1,
340 .num_entries = 128,
341 .pf = 1,
342 .unified = 1,
343 .reduce_tr = 0,
344 .reserved = 0}};
345 r9 = v.pti_val;
346 /* Only support PAGE_SIZE tc. */
347 r10 = PAGE_SIZE;
348 status = PAL_STATUS_SUCCESS;
349 }
350 #endif
351 else if (
352 #ifdef VHPT_GLOBAL
353 in1 == 1 /* Level 2. */
354 #else
355 in1 == 0 /* Level 1. */
356 #endif
357 && (in2 == 1 || in2 == 2))
358 {
359 /* itlb/dtlb, 1 entry. */
360 const pal_tc_info_u_t v =
361 { .pal_tc_info_s = {.num_sets = 1,
362 .associativity = 1,
363 .num_entries = 1,
364 .pf = 1,
365 .unified = 0,
366 .reduce_tr = 0,
367 .reserved = 0}};
368 r9 = v.pti_val;
369 /* Only support PAGE_SIZE tc. */
370 r10 = PAGE_SIZE;
371 status = PAL_STATUS_SUCCESS;
372 }
373 else
374 status = PAL_STATUS_EINVAL;
375 break;
376 case PAL_RSE_INFO:
377 status = ia64_pal_rse_info(
378 &r9,
379 (pal_hints_u_t *) &r10);
380 break;
381 case PAL_REGISTER_INFO:
382 status = ia64_pal_register_info(in1, &r9, &r10);
383 break;
384 case PAL_CACHE_FLUSH:
385 /* FIXME */
386 printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
387 BUG();
388 break;
389 case PAL_PERF_MON_INFO:
390 {
391 unsigned long pm_buffer[16];
392 status = ia64_pal_perf_mon_info(
393 pm_buffer,
394 (pal_perf_mon_info_u_t *) &r9);
395 if (status != 0) {
396 while(1)
397 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
398 break;
399 }
400 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
401 while(1)
402 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
403 "can't copy to user!!!!\n");
404 status = PAL_STATUS_UNIMPLEMENTED;
405 break;
406 }
407 }
408 break;
409 case PAL_CACHE_INFO:
410 {
411 pal_cache_config_info_t ci;
412 status = ia64_pal_cache_config_info(in1,in2,&ci);
413 if (status != 0) break;
414 r9 = ci.pcci_info_1.pcci1_data;
415 r10 = ci.pcci_info_2.pcci2_data;
416 }
417 break;
418 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
419 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
420 break;
421 case PAL_HALT_INFO:
422 {
423 /* 1000 cycles to enter/leave low power state,
424 consumes 10 mW, implemented and cache/TLB coherent. */
425 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
426 | (1UL << 61) | (1UL << 60);
427 if (copy_to_user ((void *)in1, &res, sizeof (res)))
428 status = PAL_STATUS_EINVAL;
429 else
430 status = PAL_STATUS_SUCCESS;
431 }
432 break;
433 case PAL_HALT:
434 if (current->domain == dom0) {
435 printf ("Domain0 halts the machine\n");
436 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
437 }
438 else
439 domain_shutdown (current->domain,
440 SHUTDOWN_poweroff);
441 break;
442 default:
443 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
444 index);
445 break;
446 }
447 return ((struct ia64_pal_retval) {status, r9, r10, r11});
448 }
451 #define NFUNCPTRS 20
453 static void print_md(efi_memory_desc_t *md)
454 {
455 #if 1
456 printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
457 md->type, md->attribute, md->phys_addr,
458 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
459 md->num_pages >> (20 - EFI_PAGE_SHIFT));
460 #endif
461 }
464 static u32 lsapic_nbr;
466 /* Modify lsapic table. Provides LPs. */
467 static int
468 acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
469 {
470 struct acpi_table_lsapic *lsapic;
471 int enable;
473 lsapic = (struct acpi_table_lsapic *) header;
474 if (!lsapic)
475 return -EINVAL;
477 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
478 enable = 1;
479 else
480 enable = 0;
481 if (lsapic->flags.enabled && enable) {
482 printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
483 lsapic_nbr++;
484 } else if (lsapic->flags.enabled) {
485 printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
486 lsapic->flags.enabled = 0;
487 }
488 return 0;
489 }
491 static u8
492 generate_acpi_checksum(void *tbl, unsigned long len)
493 {
494 u8 *ptr, sum = 0;
496 for (ptr = tbl; len > 0 ; len--, ptr++)
497 sum += *ptr;
499 return 0 - sum;
500 }
502 static int
503 acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
504 {
505 struct acpi_table_madt* acpi_madt;
507 if (!phys_addr || !size)
508 return -EINVAL;
510 acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
511 acpi_madt->header.checksum = 0;
512 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
514 return 0;
515 }
517 /* base is physical address of acpi table */
518 static void touch_acpi_table(void)
519 {
520 lsapic_nbr = 0;
521 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
522 printk("Error parsing MADT - no LAPIC entires\n");
523 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
525 return;
526 }
528 struct fake_acpi_tables {
529 struct acpi20_table_rsdp rsdp;
530 struct xsdt_descriptor_rev2 xsdt;
531 u64 madt_ptr;
532 struct fadt_descriptor_rev2 fadt;
533 struct facs_descriptor_rev2 facs;
534 struct acpi_table_header dsdt;
535 u8 aml[16];
536 struct acpi_table_madt madt;
537 struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
538 u8 pm1a_evt_blk[4];
539 u8 pm1a_cnt_blk[1];
540 u8 pm_tmr_blk[4];
541 };
543 /* Create enough of an ACPI structure to make the guest OS ACPI happy. */
544 static void
545 dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
546 {
547 struct acpi20_table_rsdp *rsdp = &tables->rsdp;
548 struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
549 struct fadt_descriptor_rev2 *fadt = &tables->fadt;
550 struct facs_descriptor_rev2 *facs = &tables->facs;
551 struct acpi_table_header *dsdt = &tables->dsdt;
552 struct acpi_table_madt *madt = &tables->madt;
553 struct acpi_table_lsapic *lsapic = tables->lsapic;
554 int i;
556 memset(tables, 0, sizeof(struct fake_acpi_tables));
558 /* setup XSDT (64bit version of RSDT) */
559 strncpy(xsdt->signature, XSDT_SIG, 4);
560 /* XSDT points to both the FADT and the MADT, so add one entry */
561 xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
562 xsdt->revision = 1;
563 strcpy(xsdt->oem_id, "XEN");
564 strcpy(xsdt->oem_table_id, "Xen/ia64");
565 strcpy(xsdt->asl_compiler_id, "XEN");
566 xsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
568 xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt);
569 tables->madt_ptr = dom_pa((unsigned long) madt);
571 xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
573 /* setup FADT */
574 strncpy(fadt->signature, FADT_SIG, 4);
575 fadt->length = sizeof(struct fadt_descriptor_rev2);
576 fadt->revision = FADT2_REVISION_ID;
577 strcpy(fadt->oem_id, "XEN");
578 strcpy(fadt->oem_table_id, "Xen/ia64");
579 strcpy(fadt->asl_compiler_id, "XEN");
580 fadt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
582 strncpy(facs->signature, FACS_SIG, 4);
583 facs->version = 1;
584 facs->length = sizeof(struct facs_descriptor_rev2);
586 fadt->xfirmware_ctrl = dom_pa((unsigned long) facs);
587 fadt->Xdsdt = dom_pa((unsigned long) dsdt);
589 /*
590 * All of the below FADT entries are filled it to prevent warnings
591 * from sanity checks in the ACPI CA. Emulate required ACPI hardware
592 * registers in system memory.
593 */
594 fadt->pm1_evt_len = 4;
595 fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
596 fadt->xpm1a_evt_blk.register_bit_width = 8;
597 fadt->xpm1a_evt_blk.address = dom_pa((unsigned long) &tables->pm1a_evt_blk);
598 fadt->pm1_cnt_len = 1;
599 fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
600 fadt->xpm1a_cnt_blk.register_bit_width = 8;
601 fadt->xpm1a_cnt_blk.address = dom_pa((unsigned long) &tables->pm1a_cnt_blk);
602 fadt->pm_tm_len = 4;
603 fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
604 fadt->xpm_tmr_blk.register_bit_width = 8;
605 fadt->xpm_tmr_blk.address = dom_pa((unsigned long) &tables->pm_tmr_blk);
607 fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
609 /* setup RSDP */
610 strncpy(rsdp->signature, RSDP_SIG, 8);
611 strcpy(rsdp->oem_id, "XEN");
612 rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
613 rsdp->length = sizeof(struct acpi20_table_rsdp);
614 rsdp->xsdt_address = dom_pa((unsigned long) xsdt);
616 rsdp->checksum = generate_acpi_checksum(rsdp,
617 ACPI_RSDP_CHECKSUM_LENGTH);
618 rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
620 /* setup DSDT with trivial namespace. */
621 strncpy(dsdt->signature, DSDT_SIG, 4);
622 dsdt->revision = 1;
623 dsdt->length = sizeof(struct acpi_table_header) + sizeof(tables->aml);
624 strcpy(dsdt->oem_id, "XEN");
625 strcpy(dsdt->oem_table_id, "Xen/ia64");
626 strcpy(dsdt->asl_compiler_id, "XEN");
627 dsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
629 /* Trivial namespace, avoids ACPI CA complaints */
630 tables->aml[0] = 0x10; /* Scope */
631 tables->aml[1] = 0x12; /* length/offset to next object */
632 strncpy((char *)&tables->aml[2], "_SB_", 4);
634 /* The processor object isn't absolutely necessary, revist for SMP */
635 tables->aml[6] = 0x5b; /* processor object */
636 tables->aml[7] = 0x83;
637 tables->aml[8] = 0x0b; /* next */
638 strncpy((char *)&tables->aml[9], "CPU0", 4);
640 dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
642 /* setup MADT */
643 strncpy(madt->header.signature, APIC_SIG, 4);
644 madt->header.revision = 2;
645 madt->header.length = sizeof(struct acpi_table_madt) +
646 MAX_VIRT_CPUS * sizeof(struct acpi_table_lsapic);
647 strcpy(madt->header.oem_id, "XEN");
648 strcpy(madt->header.oem_table_id, "Xen/ia64");
649 strcpy(madt->header.asl_compiler_id, "XEN");
650 madt->header.asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
652 /* An LSAPIC entry describes a CPU. */
653 for (i = 0; i < MAX_VIRT_CPUS; i++) {
654 lsapic[i].header.type = ACPI_MADT_LSAPIC;
655 lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
656 lsapic[i].id = i;
657 lsapic[i].eid = 0;
658 lsapic[i].flags.enabled = (d->vcpu[i] != NULL);
659 }
661 madt->header.checksum = generate_acpi_checksum(madt,
662 madt->header.length);
663 return;
664 }
666 #define NUM_EFI_SYS_TABLES 6
667 #define NUM_MEM_DESCS 64 //large enough
669 struct dom0_passthrough_arg {
670 #ifdef CONFIG_XEN_IA64_DOM0_VP
671 struct domain* d;
672 #endif
673 efi_memory_desc_t *md;
674 int* i;
675 };
677 static int
678 dom_fw_dom0_passthrough(efi_memory_desc_t *md, void *arg__)
679 {
680 struct dom0_passthrough_arg* arg = (struct dom0_passthrough_arg*)arg__;
681 unsigned long paddr;
683 #ifdef CONFIG_XEN_IA64_DOM0_VP
684 struct domain* d = arg->d;
685 u64 start = md->phys_addr;
686 u64 end = start + (md->num_pages << EFI_PAGE_SHIFT);
688 if (md->type == EFI_MEMORY_MAPPED_IO ||
689 md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
691 //XXX some machine has large mmio area whose size is about several TB.
692 // It requires impractical memory to map such a huge region
693 // to a domain.
694 // For now we don't map it, but later we must fix this.
695 if (md->type == EFI_MEMORY_MAPPED_IO &&
696 ((md->num_pages << EFI_PAGE_SHIFT) > 0x100000000UL))
697 return 0;
699 paddr = assign_domain_mmio_page(d, start, end - start);
700 } else
701 paddr = assign_domain_mach_page(d, start, end - start);
702 #else
703 paddr = md->phys_addr;
704 #endif
706 BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
707 md->type != EFI_RUNTIME_SERVICES_DATA &&
708 md->type != EFI_ACPI_RECLAIM_MEMORY &&
709 md->type != EFI_MEMORY_MAPPED_IO &&
710 md->type != EFI_MEMORY_MAPPED_IO_PORT_SPACE);
712 arg->md->type = md->type;
713 arg->md->pad = 0;
714 arg->md->phys_addr = paddr;
715 arg->md->virt_addr = 0;
716 arg->md->num_pages = md->num_pages;
717 arg->md->attribute = md->attribute;
718 print_md(arg->md);
720 (*arg->i)++;
721 arg->md++;
722 return 0;
723 }
725 static int
726 efi_mdt_cmp(const void *a, const void *b)
727 {
728 const efi_memory_desc_t *x = a, *y = b;
730 if (x->phys_addr > y->phys_addr)
731 return 1;
732 if (x->phys_addr < y->phys_addr)
733 return -1;
734 return 0;
735 }
737 static struct ia64_boot_param *
738 dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size)
739 {
740 efi_system_table_t *efi_systab;
741 efi_runtime_services_t *efi_runtime;
742 efi_config_table_t *efi_tables;
743 struct ia64_sal_systab *sal_systab;
744 struct ia64_sal_desc_entry_point *sal_ed;
745 struct ia64_sal_desc_ap_wakeup *sal_wakeup;
746 efi_memory_desc_t *efi_memmap, *md;
747 struct ia64_boot_param *bp;
748 unsigned long *pfn;
749 unsigned char checksum = 0;
750 char *cp, *cmd_line, *fw_vendor;
751 int i = 0;
752 unsigned long maxmem = (d->max_pages - d->arch.sys_pgnr) * PAGE_SIZE;
753 #ifdef CONFIG_XEN_IA64_DOM0_VP
754 const unsigned long start_mpaddr = 0;
755 #else
756 const unsigned long start_mpaddr = ((d==dom0)?dom0_start:0);
757 #endif
759 # define MAKE_MD(typ, attr, start, end, abs) \
760 do { \
761 md = efi_memmap + i++; \
762 md->type = typ; \
763 md->pad = 0; \
764 md->phys_addr = abs ? start : start_mpaddr + start; \
765 md->virt_addr = 0; \
766 md->num_pages = (end - start) >> 12; \
767 md->attribute = attr; \
768 print_md(md); \
769 } while (0)
771 /* FIXME: should check size but for now we have a whole MB to play with.
772 And if stealing code from fw-emu.c, watch out for new fw_vendor on the end!
773 if (fw_mem_size < sizeof(fw_mem_proto)) {
774 printf("sys_fw_init: insufficient space for fw_mem\n");
775 return 0;
776 }
777 */
778 memset(fw_mem, 0, fw_mem_size);
780 cp = fw_mem;
781 efi_systab = (void *) cp; cp += sizeof(*efi_systab);
782 efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
783 efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
784 sal_systab = (void *) cp; cp += sizeof(*sal_systab);
785 sal_ed = (void *) cp; cp += sizeof(*sal_ed);
786 sal_wakeup = (void *) cp; cp += sizeof(*sal_wakeup);
787 efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
788 bp = (void *) cp; cp += sizeof(*bp);
789 pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
790 cmd_line = (void *) cp;
792 if (args) {
793 if (arglen >= 1024)
794 arglen = 1023;
795 memcpy(cmd_line, args, arglen);
796 } else {
797 arglen = 0;
798 }
799 cmd_line[arglen] = '\0';
801 memset(efi_systab, 0, sizeof(efi_systab));
802 efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
803 efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
804 efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
805 cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary
806 #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"
807 cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary
809 memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
810 efi_systab->fw_vendor = dom_pa((unsigned long) fw_vendor);
812 efi_systab->fw_revision = 1;
813 efi_systab->runtime = (void *) dom_pa((unsigned long) efi_runtime);
814 efi_systab->nr_tables = NUM_EFI_SYS_TABLES;
815 efi_systab->tables = dom_pa((unsigned long) efi_tables);
817 efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
818 efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
819 efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
820 #define EFI_HYPERCALL_PATCH(tgt,call) do { \
821 dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \
822 tgt = dom_pa((unsigned long) pfn); \
823 *pfn++ = FW_HYPERCALL_##call##_PADDR + start_mpaddr; \
824 *pfn++ = 0; \
825 } while (0)
827 EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME);
828 EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME);
829 EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
830 EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
831 EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
832 EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE);
833 EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
834 EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE);
835 EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
836 EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM);
838 efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
839 efi_tables[0].table = dom_pa((unsigned long) sal_systab);
840 for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
841 efi_tables[i].guid = NULL_GUID;
842 efi_tables[i].table = 0;
843 }
844 if (d == dom0) {
845 #ifdef CONFIG_XEN_IA64_DOM0_VP
846 # define ASSIGN_DOMAIN_MACH_PAGE(d, p) assign_domain_mach_page(d, p, PAGE_SIZE)
847 #else
848 # define ASSIGN_DOMAIN_MACH_PAGE(d, p) ({p;})
849 #endif
851 printf("Domain0 EFI passthrough:");
852 i = 1;
853 if (efi.mps) {
854 efi_tables[i].guid = MPS_TABLE_GUID;
855 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.mps));
856 printf(" MPS=0x%lx",efi_tables[i].table);
857 i++;
858 }
860 touch_acpi_table();
862 if (efi.acpi20) {
863 efi_tables[i].guid = ACPI_20_TABLE_GUID;
864 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.acpi20));
865 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
866 i++;
867 }
868 if (efi.acpi) {
869 efi_tables[i].guid = ACPI_TABLE_GUID;
870 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.acpi));
871 printf(" ACPI=0x%lx",efi_tables[i].table);
872 i++;
873 }
874 if (efi.smbios) {
875 efi_tables[i].guid = SMBIOS_TABLE_GUID;
876 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.smbios));
877 printf(" SMBIOS=0x%lx",efi_tables[i].table);
878 i++;
879 }
880 if (efi.hcdp) {
881 efi_tables[i].guid = HCDP_TABLE_GUID;
882 efi_tables[i].table = ASSIGN_DOMAIN_MACH_PAGE(d, __pa(efi.hcdp));
883 printf(" HCDP=0x%lx",efi_tables[i].table);
884 i++;
885 }
886 printf("\n");
887 } else {
888 i = 1;
890 if ((unsigned long)fw_mem + fw_mem_size - (unsigned long)cp >=
891 sizeof(struct fake_acpi_tables)) {
892 struct fake_acpi_tables *acpi_tables;
894 acpi_tables = (void *)cp;
895 cp += sizeof(struct fake_acpi_tables);
896 dom_fw_fake_acpi(d, acpi_tables);
898 efi_tables[i].guid = ACPI_20_TABLE_GUID;
899 efi_tables[i].table = dom_pa((unsigned long) acpi_tables);
900 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
901 i++;
902 }
903 }
905 /* fill in the SAL system table: */
906 memcpy(sal_systab->signature, "SST_", 4);
907 sal_systab->size = sizeof(*sal_systab);
908 sal_systab->sal_rev_minor = 1;
909 sal_systab->sal_rev_major = 0;
910 sal_systab->entry_count = 2;
912 strcpy((char *)sal_systab->oem_id, "Xen/ia64");
913 strcpy((char *)sal_systab->product_id, "Xen/ia64");
915 /* fill in an entry point: */
916 sal_ed->type = SAL_DESC_ENTRY_POINT;
917 sal_ed->pal_proc = FW_HYPERCALL_PAL_CALL_PADDR + start_mpaddr;
918 dom_fw_pal_hypercall_patch (d, sal_ed->pal_proc);
919 sal_ed->sal_proc = FW_HYPERCALL_SAL_CALL_PADDR + start_mpaddr;
920 dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
921 sal_ed->gp = 0; // will be ignored
923 /* Fill an AP wakeup descriptor. */
924 sal_wakeup->type = SAL_DESC_AP_WAKEUP;
925 sal_wakeup->mechanism = IA64_SAL_AP_EXTERNAL_INT;
926 sal_wakeup->vector = XEN_SAL_BOOT_RENDEZ_VEC;
928 for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
929 checksum += *cp;
931 sal_systab->checksum = -checksum;
933 i = 0;
934 if (d == dom0) {
935 #ifndef CONFIG_XEN_IA64_DOM0_VP
936 /*
937 * This is a bad hack. Dom0 may share other domains' memory
938 * through a dom0 physical address. Unfortunately, this
939 * address may be used in maddr_to_page (e.g. in the loopback
940 * driver) but when Linux initializes memory it only creates
941 * page structs for the physical memory it knows about. And
942 * on ia64, only for full writeback granules. So, we reserve
943 * the last full granule of Xen's memory for dom0 (in
944 * start_kernel) to ensure dom0 creates a large enough memmap
945 */
946 unsigned long last_start = max_page << PAGE_SHIFT;
947 unsigned long last_end = last_start + IA64_GRANULE_SIZE;
949 /* simulate 1MB free memory at physical address zero */
950 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0);//XXX
951 #endif
952 /* hypercall patches live here, masquerade as reserved PAL memory */
953 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0);
954 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.
955 #ifndef CONFIG_XEN_IA64_DOM0_VP
956 /* hack */ MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,last_start,last_end,1);
957 #endif
959 /* pass through the I/O port space */
960 if (!running_on_sim) {
961 struct dom0_passthrough_arg arg;
962 #ifdef CONFIG_XEN_IA64_DOM0_VP
963 arg.d = d;
964 #endif
965 arg.md = &efi_memmap[i];
966 arg.i = &i;
967 //XXX Is this needed?
968 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_CODE,
969 dom_fw_dom0_passthrough, &arg);
970 // for ACPI table.
971 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_DATA,
972 dom_fw_dom0_passthrough, &arg);
973 efi_memmap_walk_type(EFI_ACPI_RECLAIM_MEMORY,
974 dom_fw_dom0_passthrough, &arg);
975 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO,
976 dom_fw_dom0_passthrough, &arg);
977 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO_PORT_SPACE,
978 dom_fw_dom0_passthrough, &arg);
979 }
980 else MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
981 }
982 else {
983 #ifndef CONFIG_XEN_IA64_DOM0_VP
984 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 1);
985 #endif
986 /* hypercall patches live here, masquerade as reserved PAL memory */
987 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 1);
988 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 1);
989 /* Create a dummy entry for IO ports, so that IO accesses are
990 trapped by Xen. */
991 MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE,EFI_MEMORY_UC,
992 0x00000ffffc000000, 0x00000fffffffffff, 1);
993 MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
994 }
996 sort(efi_memmap, i, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);
998 bp->efi_systab = dom_pa((unsigned long) fw_mem);
999 bp->efi_memmap = dom_pa((unsigned long) efi_memmap);
1000 BUG_ON(i > NUM_MEM_DESCS);
1001 bp->efi_memmap_size = i * sizeof(efi_memory_desc_t);
1002 bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
1003 bp->efi_memdesc_version = 1;
1004 bp->command_line = dom_pa((unsigned long) cmd_line);
1005 bp->console_info.num_cols = 80;
1006 bp->console_info.num_rows = 25;
1007 bp->console_info.orig_x = 0;
1008 bp->console_info.orig_y = 24;
1009 bp->fpswa = 0;
1010 if (d == dom0) {
1011 // XXX CONFIG_XEN_IA64_DOM0_VP
1012 // initrd_start address is hard coded in start_kernel()
1013 bp->initrd_start = (dom0_start+dom0_size) -
1014 (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024);
1015 bp->initrd_size = ia64_boot_param->initrd_size;
1017 else {
1018 bp->initrd_start = d->arch.initrd_start;
1019 bp->initrd_size = d->arch.initrd_len;
1021 printf(" initrd start 0x%lx", bp->initrd_start);
1022 printf(" initrd size 0x%lx\n", bp->initrd_size);
1023 return bp;