⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dom_fw_dom0.c

📁 xen 3.2.2 源码
💻 C
字号:
/****************************************************************************** * * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp> *                    VA Linux Systems Japan K.K. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *//* *  Xen domain firmware emulation support *  Copyright (C) 2004 Hewlett-Packard Co. *       Dan Magenheimer (dan.magenheimer@hp.com) */#include <xen/config.h>#include <xen/acpi.h>#include <xen/errno.h>#include <xen/sched.h>#include <xen/list.h>#include <asm/dom_fw.h>#include <asm/dom_fw_common.h>#include <asm/dom_fw_dom0.h>#include <asm/dom_fw_utils.h>#include <linux/sort.h>struct acpi_backup_table_entry {	struct list_head list;	unsigned long pa;	unsigned long size;	unsigned char data[0];};static LIST_HEAD(acpi_backup_table_list);static u32 lsapic_nbr;/* Modify lsapic table.  Provides LPs.  */static int __initacpi_update_lsapic(acpi_table_entry_header * header, const unsigned long end){	struct acpi_table_lsapic *lsapic;	int enable;	lsapic = (struct acpi_table_lsapic *)header;	if (!lsapic)		return -EINVAL;	if (lsapic_nbr < MAX_VIRT_CPUS && dom0->vcpu[lsapic_nbr] != NULL)		enable = 1;	else		enable = 0;	if (lsapic->flags.enabled && enable) {		printk("enable lsapic entry: 0x%lx\n", (u64) lsapic);		lsapic->id = lsapic_nbr;		lsapic->eid = 0;		lsapic_nbr++;	} else if (lsapic->flags.enabled) {		printk("DISABLE lsapic entry: 0x%lx\n", (u64) lsapic);		lsapic->flags.enabled = 0;		lsapic->id = 0;		lsapic->eid = 0;	}	return 0;}static int __initacpi_patch_plat_int_src(acpi_table_entry_header * header,			const unsigned long end){	struct acpi_table_plat_int_src *plintsrc;	plintsrc = (struct acpi_table_plat_int_src *)header;	if (!plintsrc)		return -EINVAL;	if (plintsrc->type == ACPI_INTERRUPT_CPEI) {		printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n");		plintsrc->type = -1;	}	return 0;}static int __initacpi_update_madt_checksum(unsigned long phys_addr, unsigned long size){	struct acpi_table_madt *acpi_madt;	if (!phys_addr || !size)		return -EINVAL;	acpi_madt = (struct acpi_table_madt *)__va(phys_addr);	acpi_madt->header.checksum = 0;	acpi_madt->header.checksum = generate_acpi_checksum(acpi_madt, size);	return 0;}static int __initacpi_backup_table(unsigned long phys_addr, unsigned long size){	struct acpi_backup_table_entry *entry;	void *vaddr = __va(phys_addr);	if (!phys_addr || !size)		return -EINVAL;	entry = xmalloc_bytes(sizeof(*entry) + size);	if (!entry) {		dprintk(XENLOG_WARNING, "Failed to allocate memory for "		        "%.4s table backup\n",			((struct acpi_table_header *)vaddr)->signature);		return -ENOMEM;	}	entry->pa = phys_addr;	entry->size = size;	memcpy(entry->data, vaddr, size);	list_add(&entry->list, &acpi_backup_table_list);	printk(XENLOG_INFO "Backup %.4s table stored @0x%p\n",	       ((struct acpi_table_header *)entry->data)->signature,	       entry->data);	return 0;}voidacpi_restore_tables(){	struct acpi_backup_table_entry *entry;	list_for_each_entry(entry, &acpi_backup_table_list, list) {		printk(XENLOG_INFO "Restoring backup %.4s table @0x%p\n",		       ((struct acpi_table_header *)entry->data)->signature,		       entry->data);		memcpy(__va(entry->pa), entry->data, entry->size);		/* Only called from kexec path, no need to free entries */	}}/* base is physical address of acpi table */static void __init touch_acpi_table(void){	int result;	lsapic_nbr = 0;	/*	 * Modify dom0 MADT:	 *  - Disable CPUs that would exceed max vCPUs for the domain	 *  - Virtualize id/eid for indexing into domain vCPU array	 *  - Hide CPEI interrupt source	 *	 * ACPI tables must be backed-up before modification!	 */	acpi_table_parse(ACPI_APIC, acpi_backup_table);	if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0)		printk("Error parsing MADT - no LAPIC entries\n");	if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC,				  acpi_patch_plat_int_src, 0) < 0)		printk("Error parsing MADT - no PLAT_INT_SRC entries\n");	acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum);	/*	 * SRAT & SLIT tables aren't useful for Dom0 until	 * we support more NUMA configuration information in Xen.	 *	 * NB - backup ACPI tables first.	 */	acpi_table_parse(ACPI_SRAT, acpi_backup_table);	acpi_table_parse(ACPI_SLIT, acpi_backup_table);	result = acpi_table_disable(ACPI_SRAT);	if ( result == 0 )		printk("Success Disabling SRAT\n");	else if ( result != -ENOENT )		printk("ERROR: Failed Disabling SRAT\n");	result = acpi_table_disable(ACPI_SLIT);	if ( result == 0 )		printk("Success Disabling SLIT\n");	else if ( result != -ENOENT )		printk("ERROR: Failed Disabling SLIT\n");	return;}void __init efi_systable_init_dom0(struct fw_tables *tables){	int i = 1;	touch_acpi_table();	/* Write messages to the console.  */	printk("Domain0 EFI passthrough:");	if (efi.mps) {		tables->efi_tables[i].guid = MPS_TABLE_GUID;		tables->efi_tables[i].table = __pa(efi.mps);		printk(" MPS=0x%lx", tables->efi_tables[i].table);		i++;	}	if (efi.acpi20) {		tables->efi_tables[i].guid = ACPI_20_TABLE_GUID;		tables->efi_tables[i].table = __pa(efi.acpi20);		printk(" ACPI 2.0=0x%lx", tables->efi_tables[i].table);		i++;	}	if (efi.acpi) {		tables->efi_tables[i].guid = ACPI_TABLE_GUID;		tables->efi_tables[i].table = __pa(efi.acpi);		printk(" ACPI=0x%lx", tables->efi_tables[i].table);		i++;	}	if (efi.smbios) {		tables->efi_tables[i].guid = SMBIOS_TABLE_GUID;		tables->efi_tables[i].table = __pa(efi.smbios);		printk(" SMBIOS=0x%lx", tables->efi_tables[i].table);		i++;	}	if (efi.hcdp) {		tables->efi_tables[i].guid = HCDP_TABLE_GUID;		tables->efi_tables[i].table = __pa(efi.hcdp);		printk(" HCDP=0x%lx", tables->efi_tables[i].table);		i++;	}	printk("\n");	BUG_ON(i > NUM_EFI_SYS_TABLES);}static void __initsetup_dom0_memmap_info(struct domain *d, struct fw_tables *tables){	int i;	size_t size;	unsigned int num_pages;	efi_memory_desc_t *md;	efi_memory_desc_t *last_mem_md = NULL;	xen_ia64_memmap_info_t *memmap_info;	unsigned long paddr_start;	unsigned long paddr_end;	size = sizeof(*memmap_info) +		(tables->num_mds + 1) * sizeof(tables->efi_memmap[0]);	num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;	for (i = tables->num_mds - 1; i >= 0; i--) {		md = &tables->efi_memmap[i];		if (md->attribute == EFI_MEMORY_WB &&		    md->type == EFI_CONVENTIONAL_MEMORY &&		    md->num_pages >		    ((num_pages + 1) << (PAGE_SHIFT - EFI_PAGE_SHIFT))) {			last_mem_md = md;			break;		}	}	if (last_mem_md == NULL) {		printk("%s: warning: "		       "no dom0 contiguous memory to hold memory map\n",		       __func__);		return;	}	paddr_end = last_mem_md->phys_addr +	    (last_mem_md->num_pages << EFI_PAGE_SHIFT);	paddr_start = (paddr_end - (num_pages << PAGE_SHIFT)) & PAGE_MASK;	last_mem_md->num_pages -= (paddr_end - paddr_start) >> EFI_PAGE_SHIFT;	md = &tables->efi_memmap[tables->num_mds];	tables->num_mds++;	md->type = EFI_RUNTIME_SERVICES_DATA;	md->phys_addr = paddr_start;	md->virt_addr = 0;	md->num_pages = num_pages << (PAGE_SHIFT - EFI_PAGE_SHIFT);	md->attribute = EFI_MEMORY_WB;	BUG_ON(tables->fw_tables_size <	       sizeof(*tables) +	       sizeof(tables->efi_memmap[0]) * tables->num_mds);	/* with this sort, md doesn't point memmap table */	sort(tables->efi_memmap, tables->num_mds,	     sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL);	memmap_info = domain_mpa_to_imva(d, paddr_start);	memmap_info->efi_memdesc_size = sizeof(md[0]);	memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION;	memmap_info->efi_memmap_size = tables->num_mds * sizeof(md[0]);	dom_fw_copy_to(d,		       paddr_start + offsetof(xen_ia64_memmap_info_t, memdesc),		       &tables->efi_memmap[0], memmap_info->efi_memmap_size);	d->shared_info->arch.memmap_info_num_pages = num_pages;	d->shared_info->arch.memmap_info_pfn = paddr_start >> PAGE_SHIFT;}/* setup_guest() @ libxc/xc_linux_build() arranges memory for domU. * however no one arranges memory for dom0, * instead we allocate pages manually. */static voidassign_new_domain0_range(struct domain *d, const efi_memory_desc_t * md){	if (md->type == EFI_PAL_CODE ||	    md->type == EFI_RUNTIME_SERVICES_DATA ||	    md->type == EFI_CONVENTIONAL_MEMORY) {		unsigned long start = md->phys_addr & PAGE_MASK;		unsigned long end =			md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);		unsigned long addr;		if (end == start) {			/* md->num_pages = 0 is allowed. */			return;		}		for (addr = start; addr < end; addr += PAGE_SIZE)			assign_new_domain0_page(d, addr);	}}/* Complete the dom0 memmap.  */int __initcomplete_dom0_memmap(struct domain *d, struct fw_tables *tables){	u64 addr;	void *efi_map_start, *efi_map_end, *p;	u64 efi_desc_size;	int i;	for (i = 0; i < tables->num_mds; i++)		assign_new_domain0_range(d, &tables->efi_memmap[i]);	/* Walk through all MDT entries.	   Copy all interesting entries.  */	efi_map_start = __va(ia64_boot_param->efi_memmap);	efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;	efi_desc_size = ia64_boot_param->efi_memdesc_size;	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {		const efi_memory_desc_t *md = p;		efi_memory_desc_t *dom_md = &tables->efi_memmap[tables->num_mds];		u64 start = md->phys_addr;		u64 size = md->num_pages << EFI_PAGE_SHIFT;		u64 end = start + size;		u64 mpaddr;		unsigned long flags;		switch (md->type) {		case EFI_RUNTIME_SERVICES_CODE:		case EFI_RUNTIME_SERVICES_DATA:		case EFI_ACPI_RECLAIM_MEMORY:		case EFI_ACPI_MEMORY_NVS:		case EFI_RESERVED_TYPE:			/*			 * Map into dom0 - We must respect protection			 * and cache attributes.  Not all of these pages			 * are writable!!!			 */			flags = ASSIGN_writable;	/* dummy - zero */			if (md->attribute & EFI_MEMORY_WP)				flags |= ASSIGN_readonly;			if ((md->attribute & EFI_MEMORY_UC) &&			    !(md->attribute & EFI_MEMORY_WB))				flags |= ASSIGN_nocache;			assign_domain_mach_page(d, start, size, flags);			/* Fall-through.  */		case EFI_MEMORY_MAPPED_IO:			/* Will be mapped with ioremap.  */			/* Copy descriptor.  */			*dom_md = *md;			dom_md->virt_addr = 0;			tables->num_mds++;			break;		case EFI_MEMORY_MAPPED_IO_PORT_SPACE:			flags = ASSIGN_writable;	/* dummy - zero */			if (md->attribute & EFI_MEMORY_UC)				flags |= ASSIGN_nocache;			if (start > 0x1ffffffff0000000UL) {				mpaddr = 0x4000000000000UL - size;				printk(XENLOG_INFO "Remapping IO ports from "				       "%lx to %lx\n", start, mpaddr);			} else				mpaddr = start;			/* Map into dom0.  */			assign_domain_mmio_page(d, mpaddr, start, size, flags);			/* Copy descriptor.  */			*dom_md = *md;			dom_md->phys_addr = mpaddr;			dom_md->virt_addr = 0;			tables->num_mds++;			break;		case EFI_CONVENTIONAL_MEMORY:		case EFI_LOADER_CODE:		case EFI_LOADER_DATA:		case EFI_BOOT_SERVICES_CODE:		case EFI_BOOT_SERVICES_DATA: {			u64 dom_md_start;			u64 dom_md_end;			unsigned long left_mem =				(unsigned long)(d->max_pages - d->tot_pages) <<				PAGE_SHIFT;			if (!(md->attribute & EFI_MEMORY_WB))				break;			dom_md_start = max(tables->fw_end_paddr, start);			dom_md_end = dom_md_start;			do {				dom_md_end = min(dom_md_end + left_mem, end);				if (dom_md_end < dom_md_start + PAGE_SIZE)					break;				dom_md->type = EFI_CONVENTIONAL_MEMORY;				dom_md->phys_addr = dom_md_start;				dom_md->virt_addr = 0;				dom_md->num_pages =					(dom_md_end - dom_md_start) >>					EFI_PAGE_SHIFT;				dom_md->attribute = EFI_MEMORY_WB;				assign_new_domain0_range(d, dom_md);				/*				 * recalculate left_mem.				 * we might already allocated memory in				 * this region because of kernel loader.				 * So we might consumed less than				 * (dom_md_end - dom_md_start) above.				 */				left_mem = (unsigned long)					(d->max_pages - d->tot_pages) <<					PAGE_SHIFT;			} while (left_mem > 0 && dom_md_end < end);			if (!(dom_md_end < dom_md_start + PAGE_SIZE))				tables->num_mds++;			break;		}		case EFI_UNUSABLE_MEMORY:		case EFI_PAL_CODE:			/*			 * We don't really need these, but holes in the			 * memory map may cause Linux to assume there are			 * uncacheable ranges within a granule.			 */			dom_md->type = EFI_UNUSABLE_MEMORY;			dom_md->phys_addr = start;			dom_md->virt_addr = 0;			dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT;			dom_md->attribute = EFI_MEMORY_WB;			tables->num_mds++;			break;		default:			/* Print a warning but continue.  */			printk("complete_dom0_memmap: warning: "			       "unhandled MDT entry type %u\n", md->type);		}	}	BUG_ON(tables->fw_tables_size <	       sizeof(*tables) +	       sizeof(tables->efi_memmap[0]) * tables->num_mds);	sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t),	     efi_mdt_cmp, NULL);	// Map low-memory holes & unmapped MMIO for legacy drivers	for (addr = 0; addr < ONE_MB; addr += PAGE_SIZE) {		if (domain_page_mapped(d, addr))			continue;		if (efi_mmio(addr, PAGE_SIZE)) {			unsigned long flags;			flags = ASSIGN_writable | ASSIGN_nocache;			assign_domain_mmio_page(d, addr, addr, PAGE_SIZE,						flags);		}	}	setup_dom0_memmap_info(d, tables);	return tables->num_mds;}/* * Local variables: * mode: C * c-set-style: "linux" * c-basic-offset: 8 * tab-width: 8 * indent-tabs-mode: t * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -