source: trunk/packages/xen-3.1/xen-3.1/xen/arch/ia64/xen/dom_fw.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 27.2 KB
Line 
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 */
10
11#include <xen/config.h>
12#include <asm/system.h>
13#include <asm/pgalloc.h>
14
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>
24#include <xen/errno.h>
25
26#include <asm/dom_fw.h>
27#include <asm/bundle.h>
28
29#define ONE_MB (1UL << 20)
30
31extern unsigned long running_on_sim;
32
33#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"
34
35#define MAKE_MD(typ, attr, start, end)                                  \
36        do {                                                            \
37                md = tables->efi_memmap + i++;                          \
38                md->type = typ;                                         \
39                md->pad = 0;                                            \
40                md->phys_addr = start;                                  \
41                md->virt_addr = 0;                                      \
42                md->num_pages = (end - start) >> EFI_PAGE_SHIFT;        \
43                md->attribute = attr;                                   \
44        } while (0)
45
46#define EFI_HYPERCALL_PATCH(tgt, call)                                  \
47        do {                                                            \
48                dom_efi_hypercall_patch(d, FW_HYPERCALL_##call##_PADDR, \
49                                 FW_HYPERCALL_##call, hypercalls_imva); \
50                /* Descriptor address.  */                              \
51                tables->efi_runtime.tgt =                               \
52                                    FW_FIELD_MPA(func_ptrs) + 8 * pfn;  \
53                /* Descriptor.  */                                      \
54                tables->func_ptrs[pfn++] = FW_HYPERCALL_##call##_PADDR; \
55                tables->func_ptrs[pfn++] = 0;                           \
56        } while (0)
57
58/* allocate a page for fw
59 * guest_setup() @ libxc/xc_linux_build.c does for domU
60 */
61static inline void
62assign_new_domain_page_if_dom0(struct domain *d, unsigned long mpaddr)
63{
64        if (d == dom0)
65            assign_new_domain0_page(d, mpaddr);
66}
67
68/**************************************************************************
69Hypercall bundle creation
70**************************************************************************/
71
72static void
73build_hypercall_bundle(u64 *imva, u64 brkimm, u64 hypnum, u64 ret)
74{
75        INST64_A5 slot0;
76        INST64_I19 slot1;
77        INST64_B4 slot2;
78        IA64_BUNDLE bundle;
79
80        // slot1: mov r2 = hypnum (low 20 bits)
81        slot0.inst = 0;
82        slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9;
83        slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7;
84        slot0.imm5c = hypnum >> 16; slot0.s = 0;
85        // slot1: break brkimm
86        slot1.inst = 0;
87        slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0;
88        slot1.imm20 = brkimm; slot1.i = brkimm >> 20;
89        // if ret slot2:  br.ret.sptk.many rp
90        // else   slot2:  br.cond.sptk.many rp
91        slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0;
92        slot2.wh = 0; slot2.d = 0; slot2.major = 0x0;
93        if (ret) {
94                slot2.btype = 4; slot2.x6 = 0x21;
95        }
96        else {
97                slot2.btype = 0; slot2.x6 = 0x20;
98        }
99       
100        bundle.i64[0] = 0; bundle.i64[1] = 0;
101        bundle.template = 0x11;
102        bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst;
103        bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18;
104       
105        imva[0] = bundle.i64[0]; imva[1] = bundle.i64[1];
106        ia64_fc(imva);
107        ia64_fc(imva + 1);
108}
109
110static void
111build_pal_hypercall_bundles(u64 *imva, u64 brkimm, u64 hypnum)
112{
113        extern unsigned long pal_call_stub[];
114        IA64_BUNDLE bundle;
115        INST64_A5 slot_a5;
116        INST64_M37 slot_m37;
117
118        /* The source of the hypercall stub is the pal_call_stub function
119           defined in xenasm.S.  */
120
121        /* Copy the first bundle and patch the hypercall number.  */
122        bundle.i64[0] = pal_call_stub[0];
123        bundle.i64[1] = pal_call_stub[1];
124        slot_a5.inst = bundle.slot0;
125        slot_a5.imm7b = hypnum;
126        slot_a5.imm9d = hypnum >> 7;
127        slot_a5.imm5c = hypnum >> 16;
128        bundle.slot0 = slot_a5.inst;
129        imva[0] = bundle.i64[0];
130        imva[1] = bundle.i64[1];
131        ia64_fc(imva);
132        ia64_fc(imva + 1);
133       
134        /* Copy the second bundle and patch the hypercall vector.  */
135        bundle.i64[0] = pal_call_stub[2];
136        bundle.i64[1] = pal_call_stub[3];
137        slot_m37.inst = bundle.slot0;
138        slot_m37.imm20a = brkimm;
139        slot_m37.i = brkimm >> 20;
140        bundle.slot0 = slot_m37.inst;
141        imva[2] = bundle.i64[0];
142        imva[3] = bundle.i64[1];
143        ia64_fc(imva + 2);
144        ia64_fc(imva + 3);
145}
146
147// builds a hypercall bundle at domain physical address
148static void
149dom_fpswa_hypercall_patch(struct domain *d, unsigned long imva)
150{
151        unsigned long *entry_imva, *patch_imva;
152        const unsigned long entry_paddr = FW_HYPERCALL_FPSWA_ENTRY_PADDR;
153        const unsigned long patch_paddr = FW_HYPERCALL_FPSWA_PATCH_PADDR;
154
155        entry_imva = (unsigned long *)(imva + entry_paddr -
156                                       FW_HYPERCALL_BASE_PADDR);
157        patch_imva = (unsigned long *)(imva + patch_paddr -
158                                       FW_HYPERCALL_BASE_PADDR);
159
160        /* Descriptor.  */
161        *entry_imva++ = patch_paddr;
162        *entry_imva   = 0;
163
164        build_hypercall_bundle(patch_imva, d->arch.breakimm,
165                               FW_HYPERCALL_FPSWA, 1);
166}
167
168// builds a hypercall bundle at domain physical address
169static void
170dom_efi_hypercall_patch(struct domain *d, unsigned long paddr,
171                        unsigned long hypercall, unsigned long imva)
172{
173        build_hypercall_bundle((u64 *)(imva + paddr - FW_HYPERCALL_BASE_PADDR),
174                               d->arch.breakimm, hypercall, 1);
175}
176
177// builds a hypercall bundle at domain physical address
178static void
179dom_fw_hypercall_patch(struct domain *d, unsigned long paddr,
180                       unsigned long hypercall,unsigned long ret,
181                       unsigned long imva)
182{
183        build_hypercall_bundle((u64 *)(imva + paddr - FW_HYPERCALL_BASE_PADDR),
184                               d->arch.breakimm, hypercall, ret);
185}
186
187static void
188dom_fw_pal_hypercall_patch(struct domain *d, unsigned long paddr,
189                           unsigned long imva)
190{
191        build_pal_hypercall_bundles((u64*)(imva + paddr -
192                                    FW_HYPERCALL_BASE_PADDR),
193                                    d->arch.breakimm, FW_HYPERCALL_PAL_CALL);
194}
195
196static inline void
197print_md(efi_memory_desc_t *md)
198{
199        u64 size;
200       
201        printk(XENLOG_INFO "dom mem: type=%2u, attr=0x%016lx, "
202               "range=[0x%016lx-0x%016lx) ",
203               md->type, md->attribute, md->phys_addr,
204               md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT));
205
206        size = md->num_pages << EFI_PAGE_SHIFT;
207        if (size > ONE_MB)
208                printk("(%luMB)\n", size >> 20);
209        else
210                printk("(%luKB)\n", size >> 10);
211}
212
213static u32 lsapic_nbr;
214
215/* Modify lsapic table.  Provides LPs.  */
216static int 
217acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end)
218{
219        struct acpi_table_lsapic *lsapic;
220        int enable;
221
222        lsapic = (struct acpi_table_lsapic *) header;
223        if (!lsapic)
224                return -EINVAL;
225
226        if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)
227                enable = 1;
228        else
229                enable = 0;
230        if (lsapic->flags.enabled && enable) {
231                printk("enable lsapic entry: 0x%lx\n", (u64)lsapic);
232                lsapic->id = lsapic_nbr;
233                lsapic->eid = 0;
234                lsapic_nbr++;
235        } else if (lsapic->flags.enabled) {
236                printk("DISABLE lsapic entry: 0x%lx\n", (u64)lsapic);
237                lsapic->flags.enabled = 0;
238                lsapic->id = 0;
239                lsapic->eid = 0;
240        }
241        return 0;
242}
243
244static int __init
245acpi_patch_plat_int_src (
246        acpi_table_entry_header *header, const unsigned long end)
247{
248        struct acpi_table_plat_int_src *plintsrc;
249
250        plintsrc = (struct acpi_table_plat_int_src *)header;
251        if (!plintsrc)
252                return -EINVAL;
253
254        if (plintsrc->type == ACPI_INTERRUPT_CPEI) {
255                printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n");
256                plintsrc->type = -1;
257        }
258        return 0;
259}
260
261static u8
262generate_acpi_checksum(void *tbl, unsigned long len)
263{
264        u8 *ptr, sum = 0;
265
266        for (ptr = tbl; len > 0 ; len--, ptr++)
267                sum += *ptr;
268
269        return 0 - sum;
270}
271
272static int
273acpi_update_madt_checksum (unsigned long phys_addr, unsigned long size)
274{
275        struct acpi_table_madt* acpi_madt;
276
277        if (!phys_addr || !size)
278                return -EINVAL;
279
280        acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
281        acpi_madt->header.checksum = 0;
282        acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);
283
284        return 0;
285}
286
287/* base is physical address of acpi table */
288static void touch_acpi_table(void)
289{
290        lsapic_nbr = 0;
291        if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)
292                printk("Error parsing MADT - no LAPIC entries\n");
293        if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,
294                                  acpi_patch_plat_int_src, 0) < 0)
295                printk("Error parsing MADT - no PLAT_INT_SRC entries\n");
296
297        acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);
298
299        return;
300}
301
302struct fake_acpi_tables {
303        struct acpi20_table_rsdp rsdp;
304        struct xsdt_descriptor_rev2 xsdt;
305        u64 madt_ptr;
306        struct fadt_descriptor_rev2 fadt;
307        struct facs_descriptor_rev2 facs;
308        struct acpi_table_header dsdt;
309        u8 aml[8 + 11 * MAX_VIRT_CPUS];
310        struct acpi_table_madt madt;
311        struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS];
312        u8 pm1a_evt_blk[4];
313        u8 pm1a_cnt_blk[1];
314        u8 pm_tmr_blk[4];
315};
316#define ACPI_TABLE_MPA(field) \
317  FW_ACPI_BASE_PADDR + offsetof(struct fake_acpi_tables, field);
318
319/* Create enough of an ACPI structure to make the guest OS ACPI happy. */
320static void
321dom_fw_fake_acpi(struct domain *d, struct fake_acpi_tables *tables)
322{
323        struct acpi20_table_rsdp *rsdp = &tables->rsdp;
324        struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt;
325        struct fadt_descriptor_rev2 *fadt = &tables->fadt;
326        struct facs_descriptor_rev2 *facs = &tables->facs;
327        struct acpi_table_header *dsdt = &tables->dsdt;
328        struct acpi_table_madt *madt = &tables->madt;
329        struct acpi_table_lsapic *lsapic = tables->lsapic;
330        int i;
331        int aml_len;
332        int nbr_cpus;
333
334        memset(tables, 0, sizeof(struct fake_acpi_tables));
335
336        /* setup XSDT (64bit version of RSDT) */
337        memcpy(xsdt->signature, XSDT_SIG, sizeof(xsdt->signature));
338        /* XSDT points to both the FADT and the MADT, so add one entry */
339        xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(u64);
340        xsdt->revision = 1;
341        memcpy(xsdt->oem_id, "XEN", 3);
342        memcpy(xsdt->oem_table_id, "Xen/ia64", 8);
343        memcpy(xsdt->asl_compiler_id, "XEN", 3);
344        xsdt->asl_compiler_revision = (xen_major_version() << 16) |
345                xen_minor_version();
346
347        xsdt->table_offset_entry[0] = ACPI_TABLE_MPA(fadt);
348        tables->madt_ptr = ACPI_TABLE_MPA(madt);
349
350        xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length);
351
352        /* setup FADT */
353        memcpy(fadt->signature, FADT_SIG, sizeof(fadt->signature));
354        fadt->length = sizeof(struct fadt_descriptor_rev2);
355        fadt->revision = FADT2_REVISION_ID;
356        memcpy(fadt->oem_id, "XEN", 3);
357        memcpy(fadt->oem_table_id, "Xen/ia64", 8);
358        memcpy(fadt->asl_compiler_id, "XEN", 3);
359        fadt->asl_compiler_revision = (xen_major_version() << 16) |
360                xen_minor_version();
361
362        memcpy(facs->signature, FACS_SIG, sizeof(facs->signature));
363        facs->version = 1;
364        facs->length = sizeof(struct facs_descriptor_rev2);
365
366        fadt->xfirmware_ctrl = ACPI_TABLE_MPA(facs);
367        fadt->Xdsdt = ACPI_TABLE_MPA(dsdt);
368
369        /*
370         * All of the below FADT entries are filled it to prevent warnings
371         * from sanity checks in the ACPI CA.  Emulate required ACPI hardware
372         * registers in system memory.
373         */
374        fadt->pm1_evt_len = 4;
375        fadt->xpm1a_evt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
376        fadt->xpm1a_evt_blk.register_bit_width = 8;
377        fadt->xpm1a_evt_blk.address = ACPI_TABLE_MPA(pm1a_evt_blk);
378        fadt->pm1_cnt_len = 1;
379        fadt->xpm1a_cnt_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
380        fadt->xpm1a_cnt_blk.register_bit_width = 8;
381        fadt->xpm1a_cnt_blk.address = ACPI_TABLE_MPA(pm1a_cnt_blk);
382        fadt->pm_tm_len = 4;
383        fadt->xpm_tmr_blk.address_space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
384        fadt->xpm_tmr_blk.register_bit_width = 8;
385        fadt->xpm_tmr_blk.address = ACPI_TABLE_MPA(pm_tmr_blk);
386
387        fadt->checksum = generate_acpi_checksum(fadt, fadt->length);
388
389        /* setup RSDP */
390        memcpy(rsdp->signature, RSDP_SIG, strlen(RSDP_SIG));
391        memcpy(rsdp->oem_id, "XEN", 3);
392        rsdp->revision = 2; /* ACPI 2.0 includes XSDT */
393        rsdp->length = sizeof(struct acpi20_table_rsdp);
394        rsdp->xsdt_address = ACPI_TABLE_MPA(xsdt);
395
396        rsdp->checksum = generate_acpi_checksum(rsdp,
397                                                ACPI_RSDP_CHECKSUM_LENGTH);
398        rsdp->ext_checksum = generate_acpi_checksum(rsdp, rsdp->length);
399
400        /* setup DSDT with trivial namespace. */ 
401        memcpy(dsdt->signature, DSDT_SIG, strlen(DSDT_SIG));
402        dsdt->revision = 1;
403        memcpy(dsdt->oem_id, "XEN", 3);
404        memcpy(dsdt->oem_table_id, "Xen/ia64", 8);
405        memcpy(dsdt->asl_compiler_id, "XEN", 3);
406        dsdt->asl_compiler_revision = (xen_major_version() << 16) |
407                xen_minor_version();
408
409        /* Trivial namespace, avoids ACPI CA complaints */
410        tables->aml[0] = 0x10; /* Scope */
411        tables->aml[1] = 0x40; /* length/offset to next object (patched) */
412        tables->aml[2] = 0x00;
413        memcpy(&tables->aml[3], "_SB_", 4);
414
415        /* The processor object isn't absolutely necessary, revist for SMP */
416        aml_len = 7;
417        for (i = 0; i < 3; i++) {
418                unsigned char *p = tables->aml + aml_len;
419                p[0] = 0x5b; /* processor object */
420                p[1] = 0x83;
421                p[2] = 0x0b; /* next */
422                p[3] = 'C';
423                p[4] = 'P';
424                snprintf ((char *)p + 5, 3, "%02x", i);
425                if (i < 16)
426                        p[5] = 'U';
427                p[7] = i;       /* acpi_id */
428                p[8] = 0;       /* pblk_addr */
429                p[9] = 0;
430                p[10] = 0;
431                p[11] = 0;
432                p[12] = 0;      /* pblk_len */
433                aml_len += 13;
434        }
435        tables->aml[1] = 0x40 + ((aml_len - 1) & 0x0f);
436        tables->aml[2] = (aml_len - 1) >> 4;
437        dsdt->length = sizeof(struct acpi_table_header) + aml_len;
438        dsdt->checksum = generate_acpi_checksum(dsdt, dsdt->length);
439
440        /* setup MADT */
441        memcpy(madt->header.signature, APIC_SIG, sizeof(madt->header.signature));
442        madt->header.revision = 2;
443        memcpy(madt->header.oem_id, "XEN", 3);
444        memcpy(madt->header.oem_table_id, "Xen/ia64", 8);
445        memcpy(madt->header.asl_compiler_id, "XEN", 3);
446        madt->header.asl_compiler_revision = (xen_major_version() << 16) |
447                xen_minor_version();
448
449        /* An LSAPIC entry describes a CPU.  */
450        nbr_cpus = 0;
451        for (i = 0; i < MAX_VIRT_CPUS; i++) {
452                lsapic[i].header.type = ACPI_MADT_LSAPIC;
453                lsapic[i].header.length = sizeof(struct acpi_table_lsapic);
454                lsapic[i].acpi_id = i;
455                lsapic[i].id = i;
456                lsapic[i].eid = 0;
457                if (d->vcpu[i] != NULL) {
458                        lsapic[i].flags.enabled = 1;
459                        nbr_cpus++;
460                }
461        }
462        madt->header.length = sizeof(struct acpi_table_madt) +
463                              nbr_cpus * sizeof(struct acpi_table_lsapic);
464        madt->header.checksum = generate_acpi_checksum(madt,
465                                                       madt->header.length);
466        return;
467}
468
469static int
470efi_mdt_cmp(const void *a, const void *b)
471{
472        const efi_memory_desc_t *x = a, *y = b;
473
474        if (x->phys_addr > y->phys_addr)
475                return 1;
476        if (x->phys_addr < y->phys_addr)
477                return -1;
478
479        // num_pages == 0 is allowed.
480        if (x->num_pages > y->num_pages)
481                return 1;
482        if (x->num_pages < y->num_pages)
483                return -1;
484
485        return 0;
486}
487
488#define NFUNCPTRS 16
489#define NUM_EFI_SYS_TABLES 6
490#define NUM_MEM_DESCS 64 //large enough
491
492struct fw_tables {
493        efi_system_table_t efi_systab;
494        efi_runtime_services_t efi_runtime;
495        efi_config_table_t efi_tables[NUM_EFI_SYS_TABLES];
496
497        struct ia64_sal_systab sal_systab;
498        struct ia64_sal_desc_entry_point sal_ed;
499        struct ia64_sal_desc_ap_wakeup sal_wakeup;
500        /* End of SAL descriptors.  Do not forget to update checkum bound.  */
501
502        fpswa_interface_t fpswa_inf;
503        efi_memory_desc_t efi_memmap[NUM_MEM_DESCS];
504        unsigned long func_ptrs[2*NFUNCPTRS];
505        struct xen_sal_data sal_data;
506        unsigned char fw_vendor[sizeof(FW_VENDOR)];
507};
508#define FW_FIELD_MPA(field) \
509   FW_TABLES_BASE_PADDR + offsetof(struct fw_tables, field)
510
511/* Complete the dom0 memmap.  */
512static int
513complete_dom0_memmap(struct domain *d,
514                     struct fw_tables *tables,
515                     unsigned long maxmem,
516                     int num_mds)
517{
518        efi_memory_desc_t *md;
519        u64 addr;
520        void *efi_map_start, *efi_map_end, *p;
521        u64 efi_desc_size;
522        int i;
523        unsigned long dom_mem = maxmem - (d->tot_pages << PAGE_SHIFT);
524
525        /* Walk through all MDT entries.
526           Copy all interesting entries.  */
527        efi_map_start = __va(ia64_boot_param->efi_memmap);
528        efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
529        efi_desc_size = ia64_boot_param->efi_memdesc_size;
530
531        for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
532                const efi_memory_desc_t *md = p;
533                efi_memory_desc_t *dom_md = &tables->efi_memmap[num_mds];
534                u64 start = md->phys_addr;
535                u64 size = md->num_pages << EFI_PAGE_SHIFT;
536                u64 end = start + size;
537                u64 mpaddr;
538                unsigned long flags;
539
540                switch (md->type) {
541                case EFI_RUNTIME_SERVICES_CODE:
542                case EFI_RUNTIME_SERVICES_DATA:
543                case EFI_ACPI_RECLAIM_MEMORY:
544                case EFI_ACPI_MEMORY_NVS:
545                case EFI_RESERVED_TYPE:
546                        /*
547                         * Map into dom0 - We must respect protection
548                         * and cache attributes.  Not all of these pages
549                         * are writable!!!
550                         */
551                        flags = ASSIGN_writable;        /* dummy - zero */
552                        if (md->attribute & EFI_MEMORY_WP)
553                                flags |= ASSIGN_readonly;
554                        if ((md->attribute & EFI_MEMORY_UC) &&
555                            !(md->attribute & EFI_MEMORY_WB))
556                                flags |= ASSIGN_nocache;
557
558                        assign_domain_mach_page(d, start, size, flags);
559
560                        /* Fall-through.  */
561                case EFI_MEMORY_MAPPED_IO:
562                        /* Will be mapped with ioremap.  */
563                        /* Copy descriptor.  */
564                        *dom_md = *md;
565                        dom_md->virt_addr = 0;
566                        num_mds++;
567                        break;
568
569                case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
570                        flags = ASSIGN_writable;        /* dummy - zero */
571                        if (md->attribute & EFI_MEMORY_UC)
572                                flags |= ASSIGN_nocache;
573
574                        if (start > 0x1ffffffff0000000UL) {
575                                mpaddr = 0x4000000000000UL - size;
576                                printk(XENLOG_INFO "Remapping IO ports from "
577                                       "%lx to %lx\n", start, mpaddr);
578                        } else
579                                mpaddr = start;
580
581                        /* Map into dom0.  */
582                        assign_domain_mmio_page(d, mpaddr, start, size, flags);
583                        /* Copy descriptor.  */
584                        *dom_md = *md;
585                        dom_md->phys_addr = mpaddr;
586                        dom_md->virt_addr = 0;
587                        num_mds++;
588                        break;
589
590                case EFI_CONVENTIONAL_MEMORY:
591                case EFI_LOADER_CODE:
592                case EFI_LOADER_DATA:
593                case EFI_BOOT_SERVICES_CODE:
594                case EFI_BOOT_SERVICES_DATA:
595                        if (!(md->attribute & EFI_MEMORY_WB))
596                                break;
597
598                        start = max(FW_END_PADDR, start);
599                        end = min(start + dom_mem, end);
600                        if (end <= start)
601                                break;
602
603                        dom_md->type = EFI_CONVENTIONAL_MEMORY;
604                        dom_md->phys_addr = start;
605                        dom_md->virt_addr = 0;
606                        dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
607                        dom_md->attribute = EFI_MEMORY_WB;
608                        num_mds++;
609
610                        dom_mem -= dom_md->num_pages << EFI_PAGE_SHIFT;
611                        d->arch.convmem_end = end;
612                        break;
613
614                case EFI_UNUSABLE_MEMORY:
615                case EFI_PAL_CODE:
616                        /*
617                         * We don't really need these, but holes in the
618                         * memory map may cause Linux to assume there are
619                         * uncacheable ranges within a granule.
620                         */
621                        dom_md->type = EFI_UNUSABLE_MEMORY;
622                        dom_md->phys_addr = start;
623                        dom_md->virt_addr = 0;
624                        dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;
625                        dom_md->attribute = EFI_MEMORY_WB;
626                        num_mds++;
627                        break;
628
629                default:
630                        /* Print a warning but continue.  */
631                        printk("complete_dom0_memmap: warning: "
632                               "unhandled MDT entry type %u\n", md->type);
633                }
634        }
635        BUG_ON(num_mds > NUM_MEM_DESCS);
636       
637        sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t),
638             efi_mdt_cmp, NULL);
639
640        /* setup_guest() @ libxc/xc_linux_build() arranges memory for domU.
641         * however no one arranges memory for dom0,
642         * instead we allocate pages manually.
643         */
644        for (i = 0; i < num_mds; i++) {
645                md = &tables->efi_memmap[i];
646
647                if (md->type == EFI_LOADER_DATA ||
648                    md->type == EFI_PAL_CODE ||
649                    md->type == EFI_CONVENTIONAL_MEMORY) {
650                        unsigned long start = md->phys_addr & PAGE_MASK;
651                        unsigned long end = md->phys_addr +
652                                (md->num_pages << EFI_PAGE_SHIFT);
653
654                        if (end == start) {
655                                /* md->num_pages = 0 is allowed. */
656                                continue;
657                        }
658                       
659                        for (addr = start; addr < end; addr += PAGE_SIZE)
660                                assign_new_domain0_page(d, addr);
661                }
662        }
663        // Map low-memory holes & unmapped MMIO for legacy drivers
664        for (addr = 0; addr < ONE_MB; addr += PAGE_SIZE) {
665                if (domain_page_mapped(d, addr))
666                        continue;
667               
668                if (efi_mmio(addr, PAGE_SIZE)) {
669                        unsigned long flags;
670                        flags = ASSIGN_writable | ASSIGN_nocache;
671                        assign_domain_mmio_page(d, addr, addr,
672                                                PAGE_SIZE, flags);
673                }
674        }
675        return num_mds;
676}
677       
678static void
679dom_fw_init(struct domain *d,
680            struct ia64_boot_param *bp,
681            struct fw_tables *tables,
682            unsigned long hypercalls_imva,
683            unsigned long maxmem)
684{
685        efi_memory_desc_t *md;
686        unsigned long pfn;
687        unsigned char checksum;
688        char *cp;
689        int num_mds, i;
690
691        memset(tables, 0, sizeof(struct fw_tables));
692
693        /* Initialise for EFI_SET_VIRTUAL_ADDRESS_MAP emulation */
694        d->arch.efi_runtime = &tables->efi_runtime;
695        d->arch.fpswa_inf   = &tables->fpswa_inf;
696        d->arch.sal_data    = &tables->sal_data;
697
698        /* EFI systab.  */
699        tables->efi_systab.hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
700        tables->efi_systab.hdr.revision  = EFI_SYSTEM_TABLE_REVISION;
701        tables->efi_systab.hdr.headersize = sizeof(tables->efi_systab.hdr);
702
703        memcpy(tables->fw_vendor,FW_VENDOR,sizeof(FW_VENDOR));
704        tables->efi_systab.fw_vendor = FW_FIELD_MPA(fw_vendor);
705        tables->efi_systab.fw_revision = 1;
706        tables->efi_systab.runtime = (void *)FW_FIELD_MPA(efi_runtime);
707        tables->efi_systab.nr_tables = NUM_EFI_SYS_TABLES;
708        tables->efi_systab.tables = FW_FIELD_MPA(efi_tables);
709
710        /* EFI runtime.  */
711        tables->efi_runtime.hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
712        tables->efi_runtime.hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
713        tables->efi_runtime.hdr.headersize = sizeof(tables->efi_runtime.hdr);
714
715        pfn = 0;
716        EFI_HYPERCALL_PATCH(get_time,EFI_GET_TIME);
717        EFI_HYPERCALL_PATCH(set_time,EFI_SET_TIME);
718        EFI_HYPERCALL_PATCH(get_wakeup_time,EFI_GET_WAKEUP_TIME);
719        EFI_HYPERCALL_PATCH(set_wakeup_time,EFI_SET_WAKEUP_TIME);
720        EFI_HYPERCALL_PATCH(set_virtual_address_map,
721                            EFI_SET_VIRTUAL_ADDRESS_MAP);
722        EFI_HYPERCALL_PATCH(get_variable,EFI_GET_VARIABLE);
723        EFI_HYPERCALL_PATCH(get_next_variable,EFI_GET_NEXT_VARIABLE);
724        EFI_HYPERCALL_PATCH(set_variable,EFI_SET_VARIABLE);
725        EFI_HYPERCALL_PATCH(get_next_high_mono_count,
726                            EFI_GET_NEXT_HIGH_MONO_COUNT);
727        EFI_HYPERCALL_PATCH(reset_system,EFI_RESET_SYSTEM);
728
729        /* System tables.  */
730        tables->efi_tables[0].guid = SAL_SYSTEM_TABLE_GUID;
731        tables->efi_tables[0].table = FW_FIELD_MPA(sal_systab);
732        for (i = 1; i < NUM_EFI_SYS_TABLES; i++) {
733                tables->efi_tables[i].guid = NULL_GUID;
734                tables->efi_tables[i].table = 0;
735        }
736        i = 1;
737        if (d == dom0) {
738                /* Write messages to the console.  */
739                touch_acpi_table();
740
741                printk("Domain0 EFI passthrough:");
742                if (efi.mps) {
743                        tables->efi_tables[i].guid = MPS_TABLE_GUID;
744                        tables->efi_tables[i].table = __pa(efi.mps);
745                        printk(" MPS=0x%lx",tables->efi_tables[i].table);
746                        i++;
747                }
748
749                if (efi.acpi20) {
750                        tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;
751                        tables->efi_tables[i].table = __pa(efi.acpi20);
752                        printk(" ACPI 2.0=0x%lx",tables->efi_tables[i].table);
753                        i++;
754                }
755                if (efi.acpi) {
756                        tables->efi_tables[i].guid = ACPI_TABLE_GUID;
757                        tables->efi_tables[i].table = __pa(efi.acpi);
758                        printk(" ACPI=0x%lx",tables->efi_tables[i].table);
759                        i++;
760                }
761                if (efi.smbios) {
762                        tables->efi_tables[i].guid = SMBIOS_TABLE_GUID;
763                        tables->efi_tables[i].table = __pa(efi.smbios);
764                        printk(" SMBIOS=0x%lx",tables->efi_tables[i].table);
765                        i++;
766                }
767                if (efi.hcdp) {
768                        tables->efi_tables[i].guid = HCDP_TABLE_GUID;
769                        tables->efi_tables[i].table = __pa(efi.hcdp);
770                        printk(" HCDP=0x%lx",tables->efi_tables[i].table);
771                        i++;
772                }
773                printk("\n");
774        } else {
775                printk(XENLOG_GUEST XENLOG_INFO "DomainU EFI build up:");
776
777                tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;
778                tables->efi_tables[i].table = FW_ACPI_BASE_PADDR;
779                printk(" ACPI 2.0=0x%lx", tables->efi_tables[i].table);
780                i++;
781                printk("\n");
782        }
783
784        /* fill in the SAL system table: */
785        memcpy(tables->sal_systab.signature, "SST_", 4);
786        tables->sal_systab.size = sizeof(tables->sal_systab);
787        tables->sal_systab.sal_rev_minor = 1;
788        tables->sal_systab.sal_rev_major = 0;
789        tables->sal_systab.entry_count = 2;
790
791        memcpy((char *)tables->sal_systab.oem_id, "Xen/ia64", 8);
792        memcpy((char *)tables->sal_systab.product_id, "Xen/ia64", 8);
793
794        /* PAL entry point: */
795        tables->sal_ed.type = SAL_DESC_ENTRY_POINT;
796        tables->sal_ed.pal_proc = FW_HYPERCALL_PAL_CALL_PADDR;
797        dom_fw_pal_hypercall_patch(d, tables->sal_ed.pal_proc, 
798                                   hypercalls_imva);
799        /* SAL entry point.  */
800        tables->sal_ed.sal_proc = FW_HYPERCALL_SAL_CALL_PADDR;
801        dom_fw_hypercall_patch(d, tables->sal_ed.sal_proc,
802                               FW_HYPERCALL_SAL_CALL, 1, hypercalls_imva);
803        tables->sal_ed.gp = 0;  /* will be ignored */
804
805        /* Fill an AP wakeup descriptor.  */
806        tables->sal_wakeup.type = SAL_DESC_AP_WAKEUP;
807        tables->sal_wakeup.mechanism = IA64_SAL_AP_EXTERNAL_INT;
808        tables->sal_wakeup.vector = XEN_SAL_BOOT_RENDEZ_VEC;
809
810        /* Compute checksum.  */
811        checksum = 0;
812        for (cp = (char *)&tables->sal_systab;
813             cp < (char *)&tables->fpswa_inf;
814             ++cp)
815                checksum += *cp;
816        tables->sal_systab.checksum = -checksum;
817
818        /* SAL return point.  */
819        dom_fw_hypercall_patch(d, FW_HYPERCALL_SAL_RETURN_PADDR,
820                               FW_HYPERCALL_SAL_RETURN, 0, hypercalls_imva);
821
822        /* Fill in the FPSWA interface: */
823        if (fpswa_interface) {
824                tables->fpswa_inf.revision = fpswa_interface->revision;
825                dom_fpswa_hypercall_patch(d, hypercalls_imva);
826                tables->fpswa_inf.fpswa = 
827                                       (void *)FW_HYPERCALL_FPSWA_ENTRY_PADDR;
828        }
829
830        i = 0; /* Used by MAKE_MD */
831
832        /* hypercall patches live here, masquerade as reserved PAL memory */
833        MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB|EFI_MEMORY_RUNTIME,
834                FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR);
835
836        /* Create dom0/domu md entry for fw and cpi tables area.  */
837        MAKE_MD(EFI_ACPI_MEMORY_NVS, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
838                FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR);
839        MAKE_MD(EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME,
840                FW_TABLES_BASE_PADDR, FW_TABLES_END_PADDR);
841
842        if (d != dom0 || running_on_sim) {
843                /* DomU (or hp-ski).
844                   Create a continuous memory area.  */
845                /* Memory.  */
846                MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB,
847                        FW_END_PADDR, maxmem);
848                d->arch.convmem_end = maxmem;
849               
850                /* Create an entry for IO ports.  */
851                MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC,
852                        IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE);
853
854                num_mds = i;
855        }
856        else {
857                /* Dom0.
858                   We must preserve ACPI data from real machine,
859                   as well as IO areas.  */
860                num_mds = complete_dom0_memmap(d, tables, maxmem, i);
861        }
862
863        /* Display memmap.  */
864        for (i = 0 ; i < num_mds; i++)
865                print_md(&tables->efi_memmap[i]);
866
867        /* Fill boot_param  */
868        bp->efi_systab = FW_FIELD_MPA(efi_systab);
869        bp->efi_memmap = FW_FIELD_MPA(efi_memmap);
870        bp->efi_memmap_size = num_mds * 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        if (fpswa_interface)
879                bp->fpswa = FW_FIELD_MPA(fpswa_inf);
880}
881
882void dom_fw_setup(struct domain *d, unsigned long bp_mpa, unsigned long maxmem)
883{
884        struct ia64_boot_param *bp;
885        unsigned long imva_tables_base;
886        unsigned long imva_hypercall_base;
887
888        BUILD_BUG_ON(sizeof(struct fw_tables) >
889                     (FW_TABLES_END_PADDR - FW_TABLES_BASE_PADDR));
890
891        BUILD_BUG_ON(sizeof(struct fake_acpi_tables) >
892                     (FW_ACPI_END_PADDR - FW_ACPI_BASE_PADDR));
893
894        /* Create page for hypercalls.  */
895        assign_new_domain_page_if_dom0(d, FW_HYPERCALL_BASE_PADDR);
896        imva_hypercall_base = (unsigned long)domain_mpa_to_imva
897                                             (d, FW_HYPERCALL_BASE_PADDR);
898
899        /* Create page for acpi tables.  */
900        if (d != dom0) {
901                void *imva;
902
903                assign_new_domain_page_if_dom0(d, FW_ACPI_BASE_PADDR);
904                imva = domain_mpa_to_imva (d, FW_ACPI_BASE_PADDR);
905                dom_fw_fake_acpi(d, (struct fake_acpi_tables *)imva);
906        }
907
908        /* Create page for FW tables.  */
909        assign_new_domain_page_if_dom0(d, FW_TABLES_BASE_PADDR);
910        imva_tables_base = (unsigned long)domain_mpa_to_imva
911                                          (d, FW_TABLES_BASE_PADDR);
912
913        /* Create page for boot_param.  */
914        assign_new_domain_page_if_dom0(d, bp_mpa);
915        bp = domain_mpa_to_imva(d, bp_mpa);
916
917        dom_fw_init(d, bp, (struct fw_tables *)imva_tables_base,
918                    imva_hypercall_base, maxmem);
919}
Note: See TracBrowser for help on using the repository browser.