📄 dom_fw_common.c
字号:
/* * Xen domain firmware emulation support * Copyright (C) 2004 Hewlett-Packard Co. * Dan Magenheimer (dan.magenheimer@hp.com) * * Copyright (c) 2006, 2007 * Isaku Yamahata <yamahata at valinux co jp> * VA Linux Systems Japan K.K. * dom0 vp model support */#ifdef __XEN__#include <asm/system.h>#include <asm/dom_fw_dom0.h>#include <asm/dom_fw_utils.h>#else#include <string.h>#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <inttypes.h>#include <xen/arch-ia64.h>#include <asm/bundle.h>#include "xg_private.h"#include "xc_dom.h"#include "ia64/xc_dom_ia64_util.h"#define ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")#endif /* __XEN__ */#include <xen/acpi.h>#include <asm/dom_fw.h>#include <asm/dom_fw_domu.h>voidxen_ia64_efi_make_md(efi_memory_desc_t *md, uint32_t type, uint64_t attr, uint64_t start, uint64_t end){ md->type = type; md->pad = 0; md->phys_addr = start; md->virt_addr = 0; md->num_pages = (end - start) >> EFI_PAGE_SHIFT; md->attribute = attr;}#define EFI_HYPERCALL_PATCH(tgt, call) \ do { \ dom_efi_hypercall_patch(brkimm, \ FW_HYPERCALL_##call##_PADDR, \ FW_HYPERCALL_##call, hypercalls_imva); \ /* Descriptor address. */ \ tables->efi_runtime.tgt = \ FW_FIELD_MPA(func_ptrs) + 8 * pfn; \ /* Descriptor. */ \ tables->func_ptrs[pfn++] = FW_HYPERCALL_##call##_PADDR; \ tables->func_ptrs[pfn++] = 0; \ } while (0)/**************************************************************************Hypercall bundle creation**************************************************************************/static voidbuild_hypercall_bundle(uint64_t *imva, uint64_t brkimm, uint64_t hypnum, uint64_t ret){ INST64_A5 slot0; INST64_I19 slot1; INST64_B4 slot2; IA64_BUNDLE bundle; // slot1: mov r2 = hypnum (low 20 bits) slot0.inst = 0; slot0.qp = 0; slot0.r1 = 2; slot0.r3 = 0; slot0.major = 0x9; slot0.imm7b = hypnum; slot0.imm9d = hypnum >> 7; slot0.imm5c = hypnum >> 16; slot0.s = 0; // slot1: break brkimm slot1.inst = 0; slot1.qp = 0; slot1.x6 = 0; slot1.x3 = 0; slot1.major = 0x0; slot1.imm20 = brkimm; slot1.i = brkimm >> 20; // if ret slot2: br.ret.sptk.many rp // else slot2: br.cond.sptk.many rp slot2.inst = 0; slot2.qp = 0; slot2.p = 1; slot2.b2 = 0; slot2.wh = 0; slot2.d = 0; slot2.major = 0x0; if (ret) { slot2.btype = 4; slot2.x6 = 0x21; } else { slot2.btype = 0; slot2.x6 = 0x20; } bundle.i64[0] = 0; bundle.i64[1] = 0; bundle.template = 0x11; bundle.slot0 = slot0.inst; bundle.slot2 = slot2.inst; bundle.slot1a = slot1.inst; bundle.slot1b = slot1.inst >> 18; imva[0] = bundle.i64[0]; imva[1] = bundle.i64[1]; ia64_fc(imva); ia64_fc(imva + 1);}static voidbuild_pal_hypercall_bundles(uint64_t *imva, uint64_t brkimm, uint64_t hypnum){ extern unsigned long xen_ia64_pal_call_stub[]; IA64_BUNDLE bundle; INST64_A5 slot_a5; INST64_M37 slot_m37; /* * The source of the hypercall stub is * the xen_ia64_pal_call_stub function defined in dom_fw_asm.S. */ /* Copy the first bundle and patch the hypercall number. */ bundle.i64[0] = xen_ia64_pal_call_stub[0]; bundle.i64[1] = xen_ia64_pal_call_stub[1]; slot_a5.inst = bundle.slot0; slot_a5.imm7b = hypnum; slot_a5.imm9d = hypnum >> 7; slot_a5.imm5c = hypnum >> 16; bundle.slot0 = slot_a5.inst; imva[0] = bundle.i64[0]; imva[1] = bundle.i64[1]; ia64_fc(imva); ia64_fc(imva + 1); /* Copy the second bundle and patch the hypercall vector. */ bundle.i64[0] = xen_ia64_pal_call_stub[2]; bundle.i64[1] = xen_ia64_pal_call_stub[3]; slot_m37.inst = bundle.slot0; slot_m37.imm20a = brkimm; slot_m37.i = brkimm >> 20; bundle.slot0 = slot_m37.inst; imva[2] = bundle.i64[0]; imva[3] = bundle.i64[1]; ia64_fc(imva + 2); ia64_fc(imva + 3);}// builds a hypercall bundle at domain physical addressstatic voiddom_fpswa_hypercall_patch(uint64_t brkimm, unsigned long imva){ unsigned long *entry_imva, *patch_imva; const unsigned long entry_paddr = FW_HYPERCALL_FPSWA_ENTRY_PADDR; const unsigned long patch_paddr = FW_HYPERCALL_FPSWA_PATCH_PADDR; entry_imva = (unsigned long *)(imva + entry_paddr - FW_HYPERCALL_BASE_PADDR); patch_imva = (unsigned long *)(imva + patch_paddr - FW_HYPERCALL_BASE_PADDR); /* Descriptor. */ *entry_imva++ = patch_paddr; *entry_imva = 0; build_hypercall_bundle(patch_imva, brkimm, FW_HYPERCALL_FPSWA, 1);}// builds a hypercall bundle at domain physical addressstatic voiddom_efi_hypercall_patch(uint64_t brkimm, unsigned long paddr, unsigned long hypercall, unsigned long imva){ build_hypercall_bundle((uint64_t *)(imva + paddr - FW_HYPERCALL_BASE_PADDR), brkimm, hypercall, 1);}// builds a hypercall bundle at domain physical addressstatic voiddom_fw_hypercall_patch(uint64_t brkimm, unsigned long paddr, unsigned long hypercall,unsigned long ret, unsigned long imva){ build_hypercall_bundle((uint64_t *)(imva + paddr - FW_HYPERCALL_BASE_PADDR), brkimm, hypercall, ret);}static voiddom_fw_pal_hypercall_patch(uint64_t brkimm, unsigned long paddr, unsigned long imva){ build_pal_hypercall_bundles((uint64_t*)(imva + paddr - FW_HYPERCALL_BASE_PADDR), brkimm, FW_HYPERCALL_PAL_CALL);}static inline voidprint_md(efi_memory_desc_t *md){ uint64_t size; printk(XENLOG_INFO "dom mem: type=%2u, attr=0x%016lx, " "range=[0x%016lx-0x%016lx) ", md->type, md->attribute, md->phys_addr, md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)); size = md->num_pages << EFI_PAGE_SHIFT; if (size > ONE_MB) printk("(%luMB)\n", size >> 20); else printk("(%luKB)\n", size >> 10);}struct fake_acpi_tables { struct acpi20_table_rsdp rsdp; struct xsdt_descriptor_rev2 xsdt; uint64_t madt_ptr; struct fadt_descriptor_rev2 fadt; struct facs_descriptor_rev2 facs; struct acpi_table_header dsdt; uint8_t aml[8 + 11 * MAX_VIRT_CPUS]; struct acpi_table_madt madt; struct acpi_table_lsapic lsapic[MAX_VIRT_CPUS]; uint8_t pm1a_evt_blk[4]; uint8_t pm1a_cnt_blk[1]; uint8_t pm_tmr_blk[4];};#define ACPI_TABLE_MPA(field) \ FW_ACPI_BASE_PADDR + offsetof(struct fake_acpi_tables, field);/* Create enough of an ACPI structure to make the guest OS ACPI happy. */voiddom_fw_fake_acpi(domain_t *d, struct fake_acpi_tables *tables){ struct acpi20_table_rsdp *rsdp = &tables->rsdp; struct xsdt_descriptor_rev2 *xsdt = &tables->xsdt; struct fadt_descriptor_rev2 *fadt = &tables->fadt; struct facs_descriptor_rev2 *facs = &tables->facs; struct acpi_table_header *dsdt = &tables->dsdt; struct acpi_table_madt *madt = &tables->madt; struct acpi_table_lsapic *lsapic = tables->lsapic; int i; int aml_len; int nbr_cpus; BUILD_BUG_ON(sizeof(struct fake_acpi_tables) > (FW_ACPI_END_PADDR - FW_ACPI_BASE_PADDR)); memset(tables, 0, sizeof(struct fake_acpi_tables)); /* setup XSDT (64bit version of RSDT) */ memcpy(xsdt->signature, XSDT_SIG, sizeof(xsdt->signature)); /* XSDT points to both the FADT and the MADT, so add one entry */ xsdt->length = sizeof(struct xsdt_descriptor_rev2) + sizeof(uint64_t); xsdt->revision = 1; memcpy(xsdt->oem_id, "XEN", 3); memcpy(xsdt->oem_table_id, "Xen/ia64", 8); memcpy(xsdt->asl_compiler_id, "XEN", 3); xsdt->asl_compiler_revision = xen_ia64_version(d); xsdt->table_offset_entry[0] = ACPI_TABLE_MPA(fadt); tables->madt_ptr = ACPI_TABLE_MPA(madt); xsdt->checksum = generate_acpi_checksum(xsdt, xsdt->length); /* setup FADT */ memcpy(fadt->signature, FADT_SIG, sizeof(fadt->signature)); fadt->length = sizeof(struct fadt_descriptor_rev2); fadt->revision = FADT2_REVISION_ID; memcpy(fadt->oem_id, "XEN", 3); memcpy(fadt->oem_table_id, "Xen/ia64", 8); memcpy(fadt->asl_compiler_id, "XEN", 3); fadt->asl_compiler_revision = xen_ia64_version(d); memcpy(facs->signature, FACS_SIG, sizeof(facs->signature)); facs->version = 1; facs->length = sizeof(struct facs_descriptor_rev2); fadt->xfirmware_ctrl = ACPI_TABLE_MPA(facs); fadt->Xdsdt = ACPI_TABLE_MPA(dsdt); /* * All of the below FADT entries are filled it to prevent warnings * from sanity checks in the ACPI CA. Emulate required ACPI hardware * registers in system memory. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -