ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 9684:918ce6a565b7

[IA64] VM_SUMMARY and VM_INFO

xen_pal_emulator: implements VM_SUMMARY and VM_INFO.

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