ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 9484:ddc279c91502

[IA64] Dummy emulation of SAL INFO sal calls.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Fri Mar 31 14:04:16 2006 -0700 (2006-03-31)
parents f517be67eeac
children 3b3a5588baca
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 /* No more info. */
161 status = -5;
162 r9 = 0;
163 break;
164 case SAL_GET_STATE_INFO_SIZE:
165 /* Return a dummy size. */
166 status = 0;
167 r9 = 128;
168 break;
169 case SAL_CLEAR_STATE_INFO:
170 /* Noop. */
171 break;
172 case SAL_MC_RENDEZ:
173 printf("*** CALLED SAL_MC_RENDEZ. IGNORED...\n");
174 break;
175 case SAL_MC_SET_PARAMS:
176 printf("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n");
177 break;
178 case SAL_CACHE_FLUSH:
179 printf("*** CALLED SAL_CACHE_FLUSH. IGNORED...\n");
180 break;
181 case SAL_CACHE_INIT:
182 printf("*** CALLED SAL_CACHE_INIT. IGNORED...\n");
183 break;
184 case SAL_UPDATE_PAL:
185 printf("*** CALLED SAL_UPDATE_PAL. IGNORED...\n");
186 break;
187 default:
188 printf("*** CALLED SAL_ WITH UNKNOWN INDEX. IGNORED...\n");
189 status = -1;
190 break;
191 }
192 return ((struct sal_ret_values) {status, r9, r10, r11});
193 }
195 struct ia64_pal_retval
196 xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3)
197 {
198 unsigned long r9 = 0;
199 unsigned long r10 = 0;
200 unsigned long r11 = 0;
201 long status = -1;
203 if (running_on_sim)
204 return pal_emulator_static(index);
206 // pal code must be mapped by a TR when pal is called, however
207 // calls are rare enough that we will map it lazily rather than
208 // at every context switch
209 //efi_map_pal_code();
210 switch (index) {
211 case PAL_MEM_ATTRIB:
212 status = ia64_pal_mem_attrib(&r9);
213 break;
214 case PAL_FREQ_BASE:
215 status = ia64_pal_freq_base(&r9);
216 break;
217 case PAL_PROC_GET_FEATURES:
218 status = ia64_pal_proc_get_features(&r9,&r10,&r11);
219 break;
220 case PAL_BUS_GET_FEATURES:
221 status = ia64_pal_bus_get_features(
222 (pal_bus_features_u_t *) &r9,
223 (pal_bus_features_u_t *) &r10,
224 (pal_bus_features_u_t *) &r11);
225 break;
226 case PAL_FREQ_RATIOS:
227 status = ia64_pal_freq_ratios(
228 (struct pal_freq_ratio *) &r9,
229 (struct pal_freq_ratio *) &r10,
230 (struct pal_freq_ratio *) &r11);
231 break;
232 case PAL_PTCE_INFO:
233 {
234 // return hard-coded xen-specific values because ptc.e
235 // is emulated on xen to always flush everything
236 // these values result in only one ptc.e instruction
237 status = 0; r9 = 0; r10 = (1L << 32) | 1L; r11 = 0;
238 }
239 break;
240 case PAL_VERSION:
241 status = ia64_pal_version(
242 (pal_version_u_t *) &r9,
243 (pal_version_u_t *) &r10);
244 break;
245 case PAL_VM_PAGE_SIZE:
246 status = ia64_pal_vm_page_size(&r9,&r10);
247 break;
248 case PAL_DEBUG_INFO:
249 status = ia64_pal_debug_info(&r9,&r10);
250 break;
251 case PAL_CACHE_SUMMARY:
252 status = ia64_pal_cache_summary(&r9,&r10);
253 break;
254 case PAL_VM_SUMMARY:
255 // FIXME: what should xen return for these, figure out later
256 // For now, linux does the right thing if pal call fails
257 // In particular, rid_size must be set properly!
258 //status = ia64_pal_vm_summary(
259 // (pal_vm_info_1_u_t *) &r9,
260 // (pal_vm_info_2_u_t *) &r10);
261 break;
262 case PAL_RSE_INFO:
263 status = ia64_pal_rse_info(
264 &r9,
265 (pal_hints_u_t *) &r10);
266 break;
267 case PAL_VM_INFO:
268 status = ia64_pal_vm_info(
269 in1,
270 in2,
271 (pal_tc_info_u_t *) &r9,
272 &r10);
273 break;
274 case PAL_REGISTER_INFO:
275 status = ia64_pal_register_info(in1, &r9, &r10);
276 break;
277 case PAL_CACHE_FLUSH:
278 /* FIXME */
279 printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n");
280 BUG();
281 break;
282 case PAL_PERF_MON_INFO:
283 {
284 unsigned long pm_buffer[16];
285 status = ia64_pal_perf_mon_info(
286 pm_buffer,
287 (pal_perf_mon_info_u_t *) &r9);
288 if (status != 0) {
289 while(1)
290 printk("PAL_PERF_MON_INFO fails ret=%ld\n", status);
291 break;
292 }
293 if (copy_to_user((void __user *)in1,pm_buffer,128)) {
294 while(1)
295 printk("xen_pal_emulator: PAL_PERF_MON_INFO "
296 "can't copy to user!!!!\n");
297 status = -1;
298 break;
299 }
300 }
301 break;
302 case PAL_CACHE_INFO:
303 {
304 pal_cache_config_info_t ci;
305 status = ia64_pal_cache_config_info(in1,in2,&ci);
306 if (status != 0) break;
307 r9 = ci.pcci_info_1.pcci1_data;
308 r10 = ci.pcci_info_2.pcci2_data;
309 }
310 break;
311 case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */
312 printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n");
313 break;
314 case PAL_HALT_INFO:
315 {
316 /* 1000 cycles to enter/leave low power state,
317 consumes 10 mW, implemented and cache/TLB coherent. */
318 unsigned long res = 1000UL | (1000UL << 16) | (10UL << 32)
319 | (1UL << 61) | (1UL << 60);
320 if (copy_to_user ((void *)in1, &res, sizeof (res)))
321 status = PAL_STATUS_EINVAL;
322 else
323 status = PAL_STATUS_SUCCESS;
324 }
325 break;
326 case PAL_HALT:
327 if (current->domain == dom0) {
328 printf ("Domain0 halts the machine\n");
329 (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL);
330 }
331 else
332 domain_shutdown (current->domain,
333 SHUTDOWN_poweroff);
334 break;
335 default:
336 printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n",
337 index);
338 break;
339 }
340 return ((struct ia64_pal_retval) {status, r9, r10, r11});
341 }
344 #define NFUNCPTRS 20
346 static void print_md(efi_memory_desc_t *md)
347 {
348 #if 1
349 printk("domain mem: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
350 md->type, md->attribute, md->phys_addr,
351 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
352 md->num_pages >> (20 - EFI_PAGE_SHIFT));
353 #endif
354 }
357 static u32 lsapic_nbr;
359 /* Modify lsapic table. Provides LPs. */
360 static int
361 acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
362 {
363 struct acpi_table_lsapic *lsapic;
364 int enable;
366 lsapic = (struct acpi_table_lsapic *) header;
367 if (!lsapic)
368 return -EINVAL;
370 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
371 enable = 1;
372 else
373 enable = 0;
374 if (lsapic->flags.enabled && enable) {
375 printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
376 lsapic_nbr++;
377 } else if (lsapic->flags.enabled) {
378 printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
379 lsapic->flags.enabled = 0;
380 }
381 return 0;
382 }
384 static u8
385 generate_acpi_checksum(void *tbl, unsigned long len)
386 {
387 u8 *ptr, sum = 0;
389 for (ptr = tbl; len > 0 ; len--, ptr++)
390 sum += *ptr;
392 return 0 - sum;
393 }
395 static int
396 acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
397 {
398 struct acpi_table_madt* acpi_madt;
400 if (!phys_addr || !size)
401 return -EINVAL;
403 acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
404 acpi_madt->header.checksum = 0;
405 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
407 return 0;
408 }
410 /* base is physical address of acpi table */
411 static void touch_acpi_table(void)
412 {
413 lsapic_nbr = 0;
414 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
415 printk("Error parsing MADT - no LAPIC entires\n");
416 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
418 return;
419 }
421 struct fake_acpi_tables {
422 struct acpi20_table_rsdp rsdp;
423 struct xsdt_descriptor_rev2 xsdt;
424 u64 madt_ptr;
425 struct fadt_descriptor_rev2 fadt;
426 struct facs_descriptor_rev2 facs;
427 struct acpi_table_header dsdt;
428 u8 aml[16];
429 struct acpi_table_madt madt;
430 struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
431 u8 pm1a_evt_blk[4];
432 u8 pm1a_cnt_blk[1];
433 u8 pm_tmr_blk[4];
434 };
436 /* Create enough of an ACPI structure to make the guest OS ACPI happy. */
437 static void
438 dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
439 {
440 struct acpi20_table_rsdp *rsdp = &tables->rsdp;
441 struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
442 struct fadt_descriptor_rev2 *fadt = &tables->fadt;
443 struct facs_descriptor_rev2 *facs = &tables->facs;
444 struct acpi_table_header *dsdt = &tables->dsdt;
445 struct acpi_table_madt *madt = &tables->madt;
446 struct acpi_table_lsapic *lsapic = tables->lsapic;
447 int i;
449 memset(tables, 0, sizeof(struct fake_acpi_tables));
451 /* setup XSDT (64bit version of RSDT) */
452 strncpy(xsdt->signature, XSDT_SIG, 4);
453 /* XSDT points to both the FADT and the MADT, so add one entry */
454 xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
455 xsdt->revision = 1;
456 strcpy(xsdt->oem_id, "XEN");
457 strcpy(xsdt->oem_table_id, "Xen/ia64");
458 strcpy(xsdt->asl_compiler_id, "XEN");
459 xsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
461 xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt);
462 tables->madt_ptr = dom_pa((unsigned long) madt);
464 xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
466 /* setup FADT */
467 strncpy(fadt->signature, FADT_SIG, 4);
468 fadt->length = sizeof(struct fadt_descriptor_rev2);
469 fadt->revision = FADT2_REVISION_ID;
470 strcpy(fadt->oem_id, "XEN");
471 strcpy(fadt->oem_table_id, "Xen/ia64");
472 strcpy(fadt->asl_compiler_id, "XEN");
473 fadt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
475 strncpy(facs->signature, FACS_SIG, 4);
476 facs->version = 1;
477 facs->length = sizeof(struct facs_descriptor_rev2);
479 fadt->xfirmware_ctrl = dom_pa((unsigned long) facs);
480 fadt->Xdsdt = dom_pa((unsigned long) dsdt);
482 /*
483 * All of the below FADT entries are filled it to prevent warnings
484 * from sanity checks in the ACPI CA. Emulate required ACPI hardware
485 * registers in system memory.
486 */
487 fadt->pm1_evt_len = 4;
488 fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
489 fadt->xpm1a_evt_blk.register_bit_width = 8;
490 fadt->xpm1a_evt_blk.address = dom_pa((unsigned long) &tables->pm1a_evt_blk);
491 fadt->pm1_cnt_len = 1;
492 fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
493 fadt->xpm1a_cnt_blk.register_bit_width = 8;
494 fadt->xpm1a_cnt_blk.address = dom_pa((unsigned long) &tables->pm1a_cnt_blk);
495 fadt->pm_tm_len = 4;
496 fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
497 fadt->xpm_tmr_blk.register_bit_width = 8;
498 fadt->xpm_tmr_blk.address = dom_pa((unsigned long) &tables->pm_tmr_blk);
500 fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
502 /* setup RSDP */
503 strncpy(rsdp->signature, RSDP_SIG, 8);
504 strcpy(rsdp->oem_id, "XEN");
505 rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
506 rsdp->length = sizeof(struct acpi20_table_rsdp);
507 rsdp->xsdt_address = dom_pa((unsigned long) xsdt);
509 rsdp->checksum = generate_acpi_checksum(rsdp,
510 ACPI_RSDP_CHECKSUM_LENGTH);
511 rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
513 /* setup DSDT with trivial namespace. */
514 strncpy(dsdt->signature, DSDT_SIG, 4);
515 dsdt->revision = 1;
516 dsdt->length = sizeof(struct acpi_table_header) + sizeof(tables->aml);
517 strcpy(dsdt->oem_id, "XEN");
518 strcpy(dsdt->oem_table_id, "Xen/ia64");
519 strcpy(dsdt->asl_compiler_id, "XEN");
520 dsdt->asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
522 /* Trivial namespace, avoids ACPI CA complaints */
523 tables->aml[0] = 0x10; /* Scope */
524 tables->aml[1] = 0x12; /* length/offset to next object */
525 strncpy((char *)&tables->aml[2], "_SB_", 4);
527 /* The processor object isn't absolutely necessary, revist for SMP */
528 tables->aml[6] = 0x5b; /* processor object */
529 tables->aml[7] = 0x83;
530 tables->aml[8] = 0x0b; /* next */
531 strncpy((char *)&tables->aml[9], "CPU0", 4);
533 dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
535 /* setup MADT */
536 strncpy(madt->header.signature, APIC_SIG, 4);
537 madt->header.revision = 2;
538 madt->header.length = sizeof(struct acpi_table_madt) +
539 MAX_VIRT_CPUS * sizeof(struct acpi_table_lsapic);
540 strcpy(madt->header.oem_id, "XEN");
541 strcpy(madt->header.oem_table_id, "Xen/ia64");
542 strcpy(madt->header.asl_compiler_id, "XEN");
543 madt->header.asl_compiler_revision = (XEN_VERSION<<16)|(XEN_SUBVERSION);
545 /* An LSAPIC entry describes a CPU. */
546 for (i = 0; i < MAX_VIRT_CPUS; i++) {
547 lsapic[i].header.type = ACPI_MADT_LSAPIC;
548 lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
549 lsapic[i].id = i;
550 lsapic[i].eid = 0;
551 lsapic[i].flags.enabled = (d->vcpu[i] != NULL);
552 }
554 madt->header.checksum = generate_acpi_checksum(madt,
555 madt->header.length);
556 return;
557 }
559 static struct ia64_boot_param *
560 dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size)
561 {
562 efi_system_table_t *efi_systab;
563 efi_runtime_services_t *efi_runtime;
564 efi_config_table_t *efi_tables;
565 struct ia64_sal_systab *sal_systab;
566 efi_memory_desc_t *efi_memmap, *md;
567 struct ia64_sal_desc_entry_point *sal_ed;
568 struct ia64_boot_param *bp;
569 unsigned long *pfn;
570 unsigned char checksum = 0;
571 char *cp, *cmd_line, *fw_vendor;
572 int i = 0;
573 unsigned long maxmem = (d->max_pages - d->arch.sys_pgnr) * PAGE_SIZE;
574 const unsigned long start_mpaddr = ((d==dom0)?dom0_start:0);
576 # define MAKE_MD(typ, attr, start, end, abs) \
577 do { \
578 md = efi_memmap + i++; \
579 md->type = typ; \
580 md->pad = 0; \
581 md->phys_addr = abs ? start : start_mpaddr + start; \
582 md->virt_addr = 0; \
583 md->num_pages = (end - start) >> 12; \
584 md->attribute = attr; \
585 print_md(md); \
586 } while (0)
588 /* FIXME: should check size but for now we have a whole MB to play with.
589 And if stealing code from fw-emu.c, watch out for new fw_vendor on the end!
590 if (fw_mem_size < sizeof(fw_mem_proto)) {
591 printf("sys_fw_init: insufficient space for fw_mem\n");
592 return 0;
593 }
594 */
595 memset(fw_mem, 0, fw_mem_size);
597 cp = fw_mem;
598 efi_systab = (void *) cp; cp += sizeof(*efi_systab);
599 efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
600 efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
601 sal_systab = (void *) cp; cp += sizeof(*sal_systab);
602 sal_ed = (void *) cp; cp += sizeof(*sal_ed);
603 efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
604 bp = (void *) cp; cp += sizeof(*bp);
605 pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
606 cmd_line = (void *) cp;
608 if (args) {
609 if (arglen >= 1024)
610 arglen = 1023;
611 memcpy(cmd_line, args, arglen);
612 } else {
613 arglen = 0;
614 }
615 cmd_line[arglen] = '\0';
617 memset(efi_systab, 0, sizeof(efi_systab));
618 efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
619 efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
620 efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
621 cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary
622 #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"
623 cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary
625 memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
626 efi_systab->fw_vendor = dom_pa((unsigned long) fw_vendor);
628 efi_systab->fw_revision = 1;
629 efi_systab->runtime = (void *) dom_pa((unsigned long) efi_runtime);
630 efi_systab->nr_tables = NUM_EFI_SYS_TABLES;
631 efi_systab->tables = dom_pa((unsigned long) efi_tables);
633 efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
634 efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
635 efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
636 #define EFI_HYPERCALL_PATCH(tgt,call) do { \
637 dom_efi_hypercall_patch(d,FW_HYPERCALL_##call##_PADDR,FW_HYPERCALL_##call); \
638 tgt = dom_pa((unsigned long) pfn); \
639 *pfn++ = FW_HYPERCALL_##call##_PADDR + start_mpaddr; \
640 *pfn++ = 0; \
641 } while (0)
643 EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME);
644 EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME);
645 EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
646 EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
647 EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
648 EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE);
649 EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
650 EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE);
651 EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
652 EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM);
654 efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
655 efi_tables[0].table = dom_pa((unsigned long) sal_systab);
656 for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
657 efi_tables[i].guid = NULL_GUID;
658 efi_tables[i].table = 0;
659 }
660 if (d == dom0) {
661 printf("Domain0 EFI passthrough:");
662 i = 1;
663 if (efi.mps) {
664 efi_tables[i].guid = MPS_TABLE_GUID;
665 efi_tables[i].table = __pa(efi.mps);
666 printf(" MPS=0x%lx",efi_tables[i].table);
667 i++;
668 }
670 touch_acpi_table();
672 if (efi.acpi20) {
673 efi_tables[i].guid = ACPI_20_TABLE_GUID;
674 efi_tables[i].table = __pa(efi.acpi20);
675 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
676 i++;
677 }
678 if (efi.acpi) {
679 efi_tables[i].guid = ACPI_TABLE_GUID;
680 efi_tables[i].table = __pa(efi.acpi);
681 printf(" ACPI=0x%lx",efi_tables[i].table);
682 i++;
683 }
684 if (efi.smbios) {
685 efi_tables[i].guid = SMBIOS_TABLE_GUID;
686 efi_tables[i].table = __pa(efi.smbios);
687 printf(" SMBIOS=0x%lx",efi_tables[i].table);
688 i++;
689 }
690 if (efi.hcdp) {
691 efi_tables[i].guid = HCDP_TABLE_GUID;
692 efi_tables[i].table = __pa(efi.hcdp);
693 printf(" HCDP=0x%lx",efi_tables[i].table);
694 i++;
695 }
696 printf("\n");
697 } else {
698 i = 1;
700 if ((unsigned long)fw_mem + fw_mem_size - (unsigned long)cp >=
701 sizeof(struct fake_acpi_tables)) {
702 struct fake_acpi_tables *acpi_tables;
704 acpi_tables = (void *)cp;
705 cp += sizeof(struct fake_acpi_tables);
706 dom_fw_fake_acpi(d, acpi_tables);
708 efi_tables[i].guid = ACPI_20_TABLE_GUID;
709 efi_tables[i].table = dom_pa((unsigned long) acpi_tables);
710 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
711 i++;
712 }
713 }
715 /* fill in the SAL system table: */
716 memcpy(sal_systab->signature, "SST_", 4);
717 sal_systab->size = sizeof(*sal_systab);
718 sal_systab->sal_rev_minor = 1;
719 sal_systab->sal_rev_major = 0;
720 sal_systab->entry_count = 1;
722 strcpy((char *)sal_systab->oem_id, "Xen/ia64");
723 strcpy((char *)sal_systab->product_id, "Xen/ia64");
725 /* fill in an entry point: */
726 sal_ed->type = SAL_DESC_ENTRY_POINT;
727 sal_ed->pal_proc = FW_HYPERCALL_PAL_CALL_PADDR + start_mpaddr;
728 dom_fw_pal_hypercall_patch (d, sal_ed->pal_proc);
729 sal_ed->sal_proc = FW_HYPERCALL_SAL_CALL_PADDR + start_mpaddr;
730 dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
731 sal_ed->gp = 0; // will be ignored
733 for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
734 checksum += *cp;
736 sal_systab->checksum = -checksum;
738 i = 0;
739 if (d == dom0) {
740 /*
741 * This is a bad hack. Dom0 may share other domains' memory
742 * through a dom0 physical address. Unfortunately, this
743 * address may be used in maddr_to_page (e.g. in the loopback
744 * driver) but when Linux initializes memory it only creates
745 * page structs for the physical memory it knows about. And
746 * on ia64, only for full writeback granules. So, we reserve
747 * the last full granule of Xen's memory for dom0 (in
748 * start_kernel) to ensure dom0 creates a large enough memmap
749 */
750 unsigned long last_start = max_page << PAGE_SHIFT;
751 unsigned long last_end = last_start + IA64_GRANULE_SIZE;
753 /* simulate 1MB free memory at physical address zero */
754 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 0);
755 /* hypercall patches live here, masquerade as reserved PAL memory */
756 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 0);
757 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem-IA64_GRANULE_SIZE, 0);
758 /* hack */ MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,last_start,last_end,1);
760 /* pass through the I/O port space */
761 if (!running_on_sim) {
762 efi_memory_desc_t *efi_get_io_md(void);
763 efi_memory_desc_t *ia64_efi_io_md;
764 u32 type;
765 u64 iostart, ioend, ioattr;
767 ia64_efi_io_md = efi_get_io_md();
768 type = ia64_efi_io_md->type;
769 iostart = ia64_efi_io_md->phys_addr;
770 ioend = ia64_efi_io_md->phys_addr +
771 (ia64_efi_io_md->num_pages << 12);
772 ioattr = ia64_efi_io_md->attribute;
773 MAKE_MD(type,ioattr,iostart,ioend, 1);
774 }
775 else MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
776 }
777 else {
778 MAKE_MD(EFI_LOADER_DATA,EFI_MEMORY_WB,0*MB,1*MB, 1);
779 /* hypercall patches live here, masquerade as reserved PAL memory */
780 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB,HYPERCALL_START,HYPERCALL_END, 1);
781 MAKE_MD(EFI_CONVENTIONAL_MEMORY,EFI_MEMORY_WB,HYPERCALL_END,maxmem, 1);
782 /* Create a dummy entry for IO ports, so that IO accesses are
783 trapped by Xen. */
784 MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE,EFI_MEMORY_UC,
785 0x00000ffffc000000, 0x00000fffffffffff, 1);
786 MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
787 }
789 bp->efi_systab = dom_pa((unsigned long) fw_mem);
790 bp->efi_memmap = dom_pa((unsigned long) efi_memmap);
791 bp->efi_memmap_size = NUM_MEM_DESCS*sizeof(efi_memory_desc_t);
792 bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
793 bp->efi_memdesc_version = 1;
794 bp->command_line = dom_pa((unsigned long) cmd_line);
795 bp->console_info.num_cols = 80;
796 bp->console_info.num_rows = 25;
797 bp->console_info.orig_x = 0;
798 bp->console_info.orig_y = 24;
799 bp->fpswa = 0;
800 if (d == dom0) {
801 bp->initrd_start = (dom0_start+dom0_size) -
802 (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024);
803 bp->initrd_size = ia64_boot_param->initrd_size;
804 }
805 else {
806 bp->initrd_start = d->arch.initrd_start;
807 bp->initrd_size = d->arch.initrd_len;
808 }
809 printf(" initrd start 0x%lx", bp->initrd_start);
810 printf(" initrd size 0x%lx\n", bp->initrd_size);
811 return bp;
812 }