ia64/xen-unstable

view xen/arch/ia64/xen/dom_fw.c @ 10936:3f3388f3e605

[IA64] Virtualize dom0 lid

Because dom0 can't write eid/id into iosapics, lid can be virtualized.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Tue Aug 08 14:40:57 2006 -0600 (2006-08-08)
parents 6c67ca1e1c1a
children d42e9a6f5378
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 * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp>
7 * VA Linux Systems Japan K.K.
8 * dom0 vp model support
9 */
11 #include <xen/config.h>
12 #include <asm/system.h>
13 #include <asm/pgalloc.h>
15 #include <linux/efi.h>
16 #include <linux/sort.h>
17 #include <asm/io.h>
18 #include <asm/pal.h>
19 #include <asm/sal.h>
20 #include <asm/meminit.h>
21 #include <asm/fpswa.h>
22 #include <xen/version.h>
23 #include <xen/acpi.h>
25 #include <asm/dom_fw.h>
26 #include <asm/bundle.h>
28 static void dom_fw_init (struct domain *d, struct ia64_boot_param *bp, char *fw_mem, int fw_mem_size, unsigned long maxmem);
30 extern struct domain *dom0;
32 extern unsigned long running_on_sim;
34 /* Note: two domains cannot be created simulteanously! */
35 static unsigned long dom_fw_base_mpa = -1;
36 static unsigned long imva_fw_base = -1;
38 #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"
40 #define MAKE_MD(typ, attr, start, end, abs) \
41 do { \
42 md = efi_memmap + i++; \
43 md->type = typ; \
44 md->pad = 0; \
45 md->phys_addr = abs ? start : start_mpaddr + start; \
46 md->virt_addr = 0; \
47 md->num_pages = (end - start) >> EFI_PAGE_SHIFT; \
48 md->attribute = attr; \
49 } while (0)
51 #define EFI_HYPERCALL_PATCH(tgt, call) \
52 do { \
53 dom_efi_hypercall_patch(d, FW_HYPERCALL_##call##_PADDR, \
54 FW_HYPERCALL_##call); \
55 tgt = dom_pa((unsigned long) pfn); \
56 *pfn++ = FW_HYPERCALL_##call##_PADDR + start_mpaddr; \
57 *pfn++ = 0; \
58 } while (0)
60 // return domain (meta)physical address for a given imva
61 // this function is a call-back from dom_fw_init
62 static unsigned long
63 dom_pa(unsigned long imva)
64 {
65 if (dom_fw_base_mpa == -1 || imva_fw_base == -1) {
66 printf("dom_pa: uninitialized! (spinning...)\n");
67 while(1);
68 }
69 if (imva - imva_fw_base > PAGE_SIZE) {
70 printf("dom_pa: bad offset! imva=0x%lx, imva_fw_base=0x%lx (spinning...)\n",
71 imva, imva_fw_base);
72 while(1);
73 }
74 return dom_fw_base_mpa + (imva - imva_fw_base);
75 }
77 // allocate a page for fw
78 // build_physmap_table() which is called by new_thread()
79 // does for domU.
80 #define ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, mpaddr) \
81 do { \
82 if ((d) == dom0) { \
83 assign_new_domain0_page((d), (mpaddr)); \
84 } \
85 } while (0)
87 /**************************************************************************
88 Hypercall bundle creation
89 **************************************************************************/
91 static void build_hypercall_bundle(UINT64 *imva, UINT64 brkimm, UINT64 hypnum, UINT64 ret)
92 {
93 INST64_A5 slot0;
94 INST64_I19 slot1;
95 INST64_B4 slot2;
96 IA64_BUNDLE bundle;
98 // slot1: mov r2 = hypnum (low 20 bits)
99 slot0.inst = 0;
100 slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9;
101 slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7;
102 slot0.imm5c = hypnum >> 16; slot0.s = 0;
103 // slot1: break brkimm
104 slot1.inst = 0;
105 slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0;
106 slot1.imm20 = brkimm; slot1.i = brkimm >> 20;
107 // if ret slot2: br.ret.sptk.many rp
108 // else slot2: br.cond.sptk.many rp
109 slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0;
110 slot2.wh = 0; slot2.d = 0; slot2.major = 0x0;
111 if (ret) {
112 slot2.btype = 4; slot2.x6 = 0x21;
113 }
114 else {
115 slot2.btype = 0; slot2.x6 = 0x20;
116 }
118 bundle.i64[0] = 0; bundle.i64[1] = 0;
119 bundle.template = 0x11;
120 bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst;
121 bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18;
123 imva[0] = bundle.i64[0]; imva[1] = bundle.i64[1];
124 ia64_fc(imva);
125 ia64_fc(imva + 1);
126 }
128 static void build_pal_hypercall_bundles(UINT64 *imva, UINT64 brkimm, UINT64 hypnum)
129 {
130 extern unsigned long pal_call_stub[];
131 IA64_BUNDLE bundle;
132 INST64_A5 slot_a5;
133 INST64_M37 slot_m37;
135 /* The source of the hypercall stub is the pal_call_stub function
136 defined in xenasm.S. */
138 /* Copy the first bundle and patch the hypercall number. */
139 bundle.i64[0] = pal_call_stub[0];
140 bundle.i64[1] = pal_call_stub[1];
141 slot_a5.inst = bundle.slot0;
142 slot_a5.imm7b = hypnum;
143 slot_a5.imm9d = hypnum >> 7;
144 slot_a5.imm5c = hypnum >> 16;
145 bundle.slot0 = slot_a5.inst;
146 imva[0] = bundle.i64[0];
147 imva[1] = bundle.i64[1];
148 ia64_fc(imva);
149 ia64_fc(imva + 1);
151 /* Copy the second bundle and patch the hypercall vector. */
152 bundle.i64[0] = pal_call_stub[2];
153 bundle.i64[1] = pal_call_stub[3];
154 slot_m37.inst = bundle.slot0;
155 slot_m37.imm20a = brkimm;
156 slot_m37.i = brkimm >> 20;
157 bundle.slot0 = slot_m37.inst;
158 imva[2] = bundle.i64[0];
159 imva[3] = bundle.i64[1];
160 ia64_fc(imva + 2);
161 ia64_fc(imva + 3);
162 }
164 // builds a hypercall bundle at domain physical address
165 static void dom_fpswa_hypercall_patch(struct domain *d)
166 {
167 unsigned long *entry_imva, *patch_imva;
168 unsigned long entry_paddr = FW_HYPERCALL_FPSWA_ENTRY_PADDR;
169 unsigned long patch_paddr = FW_HYPERCALL_FPSWA_PATCH_PADDR;
171 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, entry_paddr);
172 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, patch_paddr);
173 entry_imva = domain_mpa_to_imva(d, entry_paddr);
174 patch_imva = domain_mpa_to_imva(d, patch_paddr);
176 *entry_imva++ = patch_paddr;
177 *entry_imva = 0;
178 build_hypercall_bundle(patch_imva, d->arch.breakimm, FW_HYPERCALL_FPSWA, 1);
179 }
181 // builds a hypercall bundle at domain physical address
182 static void dom_efi_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall)
183 {
184 unsigned long *imva;
186 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
187 imva = domain_mpa_to_imva(d, paddr);
188 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, 1);
189 }
191 // builds a hypercall bundle at domain physical address
192 static void dom_fw_hypercall_patch(struct domain *d, unsigned long paddr, unsigned long hypercall,unsigned long ret)
193 {
194 unsigned long *imva;
196 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
197 imva = domain_mpa_to_imva(d, paddr);
198 build_hypercall_bundle(imva, d->arch.breakimm, hypercall, ret);
199 }
201 static void dom_fw_pal_hypercall_patch(struct domain *d, unsigned long paddr)
202 {
203 unsigned long *imva;
205 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, paddr);
206 imva = domain_mpa_to_imva(d, paddr);
207 build_pal_hypercall_bundles(imva, d->arch.breakimm, FW_HYPERCALL_PAL_CALL);
208 }
211 void dom_fw_setup(struct domain *d, unsigned long bp_mpa, unsigned long maxmem)
212 {
213 struct ia64_boot_param *bp;
215 dom_fw_base_mpa = 0;
216 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, dom_fw_base_mpa);
217 imva_fw_base = (unsigned long) domain_mpa_to_imva(d, dom_fw_base_mpa);
218 ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, bp_mpa);
219 bp = domain_mpa_to_imva(d, bp_mpa);
220 dom_fw_init(d, bp, (char *) imva_fw_base, PAGE_SIZE, maxmem);
221 }
224 /* the following heavily leveraged from linux/arch/ia64/hp/sim/fw-emu.c */
226 #define NFUNCPTRS 20
228 static inline void
229 print_md(efi_memory_desc_t *md)
230 {
231 printk("domain mem: type=%2u, attr=0x%016lx, range=[0x%016lx-0x%016lx) (%luMB)\n",
232 md->type, md->attribute, md->phys_addr,
233 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
234 md->num_pages >> (20 - EFI_PAGE_SHIFT));
235 }
237 static u32 lsapic_nbr;
239 /* Modify lsapic table. Provides LPs. */
240 static int
241 acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
242 {
243 struct acpi_table_lsapic *lsapic;
244 int enable;
246 lsapic = (struct acpi_table_lsapic *) header;
247 if (!lsapic)
248 return -EINVAL;
250 if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
251 enable = 1;
252 else
253 enable = 0;
254 if (lsapic->flags.enabled && enable) {
255 printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
256 lsapic->id = lsapic_nbr;
257 lsapic->eid = 0;
258 lsapic_nbr++;
259 } else if (lsapic->flags.enabled) {
260 printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
261 lsapic->flags.enabled = 0;
262 lsapic->id = 0;
263 lsapic->eid = 0;
264 }
265 return 0;
266 }
268 static u8
269 generate_acpi_checksum(void *tbl, unsigned long len)
270 {
271 u8 *ptr, sum = 0;
273 for (ptr = tbl; len > 0 ; len--, ptr++)
274 sum += *ptr;
276 return 0 - sum;
277 }
279 static int
280 acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
281 {
282 struct acpi_table_madt* acpi_madt;
284 if (!phys_addr || !size)
285 return -EINVAL;
287 acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
288 acpi_madt->header.checksum = 0;
289 acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
291 return 0;
292 }
294 /* base is physical address of acpi table */
295 static void touch_acpi_table(void)
296 {
297 lsapic_nbr = 0;
298 if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
299 printk("Error parsing MADT - no LAPIC entires\n");
300 acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
302 return;
303 }
305 struct fake_acpi_tables {
306 struct acpi20_table_rsdp rsdp;
307 struct xsdt_descriptor_rev2 xsdt;
308 u64 madt_ptr;
309 struct fadt_descriptor_rev2 fadt;
310 struct facs_descriptor_rev2 facs;
311 struct acpi_table_header dsdt;
312 u8 aml[8 + 11 * MAX_VIRT_CPUS];
313 struct acpi_table_madt madt;
314 struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
315 u8 pm1a_evt_blk[4];
316 u8 pm1a_cnt_blk[1];
317 u8 pm_tmr_blk[4];
318 };
320 /* Create enough of an ACPI structure to make the guest OS ACPI happy. */
321 static void
322 dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
323 {
324 struct acpi20_table_rsdp *rsdp = &tables->rsdp;
325 struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
326 struct fadt_descriptor_rev2 *fadt = &tables->fadt;
327 struct facs_descriptor_rev2 *facs = &tables->facs;
328 struct acpi_table_header *dsdt = &tables->dsdt;
329 struct acpi_table_madt *madt = &tables->madt;
330 struct acpi_table_lsapic *lsapic = tables->lsapic;
331 int i;
332 int aml_len;
333 int nbr_cpus;
335 memset(tables, 0, sizeof(struct fake_acpi_tables));
337 /* setup XSDT (64bit version of RSDT) */
338 strncpy(xsdt->signature, XSDT_SIG, 4);
339 /* XSDT points to both the FADT and the MADT, so add one entry */
340 xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
341 xsdt->revision = 1;
342 strcpy(xsdt->oem_id, "XEN");
343 strcpy(xsdt->oem_table_id, "Xen/ia64");
344 strcpy(xsdt->asl_compiler_id, "XEN");
345 xsdt->asl_compiler_revision = (xen_major_version() << 16) |
346 xen_minor_version();
348 xsdt->table_offset_entry[0] = dom_pa((unsigned long) fadt);
349 tables->madt_ptr = dom_pa((unsigned long) madt);
351 xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
353 /* setup FADT */
354 strncpy(fadt->signature, FADT_SIG, 4);
355 fadt->length = sizeof(struct fadt_descriptor_rev2);
356 fadt->revision = FADT2_REVISION_ID;
357 strcpy(fadt->oem_id, "XEN");
358 strcpy(fadt->oem_table_id, "Xen/ia64");
359 strcpy(fadt->asl_compiler_id, "XEN");
360 fadt->asl_compiler_revision = (xen_major_version() << 16) |
361 xen_minor_version();
363 strncpy(facs->signature, FACS_SIG, 4);
364 facs->version = 1;
365 facs->length = sizeof(struct facs_descriptor_rev2);
367 fadt->xfirmware_ctrl = dom_pa((unsigned long) facs);
368 fadt->Xdsdt = dom_pa((unsigned long) dsdt);
370 /*
371 * All of the below FADT entries are filled it to prevent warnings
372 * from sanity checks in the ACPI CA. Emulate required ACPI hardware
373 * registers in system memory.
374 */
375 fadt->pm1_evt_len = 4;
376 fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
377 fadt->xpm1a_evt_blk.register_bit_width = 8;
378 fadt->xpm1a_evt_blk.address = dom_pa((unsigned long) &tables->pm1a_evt_blk);
379 fadt->pm1_cnt_len = 1;
380 fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
381 fadt->xpm1a_cnt_blk.register_bit_width = 8;
382 fadt->xpm1a_cnt_blk.address = dom_pa((unsigned long) &tables->pm1a_cnt_blk);
383 fadt->pm_tm_len = 4;
384 fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
385 fadt->xpm_tmr_blk.register_bit_width = 8;
386 fadt->xpm_tmr_blk.address = dom_pa((unsigned long) &tables->pm_tmr_blk);
388 fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
390 /* setup RSDP */
391 strncpy(rsdp->signature, RSDP_SIG, 8);
392 strcpy(rsdp->oem_id, "XEN");
393 rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
394 rsdp->length = sizeof(struct acpi20_table_rsdp);
395 rsdp->xsdt_address = dom_pa((unsigned long) xsdt);
397 rsdp->checksum = generate_acpi_checksum(rsdp,
398 ACPI_RSDP_CHECKSUM_LENGTH);
399 rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
401 /* setup DSDT with trivial namespace. */
402 strncpy(dsdt->signature, DSDT_SIG, 4);
403 dsdt->revision = 1;
404 strcpy(dsdt->oem_id, "XEN");
405 strcpy(dsdt->oem_table_id, "Xen/ia64");
406 strcpy(dsdt->asl_compiler_id, "XEN");
407 dsdt->asl_compiler_revision = (xen_major_version() << 16) |
408 xen_minor_version();
410 /* Trivial namespace, avoids ACPI CA complaints */
411 tables->aml[0] = 0x10; /* Scope */
412 tables->aml[1] = 0x40; /* length/offset to next object (patched) */
413 tables->aml[2] = 0x00;
414 strncpy((char *)&tables->aml[3], "_SB_", 4);
416 /* The processor object isn't absolutely necessary, revist for SMP */
417 aml_len = 7;
418 for (i = 0; i < 3; i++) {
419 unsigned char *p = tables->aml + aml_len;
420 p[0] = 0x5b; /* processor object */
421 p[1] = 0x83;
422 p[2] = 0x0b; /* next */
423 p[3] = 'C';
424 p[4] = 'P';
425 snprintf ((char *)p + 5, 3, "%02x", i);
426 if (i < 16)
427 p[5] = 'U';
428 p[7] = i; /* acpi_id */
429 p[8] = 0; /* pblk_addr */
430 p[9] = 0;
431 p[10] = 0;
432 p[11] = 0;
433 p[12] = 0; /* pblk_len */
434 aml_len += 13;
435 }
436 tables->aml[1] = 0x40 + ((aml_len - 1) & 0x0f);
437 tables->aml[2] = (aml_len - 1) >> 4;
438 dsdt->length = sizeof(struct acpi_table_header) + aml_len;
439 dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
441 /* setup MADT */
442 strncpy(madt->header.signature, APIC_SIG, 4);
443 madt->header.revision = 2;
444 strcpy(madt->header.oem_id, "XEN");
445 strcpy(madt->header.oem_table_id, "Xen/ia64");
446 strcpy(madt->header.asl_compiler_id, "XEN");
447 madt->header.asl_compiler_revision = (xen_major_version() << 16) |
448 xen_minor_version();
450 /* An LSAPIC entry describes a CPU. */
451 nbr_cpus = 0;
452 for (i = 0; i < MAX_VIRT_CPUS; i++) {
453 lsapic[i].header.type = ACPI_MADT_LSAPIC;
454 lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
455 lsapic[i].acpi_id = i;
456 lsapic[i].id = i;
457 lsapic[i].eid = 0;
458 if (d->vcpu[i] != NULL) {
459 lsapic[i].flags.enabled = 1;
460 nbr_cpus++;
461 }
462 }
463 madt->header.length = sizeof(struct acpi_table_madt) +
464 nbr_cpus * sizeof(struct acpi_table_lsapic);
465 madt->header.checksum = generate_acpi_checksum(madt,
466 madt->header.length);
467 return;
468 }
470 #define NUM_EFI_SYS_TABLES 6
471 #define NUM_MEM_DESCS 64 //large enough
473 struct dom0_passthrough_arg {
474 struct domain* d;
475 int flags;
476 efi_memory_desc_t *md;
477 int* i;
478 };
480 static int
481 dom_fw_dom0_passthrough(efi_memory_desc_t *md, void *arg__)
482 {
483 struct dom0_passthrough_arg* arg = (struct dom0_passthrough_arg*)arg__;
484 unsigned long paddr;
485 struct domain* d = arg->d;
486 u64 start = md->phys_addr;
487 u64 size = md->num_pages << EFI_PAGE_SHIFT;
489 if (md->type == EFI_MEMORY_MAPPED_IO ||
490 md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
492 //XXX some machine has large mmio area whose size is about several TB.
493 // It requires impractical memory to map such a huge region
494 // to a domain.
495 // For now we don't map it, but later we must fix this.
496 if (md->type == EFI_MEMORY_MAPPED_IO && (size > 0x100000000UL))
497 return 0;
499 paddr = assign_domain_mmio_page(d, start, size);
500 } else
501 paddr = assign_domain_mach_page(d, start, size, arg->flags);
503 BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
504 md->type != EFI_RUNTIME_SERVICES_DATA &&
505 md->type != EFI_ACPI_RECLAIM_MEMORY &&
506 md->type != EFI_ACPI_MEMORY_NVS &&
507 md->type != EFI_RESERVED_TYPE &&
508 md->type != EFI_MEMORY_MAPPED_IO &&
509 md->type != EFI_MEMORY_MAPPED_IO_PORT_SPACE);
511 arg->md->type = md->type;
512 arg->md->pad = 0;
513 arg->md->phys_addr = paddr;
514 arg->md->virt_addr = 0;
515 arg->md->num_pages = md->num_pages;
516 arg->md->attribute = md->attribute;
518 (*arg->i)++;
519 arg->md++;
520 return 0;
521 }
523 /*
524 * Create dom0 MDT entries for conventional memory below 1MB. Without
525 * this Linux will assume VGA is present because 0xA0000 will always
526 * be either a hole in the MDT or an I/O region via the passthrough.
527 */
528 static int
529 dom_fw_dom0_lowmem(efi_memory_desc_t *md, void *arg__)
530 {
531 struct dom0_passthrough_arg* arg = (struct dom0_passthrough_arg*)arg__;
532 u64 end = min(HYPERCALL_START,
533 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT));
535 BUG_ON(md->type != EFI_CONVENTIONAL_MEMORY);
537 /* avoid hypercall area */
538 if (md->phys_addr >= HYPERCALL_START)
539 return 0;
541 /* avoid firmware base area */
542 if (md->phys_addr < dom_pa(imva_fw_base))
543 end = min(end, dom_pa(imva_fw_base));
544 else if (md->phys_addr < dom_pa(imva_fw_base + PAGE_SIZE)) {
545 if (end < dom_pa(imva_fw_base + PAGE_SIZE))
546 return 0;
547 md->phys_addr = dom_pa(imva_fw_base + PAGE_SIZE);
548 }
550 arg->md->type = md->type;
551 arg->md->pad = 0;
552 arg->md->phys_addr = md->phys_addr;
553 arg->md->virt_addr = 0;
554 arg->md->num_pages = (end - md->phys_addr) >> EFI_PAGE_SHIFT;
555 arg->md->attribute = md->attribute;
557 (*arg->i)++;
558 arg->md++;
560 /* if firmware area spliced the md, add the upper part here */
561 if (end == dom_pa(imva_fw_base)) {
562 end = min(HYPERCALL_START,
563 md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT));
564 if (end > dom_pa(imva_fw_base + PAGE_SIZE)) {
565 arg->md->type = md->type;
566 arg->md->pad = 0;
567 arg->md->phys_addr = dom_pa(imva_fw_base + PAGE_SIZE);
568 arg->md->virt_addr = 0;
569 arg->md->num_pages = (end - arg->md->phys_addr) >> EFI_PAGE_SHIFT;
570 arg->md->attribute = md->attribute;
572 (*arg->i)++;
573 arg->md++;
574 }
575 }
576 return 0;
577 }
579 static int
580 efi_mdt_cmp(const void *a, const void *b)
581 {
582 const efi_memory_desc_t *x = a, *y = b;
584 if (x->phys_addr > y->phys_addr)
585 return 1;
586 if (x->phys_addr < y->phys_addr)
587 return -1;
589 // num_pages == 0 is allowed.
590 if (x->num_pages > y->num_pages)
591 return 1;
592 if (x->num_pages < y->num_pages)
593 return -1;
595 return 0;
596 }
598 static void
599 dom_fw_init (struct domain *d, struct ia64_boot_param *bp, char *fw_mem, int fw_mem_size, unsigned long maxmem)
600 {
601 efi_system_table_t *efi_systab;
602 efi_runtime_services_t *efi_runtime;
603 efi_config_table_t *efi_tables;
604 struct ia64_sal_systab *sal_systab;
605 struct ia64_sal_desc_entry_point *sal_ed;
606 struct ia64_sal_desc_ap_wakeup *sal_wakeup;
607 fpswa_interface_t *fpswa_inf;
608 efi_memory_desc_t *efi_memmap, *md;
609 struct xen_sal_data *sal_data;
610 unsigned long *pfn;
611 unsigned char checksum = 0;
612 char *cp, *fw_vendor;
613 int num_mds, j, i = 0;
614 const unsigned long start_mpaddr = 0;
616 /* FIXME: should check size but for now we have a whole MB to play with.
617 And if stealing code from fw-emu.c, watch out for new fw_vendor on the end!
618 if (fw_mem_size < sizeof(fw_mem_proto)) {
619 printf("sys_fw_init: insufficient space for fw_mem\n");
620 return 0;
621 }
622 */
623 memset(fw_mem, 0, fw_mem_size);
625 cp = fw_mem;
626 efi_systab = (void *) cp; cp += sizeof(*efi_systab);
627 efi_runtime = (void *) cp; cp += sizeof(*efi_runtime);
628 efi_tables = (void *) cp; cp += NUM_EFI_SYS_TABLES * sizeof(*efi_tables);
629 sal_systab = (void *) cp; cp += sizeof(*sal_systab);
630 sal_ed = (void *) cp; cp += sizeof(*sal_ed);
631 sal_wakeup = (void *) cp; cp += sizeof(*sal_wakeup);
632 fpswa_inf = (void *) cp; cp += sizeof(*fpswa_inf);
633 efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap);
634 pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn);
635 sal_data = (void *) cp; cp += sizeof(*sal_data);
637 /* Initialise for EFI_SET_VIRTUAL_ADDRESS_MAP emulation */
638 d->arch.efi_runtime = efi_runtime;
639 d->arch.fpswa_inf = fpswa_inf;
640 d->arch.sal_data = sal_data;
642 memset(efi_systab, 0, sizeof(efi_systab));
643 efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
644 efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
645 efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
646 fw_vendor = cp;
647 cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary
649 memcpy(fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
650 efi_systab->fw_vendor = dom_pa((unsigned long) fw_vendor);
651 efi_systab->fw_revision = 1;
652 efi_systab->runtime = (void *) dom_pa((unsigned long) efi_runtime);
653 efi_systab->nr_tables = NUM_EFI_SYS_TABLES;
654 efi_systab->tables = dom_pa((unsigned long) efi_tables);
656 efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
657 efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
658 efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
660 EFI_HYPERCALL_PATCH(efi_runtime->get_time,EFI_GET_TIME);
661 EFI_HYPERCALL_PATCH(efi_runtime->set_time,EFI_SET_TIME);
662 EFI_HYPERCALL_PATCH(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);
663 EFI_HYPERCALL_PATCH(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);
664 EFI_HYPERCALL_PATCH(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);
665 EFI_HYPERCALL_PATCH(efi_runtime->get_variable,EFI_GET_VARIABLE);
666 EFI_HYPERCALL_PATCH(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);
667 EFI_HYPERCALL_PATCH(efi_runtime->set_variable,EFI_SET_VARIABLE);
668 EFI_HYPERCALL_PATCH(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);
669 EFI_HYPERCALL_PATCH(efi_runtime->reset_system,EFI_RESET_SYSTEM);
671 efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
672 efi_tables[0].table = dom_pa((unsigned long) sal_systab);
673 for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
674 efi_tables[i].guid = NULL_GUID;
675 efi_tables[i].table = 0;
676 }
677 if (d == dom0) {
678 printf("Domain0 EFI passthrough:");
679 i = 1;
680 if (efi.mps) {
681 efi_tables[i].guid = MPS_TABLE_GUID;
682 efi_tables[i].table = __pa(efi.mps);
683 printf(" MPS=0x%lx",efi_tables[i].table);
684 i++;
685 }
687 touch_acpi_table();
689 if (efi.acpi20) {
690 efi_tables[i].guid = ACPI_20_TABLE_GUID;
691 efi_tables[i].table = __pa(efi.acpi20);
692 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
693 i++;
694 }
695 if (efi.acpi) {
696 efi_tables[i].guid = ACPI_TABLE_GUID;
697 efi_tables[i].table = __pa(efi.acpi);
698 printf(" ACPI=0x%lx",efi_tables[i].table);
699 i++;
700 }
701 if (efi.smbios) {
702 efi_tables[i].guid = SMBIOS_TABLE_GUID;
703 efi_tables[i].table = __pa(efi.smbios);
704 printf(" SMBIOS=0x%lx",efi_tables[i].table);
705 i++;
706 }
707 if (efi.hcdp) {
708 efi_tables[i].guid = HCDP_TABLE_GUID;
709 efi_tables[i].table = __pa(efi.hcdp);
710 printf(" HCDP=0x%lx",efi_tables[i].table);
711 i++;
712 }
713 printf("\n");
714 } else {
715 printf("DomainU EFI build up:");
716 i = 1;
718 if ((unsigned long)fw_mem + fw_mem_size - (unsigned long)cp >=
719 sizeof(struct fake_acpi_tables)) {
720 struct fake_acpi_tables *acpi_tables;
722 acpi_tables = (void *)cp;
723 cp += sizeof(struct fake_acpi_tables);
724 dom_fw_fake_acpi(d, acpi_tables);
726 efi_tables[i].guid = ACPI_20_TABLE_GUID;
727 efi_tables[i].table = dom_pa((unsigned long) acpi_tables);
728 printf(" ACPI 2.0=0x%lx",efi_tables[i].table);
729 i++;
730 }
731 printf("\n");
732 }
734 /* fill in the SAL system table: */
735 memcpy(sal_systab->signature, "SST_", 4);
736 sal_systab->size = sizeof(*sal_systab);
737 sal_systab->sal_rev_minor = 1;
738 sal_systab->sal_rev_major = 0;
739 sal_systab->entry_count = 2;
741 strcpy((char *)sal_systab->oem_id, "Xen/ia64");
742 strcpy((char *)sal_systab->product_id, "Xen/ia64");
744 /* fill in an entry point: */
745 sal_ed->type = SAL_DESC_ENTRY_POINT;
746 sal_ed->pal_proc = FW_HYPERCALL_PAL_CALL_PADDR + start_mpaddr;
747 dom_fw_pal_hypercall_patch (d, sal_ed->pal_proc);
748 sal_ed->sal_proc = FW_HYPERCALL_SAL_CALL_PADDR + start_mpaddr;
749 dom_fw_hypercall_patch (d, sal_ed->sal_proc, FW_HYPERCALL_SAL_CALL, 1);
750 sal_ed->gp = 0; // will be ignored
752 /* Fill an AP wakeup descriptor. */
753 sal_wakeup->type = SAL_DESC_AP_WAKEUP;
754 sal_wakeup->mechanism = IA64_SAL_AP_EXTERNAL_INT;
755 sal_wakeup->vector = XEN_SAL_BOOT_RENDEZ_VEC;
757 /* Compute checksum. */
758 for (cp = (char *) sal_systab; cp < (char *) efi_memmap; ++cp)
759 checksum += *cp;
760 sal_systab->checksum = -checksum;
762 /* SAL return point. */
763 d->arch.sal_return_addr = FW_HYPERCALL_SAL_RETURN_PADDR + start_mpaddr;
764 dom_fw_hypercall_patch (d, d->arch.sal_return_addr,
765 FW_HYPERCALL_SAL_RETURN, 0);
767 /* Fill in the FPSWA interface: */
768 fpswa_inf->revision = fpswa_interface->revision;
769 dom_fpswa_hypercall_patch(d);
770 fpswa_inf->fpswa = (void *) FW_HYPERCALL_FPSWA_ENTRY_PADDR + start_mpaddr;
772 i = 0; /* Used by MAKE_MD */
774 /* Create dom0/domu md entry for fw_mem area */
775 MAKE_MD(EFI_ACPI_RECLAIM_MEMORY, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
776 dom_pa((unsigned long)fw_mem),
777 dom_pa((unsigned long)fw_mem + fw_mem_size), 1);
779 if (d == dom0) {
780 /* hypercall patches live here, masquerade as reserved PAL memory */
781 MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB|EFI_MEMORY_RUNTIME,HYPERCALL_START,HYPERCALL_END, 0);
783 /* pass through the I/O port space */
784 if (!running_on_sim) {
785 struct dom0_passthrough_arg arg;
786 arg.md = &efi_memmap[i];
787 arg.i = &i;
788 arg.d = d;
789 arg.flags = ASSIGN_writable;
790 //XXX Is this needed?
791 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_CODE,
792 dom_fw_dom0_passthrough, &arg);
793 // for ACPI table.
794 arg.flags = ASSIGN_readonly;
795 efi_memmap_walk_type(EFI_RUNTIME_SERVICES_DATA,
796 dom_fw_dom0_passthrough, &arg);
797 arg.flags = ASSIGN_writable;
798 efi_memmap_walk_type(EFI_ACPI_RECLAIM_MEMORY,
799 dom_fw_dom0_passthrough, &arg);
800 efi_memmap_walk_type(EFI_ACPI_MEMORY_NVS,
801 dom_fw_dom0_passthrough, &arg);
802 efi_memmap_walk_type(EFI_RESERVED_TYPE,
803 dom_fw_dom0_passthrough, &arg);
804 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO,
805 dom_fw_dom0_passthrough, &arg);
806 efi_memmap_walk_type(EFI_MEMORY_MAPPED_IO_PORT_SPACE,
807 dom_fw_dom0_passthrough, &arg);
808 efi_memmap_walk_type(EFI_CONVENTIONAL_MEMORY,
809 dom_fw_dom0_lowmem, &arg);
810 }
811 else MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
812 } else {
813 /* hypercall patches live here, masquerade as reserved
814 PAL memory */
815 MAKE_MD(EFI_PAL_CODE, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
816 HYPERCALL_START, HYPERCALL_END, 1);
817 /* Create an entry for IO ports. */
818 MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC,
819 IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE, 1);
820 MAKE_MD(EFI_RESERVED_TYPE,0,0,0,0);
821 }
823 // simple
824 // MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB,
825 // HYPERCALL_END, maxmem, 0);
826 // is not good. Check overlap.
827 sort(efi_memmap, i, sizeof(efi_memory_desc_t),
828 efi_mdt_cmp, NULL);
830 // find gap and fill it with conventional memory
831 num_mds = i;
832 for (j = 0; j < num_mds; j++) {
833 unsigned long end;
834 unsigned long next_start;
836 md = &efi_memmap[j];
837 end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
839 next_start = maxmem;
840 if (j + 1 < num_mds) {
841 efi_memory_desc_t* next_md = &efi_memmap[j + 1];
842 next_start = next_md->phys_addr;
843 BUG_ON(end > next_start);
844 if (end == next_md->phys_addr)
845 continue;
846 }
848 // clip the range and align to PAGE_SIZE
849 // Avoid "legacy" low memory addresses and the
850 // HYPERCALL patch area.
851 if (end < HYPERCALL_END)
852 end = HYPERCALL_END;
853 if (next_start > maxmem)
854 next_start = maxmem;
855 end = PAGE_ALIGN(end);
856 next_start = next_start & PAGE_MASK;
857 if (end >= next_start)
858 continue;
860 MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB,
861 end, next_start, 0);
862 if (next_start >= maxmem)
863 break;
864 }
865 sort(efi_memmap, i, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);
867 bp->efi_systab = dom_pa((unsigned long) fw_mem);
868 bp->efi_memmap = dom_pa((unsigned long) efi_memmap);
869 BUG_ON(i > NUM_MEM_DESCS);
870 bp->efi_memmap_size = i * sizeof(efi_memory_desc_t);
871 bp->efi_memdesc_size = sizeof(efi_memory_desc_t);
872 bp->efi_memdesc_version = EFI_MEMDESC_VERSION;
873 bp->command_line = 0;
874 bp->console_info.num_cols = 80;
875 bp->console_info.num_rows = 25;
876 bp->console_info.orig_x = 0;
877 bp->console_info.orig_y = 24;
878 bp->fpswa = dom_pa((unsigned long) fpswa_inf);
879 if (d == dom0) {
880 int j;
881 u64 addr;
883 // dom0 doesn't need build_physmap_table()
884 // see arch_set_info_guest()
885 // instead we allocate pages manually.
886 for (j = 0; j < i; j++) {
887 md = &efi_memmap[j];
888 if (md->phys_addr > maxmem)
889 break;
891 if (md->type == EFI_LOADER_DATA ||
892 md->type == EFI_PAL_CODE ||
893 md->type == EFI_CONVENTIONAL_MEMORY) {
894 unsigned long start = md->phys_addr & PAGE_MASK;
895 unsigned long end = md->phys_addr +
896 (md->num_pages << EFI_PAGE_SHIFT);
898 if (end == start) {
899 // md->num_pages = 0 is allowed.
900 end += PAGE_SIZE;
901 }
902 if (end > (max_page << PAGE_SHIFT))
903 end = (max_page << PAGE_SHIFT);
905 for (addr = start; addr < end; addr += PAGE_SIZE) {
906 assign_new_domain0_page(d, addr);
907 }
908 }
909 }
910 // Map low-memory holes & unmapped MMIO for legacy drivers
911 for (addr = 0; addr < 1*MB; addr += PAGE_SIZE) {
912 if (domain_page_mapped(d, addr))
913 continue;
915 if (efi_mmio(addr, PAGE_SIZE))
916 assign_domain_mmio_page(d, addr, PAGE_SIZE);
917 }
918 }
919 for (i = 0 ; i < bp->efi_memmap_size/sizeof(efi_memory_desc_t) ; i++) {
920 md = efi_memmap + i;
921 print_md(md);
922 }
923 }