ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 9405:29dfadcc5029

[IA64] Followup to xen time cleanup

Clean up to xen time handler. Tristan #if 0 some code because it seems
redundant, which however is actually problematic logic as a reason for
an intermittent timer oops issue of dom0. So delete it now.

Also remove vcpu_wake, since wakeup current has nothing meaningful and
simply waste cpu cycle.

Signed-off-by: Kevin Tian <kevin.tian@intel.com>
author awilliam@xenbuild.aw
date Mon Mar 27 15:32:08 2006 -0700 (2006-03-27)
parents f517be67eeac
children ddc279c91502
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 <asm/io.h>
14 #include <asm/pal.h>
15 #include <asm/sal.h>
16 #include <asm/meminit.h>
17 #include <xen/compile.h>
18 #include <xen/acpi.h>
20 #include <asm/dom_fw.h>
21 #include <public/sched.h>
23 static struct ia64_boot_param *dom_fw_init(struct domain *, const char *,int,char *,int);
24 extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr);
25 extern struct domain *dom0;
26 extern unsigned long dom0_start;
28 extern unsigned long running_on_sim;
31 unsigned long dom_fw_base_mpa = -1;
32 unsigned long imva_fw_base = -1;
34 // return domain (meta)physical address for a given imva
35 // this function is a call-back from dom_fw_init
36 unsigned long dom_pa(unsigned long imva)
37 {
38 if (dom_fw_base_mpa == -1 || imva_fw_base == -1) {
39 printf("dom_pa: uninitialized! (spinning...)\n");
40 while(1);
41 }
42 if (imva - imva_fw_base > PAGE_SIZE) {
43 printf("dom_pa: bad offset! imva=0x%lx, imva_fw_base=0x%lx (spinning...)\n",
44 imva, imva_fw_base);
45 while(1);
46 }
47 return dom_fw_base_mpa + (imva - imva_fw_base);
48 }
50 // builds a hypercall bundle at domain physical address
51 static void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall)
52 {
53 unsigned long *imva;
55 if (d == dom0) paddr += dom0_start;
56 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
57 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, 1);
58 }
61 // builds a hypercall bundle at domain physical address
62 static void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret)
63 {
64 unsigned long *imva;
66 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
67 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, ret);
68 }
70 static void dom_fw_pal_hypercall_patch(struct domain *d, unsigned long paddr)
71 {
72 unsigned long *imva;
74 imva = (unsigned long *) domain_mpa_to_imva(d, paddr);
75 build_pal_hypercall_bundles(imva, d->arch.breakimm, FW_HYPERCALL_PAL_CALL);
76 }
79 // FIXME: This is really a hack: Forcing the boot parameter block
80 // at domain mpaddr 0 page, then grabbing only the low bits of the
81 // Xen imva, which is the offset into the page
82 unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen)
83 {
84 struct ia64_boot_param *bp;
86 dom_fw_base_mpa = 0;
87 if (d == dom0) dom_fw_base_mpa += dom0_start;
88 imva_fw_base = domain_mpa_to_imva(d, dom_fw_base_mpa);
89 bp = dom_fw_init(d, args, arglen, (char *) imva_fw_base, PAGE_SIZE);
90 return dom_pa((unsigned long) bp);
91 }
94 /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */
96 #define NUM_EFI_SYS_TABLES 6
97 # define NUM_MEM_DESCS 5
100 struct sal_ret_values
101 sal_emulator (long index, unsigned long in1, unsigned long in2,
102 unsigned long in3, unsigned long in4, unsigned long in5,
103 unsigned long in6, unsigned long in7)
104 {
105 unsigned long r9 = 0;
106 unsigned long r10 = 0;
107 long r11 = 0;
108 long status;
110 status = 0;
111 switch (index) {
112 case SAL_FREQ_BASE:
113 if (!running_on_sim)
114 status = ia64_sal_freq_base(in1,&r9,&r10);
115 else switch (in1) {
116 case SAL_FREQ_BASE_PLATFORM:
117 r9 = 200000000;
118 break;
120 case SAL_FREQ_BASE_INTERVAL_TIMER:
121 r9 = 700000000;
122 break;
124 case SAL_FREQ_BASE_REALTIME_CLOCK:
125 r9 = 1;
126 break;
128 default:
129 status = -1;
130 break;
131 }
132 break;
133 case SAL_PCI_CONFIG_READ:
134 if (current->domain == dom0) {
135 u64 value;
136 // note that args 2&3 are swapped!!
137 status = ia64_sal_pci_config_read(in1,in3,in2,&value);
138 r9 = value;
139 }
140 else
141 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n");
142 break;
143 case SAL_PCI_CONFIG_WRITE:
144 if (current->domain == dom0) {
145 if (((in1 & ~0xffffffffUL) && (in4 == 0)) ||
146 (in4 > 1) ||
147 (in2 > 8) || (in2 & (in2-1)))
148 printf("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n",
149 in1,in4,in2,in3);
150 // note that args are in a different order!!
151 status = ia64_sal_pci_config_write(in1,in4,in2,in3);
152 }
153 else
154 printf("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n");
155 break;
156 case SAL_SET_VECTORS:
157 printf("*** CALLED SAL_SET_VECTORS. IGNORED...\n");
158 break;
159 case SAL_GET_STATE_INFO:
160 printf("*** CALLED SAL_GET_STATE_INFO. IGNORED...\n");
161 break;
162 case SAL_GET_STATE_INFO_SIZE:
163 printf("*** CALLED SAL_GET_STATE_INFO_SIZE. IGNORED...\n");
164 break;
165 case SAL_CLEAR_STATE_INFO:
166 printf("*** CALLED SAL_CLEAR_STATE_INFO. IGNORED...\n");
167 break;
168 case SAL_MC_RENDEZ:
169 printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
170 break;
171 case SAL_MC_SET_PARAMS:
172 printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
173 break;
174 case SAL_CACHE_FLUSH:
175 printf("*** CALLED SAL_CACHE_FLUSH. IGNORED...\n");
176 break;
177 case SAL_CACHE_INIT:
178 printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
179 break;
180 case SAL_UPDATE_PAL:
181 printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
182 break;
183 default:
184 printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
185 status = -1;
186 break;
187 }
188 return ((struct sal_ret_values) {status, r9, r10, r11});
189 }
191 struct ia64_pal_retval
192 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
193 {
194 unsigned long r9 = 0;
195 unsigned long r10 = 0;
196 unsigned long r11 = 0;
197 long status = -1;
199 if (running_on_sim)
200 return pal_emulator_static(index);
202 // pal code must be mapped by a TR when pal is called, however
203 // calls are rare enough that we will map it lazily rather than
204 // at every context switch
205 //efi_map_pal_code();
206 switch (index) {
207 case PAL_MEM_ATTRIB:
208 status = ia64_pal_mem_attrib(&r9);
209 break;
210 case PAL_FREQ_BASE:
211 status = ia64_pal_freq_base(&r9);
212 break;
213 case PAL_PROC_GET_FEATURES:
214 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
215 break;
216 case PAL_BUS_GET_FEATURES:
217 status = ia64_pal_bus_get_features(
218 (pal_bus_features_u_t *) &r9,
219 (pal_bus_features_u_t *) &r10,
220 (pal_bus_features_u_t *) &r11);
221 break;
222 case PAL_FREQ_RATIOS:
223 status = ia64_pal_freq_ratios(
224 (struct pal_freq_ratio *) &r9,
225 (struct pal_freq_ratio *) &r10,
226 (struct pal_freq_ratio *) &r11);
227 break;
228 case PAL_PTCE_INFO:
229 {
230 // return hard-coded xen-specific values because ptc.e
231 // is emulated on xen to always flush everything
232 // these values result in only one ptc.e instruction
233 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
234 }
235 break;
236 case PAL_VERSION:
237 status = ia64_pal_version(
238 (pal_version_u_t *) &r9,
239 (pal_version_u_t *) &r10);
240 break;
241 case PAL_VM_PAGE_SIZE:
242 status = ia64_pal_vm_page_size(&r9,&r10);
243 break;
244 case PAL_DEBUG_INFO:
245 status = ia64_pal_debug_info(&r9,&r10);
246 break;
247 case PAL_CACHE_SUMMARY:
248 status = ia64_pal_cache_summary(&r9,&r10);
249 break;
250 case PAL_VM_SUMMARY:
251 // FIXME: what should xen return for these, figure out later
252 // For now, linux does the right thing if pal call fails
253 // In particular, rid_size must be set properly!
254 //status = ia64_pal_vm_summary(
255 // (pal_vm_info_1_u_t *) &r9,
256 // (pal_vm_info_2_u_t *) &r10);
257 break;
258 case PAL_RSE_INFO:
259 status = ia64_pal_rse_info(
260 &r9,
261 (pal_hints_u_t *) &r10);
262 break;
263 case PAL_VM_INFO:
264 status = ia64_pal_vm_info(
265 in1,
266 in2,
267 (pal_tc_info_u_t *) &r9,
268 &r10);
269 break;
270 case PAL_REGISTER_INFO:
271 status = ia64_pal_register_info(in1, &r9, &r10);
272 break;
273 case PAL_CACHE_FLUSH:
274 /* FIXME */
275 printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
276 BUG();
277 break;
278 case PAL_PERF_MON_INFO:
279 {
280 unsigned long pm_buffer[16];
281 status = ia64_pal_perf_mon_info(
282 pm_buffer,
283 (pal_perf_mon_info_u_t *) &r9);
284 if (status != 0) {
285 while(1)
286 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
287 break;
288 }
289 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
290 while(1)
291 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
292 "can't copy to user!!!!\n");
293 status = -1;
294 break;
295 }
296 }
297 break;
298 case PAL_CACHE_INFO:
299 {
300 pal_cache_config_info_t ci;
301 status = ia64_pal_cache_config_info(in1,in2,&ci);
302 if (status != 0) break;
303 r9 = ci.pcci_info_1.pcci1_data;
304 r10 = ci.pcci_info_2.pcci2_data;
305 }
306 break;
307 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
308 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
309 break;
310 case PAL_HALT_INFO:
311 {
312 /* 1000 cycles to enter/leave low power state,
313 consumes 10 mW, implemented and cache/TLB coherent. */
314 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
315 | (1UL << 61) | (1UL << 60);
316 if (copy_to_user ((void *)in1, &res, sizeof (res)))
317 status = PAL_STATUS_EINVAL;
318 else
319 status = PAL_STATUS_SUCCESS;
320 }
321 break;
322 case PAL_HALT:
323 if (current->domain == dom0) {
324 printf ("Domain0 halts the machine\n");
325 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
326 }
327 else
328 domain_shutdown (current->domain,
329 SHUTDOWN_poweroff);
330 break;
331 default:
332 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
333 index);
334 break;
335 }
336 return ((struct ia64_pal_retval) {status, r9, r10, r11});
337 }
340 #define NFUNCPTRS 20
342 static void print_md(efi_memory_desc_t *md)
343 {
344 #if 1
345 printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
346 md->type, md->attribute, md->phys_addr,
347 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
348 md->num_pages >> (20 - EFI_PAGE_SHIFT));
349 #endif
350 }
353 static u32 lsapic_nbr;
355 /* Modify lsapic table. Provides LPs. */
356 static int
357 acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
358 {
359 struct acpi_table_lsapic *lsapic;
360 int enable;
362 lsapic = (struct acpi_table_lsapic *) header;
363 if (!lsapic)
364 return -EINVAL;
366 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
367 enable = 1;
368 else
369 enable = 0;
370 if (lsapic->flags.enabled && enable) {
371 printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
372 lsapic_nbr++;
373 } else if (lsapic->flags.enabled) {
374 printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
375 lsapic->flags.enabled = 0;
376 }
377 return 0;
378 }
380 static u8
381 generate_acpi_checksum(void *tbl, unsigned long len)
382 {
383 u8 *ptr, sum = 0;
385 for (ptr = tbl; len > 0 ; len--, ptr++)
386 sum += *ptr;
388 return 0 - sum;
389 }
391 static int
392 acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
393 {
394 struct acpi_table_madt* acpi_madt;
396 if (!phys_addr || !size)
397 return -EINVAL;
399 acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
400 acpi_madt->header.checksum = 0;
401 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
403 return 0;
404 }
406 /* base is physical address of acpi table */
407 static void touch_acpi_table(void)
408 {
409 lsapic_nbr = 0;
410 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
411 printk("Error parsing MADT - no LAPIC entires\n");
412 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
414 return;
415 }
417 struct fake_acpi_tables {
418 struct acpi20_table_rsdp rsdp;
419 struct xsdt_descriptor_rev2 xsdt;
420 u64 madt_ptr;
421 struct fadt_descriptor_rev2 fadt;
422 struct facs_descriptor_rev2 facs;
423 struct acpi_table_header dsdt;
424 u8 aml[16];
425 struct acpi_table_madt madt;
426 struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
427 u8 pm1a_evt_blk[4];
428 u8 pm1a_cnt_blk[1];
429 u8 pm_tmr_blk[4];
430 };
432 /* Create enough of an ACPI structure to make the guest OS ACPI happy. */
433 static void
434 dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
435 {
436 struct acpi20_table_rsdp *rsdp = &tables->rsdp;
437 struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
438 struct fadt_descriptor_rev2 *fadt = &tables->fadt;
439 struct facs_descriptor_rev2 *facs = &tables->facs;
440 struct acpi_table_header *dsdt = &tables->dsdt;
441 struct acpi_table_madt *madt = &tables->madt;
442 struct acpi_table_lsapic *lsapic = tables->lsapic;
443 int i;
445 memset(tables, 0, sizeof(struct fake_acpi_tables));
447 /* setup XSDT (64bit version of RSDT) */
448 strncpy(xsdt->signature, XSDT_SIG, 4);
449 /* XSDT points to both the FADT and the MADT, so add one entry */
450 xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
451 xsdt->revision = 1;
452 strcpy(xsdt->oem_id, "XEN");
453 strcpy(xsdt->oem_table_id, "Xen/ia64");
454 strcpy(xsdt->asl_compiler_id, "XEN");
455 xsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
457 xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt);
458 tables->madt_ptr = dom_pa((unsigned long) madt);
460 xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
462 /* setup FADT */
463 strncpy(fadt->signature, FADT_SIG, 4);
464 fadt->length = sizeof(struct fadt_descriptor_rev2);
465 fadt->revision = FADT2_REVISION_ID;
466 strcpy(fadt->oem_id, "XEN");
467 strcpy(fadt->oem_table_id, "Xen/ia64");
468 strcpy(fadt->asl_compiler_id, "XEN");
469 fadt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
471 strncpy(facs->signature, FACS_SIG, 4);
472 facs->version = 1;
473 facs->length = sizeof(struct facs_descriptor_rev2);
475 fadt->xfirmware_ctrl = dom_pa((unsigned long) facs);
476 fadt->Xdsdt = dom_pa((unsigned long) dsdt);
478 /*
479 * All of the below FADT entries are filled it to prevent warnings
480 * from sanity checks in the ACPI CA. Emulate required ACPI hardware
481 * registers in system memory.
482 */
483 fadt->pm1_evt_len = 4;
484 fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
485 fadt->xpm1a_evt_blk.register_bit_width = 8;
486 fadt->xpm1a_evt_blk.address = dom_pa((unsigned long) &tables->pm1a_evt_blk);
487 fadt->pm1_cnt_len = 1;
488 fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
489 fadt->xpm1a_cnt_blk.register_bit_width = 8;
490 fadt->xpm1a_cnt_blk.address = dom_pa((unsigned long) &tables->pm1a_cnt_blk);
491 fadt->pm_tm_len = 4;
492 fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
493 fadt->xpm_tmr_blk.register_bit_width = 8;
494 fadt->xpm_tmr_blk.address = dom_pa((unsigned long) &tables->pm_tmr_blk);
496 fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
498 /* setup RSDP */
499 strncpy(rsdp->signature, RSDP_SIG, 8);
500 strcpy(rsdp->oem_id, "XEN");
501 rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
502 rsdp->length = sizeof(struct acpi20_table_rsdp);
503 rsdp->xsdt_address = dom_pa((unsigned long) xsdt);
505 rsdp->checksum = generate_acpi_checksum(rsdp,
506 ACPI_RSDP_CHECKSUM_LENGTH);
507 rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
509 /* setup DSDT with trivial namespace. */
510 strncpy(dsdt->signature, DSDT_SIG, 4);
511 dsdt->revision = 1;
512 dsdt->length = sizeof(struct acpi_table_header) + sizeof(tables->aml);
513 strcpy(dsdt->oem_id, "XEN");
514 strcpy(dsdt->oem_table_id, "Xen/ia64");
515 strcpy(dsdt->asl_compiler_id, "XEN");
516 dsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
518 /* Trivial namespace, avoids ACPI CA complaints */
519 tables->aml[0] = 0x10; /* Scope */
520 tables->aml[1] = 0x12; /* length/offset to next object */
521 strncpy((char *)&tables->aml[2], "_SB_", 4);
523 /* The processor object isn't absolutely necessary, revist for SMP */
524 tables->aml[6] = 0x5b; /* processor object */
525 tables->aml[7] = 0x83;
526 tables->aml[8] = 0x0b; /* next */
527 strncpy((char *)&tables->aml[9], "CPU0", 4);
529 dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
531 /* setup MADT */
532 strncpy(madt->header.signature, APIC_SIG, 4);
533 madt->header.revision = 2;
534 madt->header.length = sizeof(struct acpi_table_madt) +
535 MAX_VIRT_CPUS * sizeof(struct acpi_table_lsapic);
536 strcpy(madt->header.oem_id, "XEN");
537 strcpy(madt->header.oem_table_id, "Xen/ia64");
538 strcpy(madt->header.asl_compiler_id, "XEN");
539 madt->header.asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
541 /* An LSAPIC entry describes a CPU. */
542 for (i = 0; i < MAX_VIRT_CPUS; i++) {
543 lsapic[i].header.type = ACPI_MADT_LSAPIC;
544 lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
545 lsapic[i].id = i;
546 lsapic[i].eid = 0;
547 lsapic[i].flags.enabled = (d->vcpu[i] != NULL);
548 }
550 madt->header.checksum = generate_acpi_checksum(madt,
551 madt->header.length);
552 return;
553 }
555 static struct ia64_boot_param *
556 dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size)
557 {
558 efi_system_table_t *efi_systab;
559 efi_runtime_services_t *efi_runtime;
560 efi_config_table_t *efi_tables;
561 struct ia64_sal_systab *sal_systab;
562 efi_memory_desc_t *efi_memmap, *md;
563 struct ia64_sal_desc_entry_point *sal_ed;
564 struct ia64_boot_param *bp;
565 unsigned long *pfn;
566 unsigned char checksum = 0;
567 char *cp, *cmd_line, *fw_vendor;
568 int i = 0;
569 unsigned long maxmem = (d->max_pages - d->arch.sys_pgnr) * PAGE_SIZE;
570 const unsigned long start_mpaddr = ((d==dom0)?dom0_start:0);
572 # define MAKE_MD(typ, attr, start, end, abs) \
573 do { \
574 md = efi_memmap + i++; \
575 md->type = typ; \
576 md->pad = 0; \
577 md->phys_addr = abs ? start : start_mpaddr + start; \
578 md->virt_addr = 0; \
579 md->num_pages = (end - start) >> 12; \
580 md->attribute = attr; \
581 print_md(md); \
582 } while (0)
584 /* FIXME: should check size but for now we have a whole MB to play with.
585 And if stealing code from fw-emu.c, watch out for new fw_vendor on the end!
586 if (fw_mem_size < sizeof(fw_mem_proto)) {
587 printf("sys_fw_init: insufficient space for fw_mem\n");
588 return 0;
589 }
590 */
591 memset(fw_mem, 0, fw_mem_size);
593 cp = fw_mem;
594 efi_systab = (void *) cp; cp += sizeof(*efi_systab);
595 efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
596 efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
597 sal_systab = (void *) cp; cp += sizeof(*sal_systab);
598 sal_ed = (void *) cp; cp += sizeof(*sal_ed);
599 efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
600 bp = (void *) cp; cp += sizeof(*bp);
601 pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
602 cmd_line = (void *) cp;
604 if (args) {
605 if (arglen >= 1024)
606 arglen = 1023;
607 memcpy(cmd_line, args, arglen);
608 } else {
609 arglen = 0;
610 }
611 cmd_line[arglen] = '\0';
613 memset(efi_systab, 0, sizeof(efi_systab));
614 efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
615 efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
616 efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
617 cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary
618 #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"
619 cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary
621 memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
622 efi_systab->fw_vendor = dom_pa((unsigned long) fw_vendor);
624 efi_systab->fw_revision = 1;
625 efi_systab->runtime = (void *) dom_pa((unsigned long) efi_runtime);
626 efi_systab->nr_tables = NUM_EFI_SYS_TABLES;
627 efi_systab->tables = dom_pa((unsigned long) efi_tables);
629 efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
630 efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
631 efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
632 #define EFI_HYPERCALL_PATCH(tgt,call) do { \
633 dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \
634 tgt = dom_pa((unsigned long) pfn); \
635 *pfn++ = FW_HYPERCALL_##call##_PADDR + start_mpaddr; \
636 *pfn++ = 0; \
637 } while (0)
639 EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME);
640 EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME);
641 EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
642 EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
643 EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
644 EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE);
645 EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
646 EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE);
647 EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
648 EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM);
650 efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
651 efi_tables[0].table = dom_pa((unsigned long) sal_systab);
652 for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
653 efi_tables[i].guid = NULL_GUID;
654 efi_tables[i].table = 0;
655 }
656 if (d == dom0) {
657 printf("Domain0 EFI passthrough:");
658 i = 1;
659 if (efi.mps) {
660 efi_tables[i].guid = MPS_TABLE_GUID;
661 efi_tables[i].table = __pa(efi.mps);
662 printf(" MPS=0x%lx",efi_tables[i].table);
663 i++;
664 }
666 touch_acpi_table();
668 if (efi.acpi20) {
669 efi_tables[i].guid = ACPI_20_TABLE_GUID;
670 efi_tables[i].table = __pa(efi.acpi20);
671 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
672 i++;
673 }
674 if (efi.acpi) {
675 efi_tables[i].guid = ACPI_TABLE_GUID;
676 efi_tables[i].table = __pa(efi.acpi);
677 printf(" ACPI=0x%lx",efi_tables[i].table);
678 i++;
679 }
680 if (efi.smbios) {
681 efi_tables[i].guid = SMBIOS_TABLE_GUID;
682 efi_tables[i].table = __pa(efi.smbios);
683 printf(" SMBIOS=0x%lx",efi_tables[i].table);
684 i++;
685 }
686 if (efi.hcdp) {
687 efi_tables[i].guid = HCDP_TABLE_GUID;
688 efi_tables[i].table = __pa(efi.hcdp);
689 printf(" HCDP=0x%lx",efi_tables[i].table);
690 i++;
691 }
692 printf("\n");
693 } else {
694 i = 1;
696 if ((unsigned long)fw_mem + fw_mem_size - (unsigned long)cp >=
697 sizeof(struct fake_acpi_tables)) {
698 struct fake_acpi_tables *acpi_tables;
700 acpi_tables = (void *)cp;
701 cp += sizeof(struct fake_acpi_tables);
702 dom_fw_fake_acpi(d, acpi_tables);
704 efi_tables[i].guid = ACPI_20_TABLE_GUID;
705 efi_tables[i].table = dom_pa((unsigned long) acpi_tables);
706 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
707 i++;
708 }
709 }
711 /* fill in the SAL system table: */
712 memcpy(sal_systab->signature, "SST_", 4);
713 sal_systab->size = sizeof(*sal_systab);
714 sal_systab->sal_rev_minor = 1;
715 sal_systab->sal_rev_major = 0;
716 sal_systab->entry_count = 1;
718 strcpy((char *)sal_systab->oem_id, "Xen/ia64");
719 strcpy((char *)sal_systab->product_id, "Xen/ia64");
721 /* fill in an entry point: */
722 sal_ed->type = SAL_DESC_ENTRY_POINT;
723 sal_ed->pal_proc = FW_HYPERCALL_PAL_CALL_PADDR + start_mpaddr;
724 dom_fw_pal_hypercall_patch (d, sal_ed->pal_proc);
725 sal_ed->sal_proc = FW_HYPERCALL_SAL_CALL_PADDR + start_mpaddr;
726 dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
727 sal_ed->gp = 0; // will be ignored
729 for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
730 checksum += *cp;
732 sal_systab->checksum = -checksum;
734 i = 0;
735 if (d == dom0) {
736 /*
737 * This is a bad hack. Dom0 may share other domains' memory
738 * through a dom0 physical address. Unfortunately, this
739 * address may be used in maddr_to_page (e.g. in the loopback
740 * driver) but when Linux initializes memory it only creates
741 * page structs for the physical memory it knows about. And
742 * on ia64, only for full writeback granules. So, we reserve
743 * the last full granule of Xen's memory for dom0 (in
744 * start_kernel) to ensure dom0 creates a large enough memmap
745 */
746 unsigned long last_start = max_page << PAGE_SHIFT;
747 unsigned long last_end = last_start + IA64_GRANULE_SIZE;
749 /* simulate 1MB free memory at physical address zero */
750 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0);
751 /* hypercall patches live here, masquerade as reserved PAL memory */
752 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0);
753 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem-IA64_GRANULE_SIZE, 0);
754 /* hack */ MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,last_start,last_end,1);
756 /* pass through the I/O port space */
757 if (!running_on_sim) {
758 efi_memory_desc_t *efi_get_io_md(void);
759 efi_memory_desc_t *ia64_efi_io_md;
760 u32 type;
761 u64 iostart, ioend, ioattr;
763 ia64_efi_io_md = efi_get_io_md();
764 type = ia64_efi_io_md->type;
765 iostart = ia64_efi_io_md->phys_addr;
766 ioend = ia64_efi_io_md->phys_addr +
767 (ia64_efi_io_md->num_pages << 12);
768 ioattr = ia64_efi_io_md->attribute;
769 MAKE_MD(type,ioattr,iostart,ioend, 1);
770 }
771 else MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
772 }
773 else {
774 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 1);
775 /* hypercall patches live here, masquerade as reserved PAL memory */
776 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 1);
777 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 1);
778 /* Create a dummy entry for IO ports, so that IO accesses are
779 trapped by Xen. */
780 MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE,EFI_MEMORY_UC,
781 0x00000ffffc000000, 0x00000fffffffffff, 1);
782 MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
783 }
785 bp->efi_systab = dom_pa((unsigned long) fw_mem);
786 bp->efi_memmap = dom_pa((unsigned long) efi_memmap);
787 bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t);
788 bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
789 bp->efi_memdesc_version = 1;
790 bp->command_line = dom_pa((unsigned long) cmd_line);
791 bp->console_info.num_cols = 80;
792 bp->console_info.num_rows = 25;
793 bp->console_info.orig_x = 0;
794 bp->console_info.orig_y = 24;
795 bp->fpswa = 0;
796 if (d == dom0) {
797 bp->initrd_start = (dom0_start+dom0_size) -
798 (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024);
799 bp->initrd_size = ia64_boot_param->initrd_size;
800 }
801 else {
802 bp->initrd_start = d->arch.initrd_start;
803 bp->initrd_size = d->arch.initrd_len;
804 }
805 printf(" initrd start 0x%lx", bp->initrd_start);
806 printf(" initrd size 0x%lx\n", bp->initrd_size);
807 return bp;
808 }