📄 boot.c
字号:
/* * boot.c - Architecture-Specific Low-Level ACPI Boot Support * * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 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 * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */#include <xen/config.h>#include <xen/errno.h>#include <xen/init.h>#include <xen/acpi.h>#include <xen/irq.h>#include <xen/dmi.h>#include <asm/fixmap.h>#include <asm/page.h>#include <asm/apic.h>#include <asm/io_apic.h>#include <asm/apic.h>#include <asm/io.h>#include <asm/mpspec.h>#include <asm/processor.h>#include <mach_apic.h>#include <mach_mpparse.h>int sbf_port;#define CONFIG_ACPI_PCI#define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ ((struct acpi_subtable_header *)entry)->length != sizeof(*entry))#define PREFIX "ACPI: "#ifdef CONFIG_ACPI_PCIint acpi_noirq __initdata; /* skip ACPI IRQ initialization */int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */#elseint acpi_noirq __initdata = 1;int acpi_pci_disabled __initdata = 1;#endifint acpi_ht __initdata = 1; /* enable HT */int acpi_lapic;int acpi_ioapic;int acpi_strict;EXPORT_SYMBOL(acpi_strict);u8 acpi_sci_flags __initdata;int acpi_sci_override_gsi __initdata;int acpi_skip_timer_override __initdata;#ifdef CONFIG_X86_LOCAL_APICstatic u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;#endifu32 acpi_smi_cmd;u8 acpi_enable_value, acpi_disable_value;#ifndef __HAVE_ARCH_CMPXCHG#warning ACPI uses CMPXCHG, i486 and later hardware#endif#define MAX_MADT_ENTRIES 256u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = {[0 ... MAX_MADT_ENTRIES - 1] = 0xff };EXPORT_SYMBOL(x86_acpiid_to_apicid);/* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- *//* * The default interrupt routing model is PIC (8259). This gets * overriden if IOAPICs are enumerated (below). */enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;/* * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, * to map the target physical address. The problem is that set_fixmap() * provides a single page, and it is possible that the page is not * sufficient. * By using this area, we can map up to MAX_IO_APICS pages temporarily, * i.e. until the next __va_range() call. * * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and * count idx down while incrementing the phys address. */char *__acpi_map_table(unsigned long phys, unsigned long size){ unsigned long base, offset, mapped_size; int idx; /* XEN: RAM holes above 1MB are not permanently mapped. */ if ((phys + size) <= (1 * 1024 * 1024)) return __va(phys); offset = phys & (PAGE_SIZE - 1); mapped_size = PAGE_SIZE - offset; set_fixmap(FIX_ACPI_END, phys); base = fix_to_virt(FIX_ACPI_END); /* * Most cases can be covered by the below. */ idx = FIX_ACPI_END; while (mapped_size < size) { if (--idx < FIX_ACPI_BEGIN) return NULL; /* cannot handle this */ phys += PAGE_SIZE; set_fixmap(idx, phys); mapped_size += PAGE_SIZE; } return ((char *) base + offset);}#ifdef CONFIG_X86_LOCAL_APICstatic int __init acpi_parse_madt(struct acpi_table_header *table){ struct acpi_table_madt *madt; madt = (struct acpi_table_madt *)table; if (madt->address) { acpi_lapic_addr = (u64) madt->address; printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", madt->address); } acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); return 0;}static int __initacpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_lapic *processor = NULL; processor = (struct acpi_table_lapic *)header; if (BAD_MADT_ENTRY(processor, end)) return -EINVAL; acpi_table_print_madt_entry(header); /* Record local apic id only when enabled */ if (processor->flags.enabled) x86_acpiid_to_apicid[processor->acpi_id] = processor->id; /* * We need to register disabled CPU as well to permit * counting disabled CPUs. This allows us to size * cpus_possible_map more accurately, to permit * to not preallocating memory for all NR_CPUS * when we use CPU hotplug. */ mp_register_lapic(processor->id, /* APIC ID */ processor->flags.enabled); /* Enabled? */ return 0;}static int __initacpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header; if (BAD_MADT_ENTRY(lapic_addr_ovr, end)) return -EINVAL; acpi_lapic_addr = lapic_addr_ovr->address; return 0;}static int __initacpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_lapic_nmi *lapic_nmi = NULL; lapic_nmi = (struct acpi_table_lapic_nmi *)header; if (BAD_MADT_ENTRY(lapic_nmi, end)) return -EINVAL; acpi_table_print_madt_entry(header); if (lapic_nmi->lint != 1) printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); return 0;}#endif /*CONFIG_X86_LOCAL_APIC */#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/static int __initacpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_ioapic *ioapic = NULL; ioapic = (struct acpi_table_ioapic *)header; if (BAD_MADT_ENTRY(ioapic, end)) return -EINVAL; acpi_table_print_madt_entry(header); mp_register_ioapic(ioapic->id, ioapic->address, ioapic->global_irq_base); return 0;}static int __initacpi_parse_int_src_ovr(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_int_src_ovr *intsrc = NULL; intsrc = (struct acpi_table_int_src_ovr *)header; if (BAD_MADT_ENTRY(intsrc, end)) return -EINVAL; acpi_table_print_madt_entry(header); if (acpi_skip_timer_override && intsrc->bus_irq == 0 && intsrc->global_irq == 2) { printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); return 0; } mp_override_legacy_irq(intsrc->bus_irq, intsrc->flags.polarity, intsrc->flags.trigger, intsrc->global_irq); return 0;}static int __initacpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end){ struct acpi_table_nmi_src *nmi_src = NULL; nmi_src = (struct acpi_table_nmi_src *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; acpi_table_print_madt_entry(header); /* TBD: Support nimsrc entries? */ return 0;}#endif /* CONFIG_X86_IO_APIC */static unsigned long __initacpi_scan_rsdp(unsigned long start, unsigned long length){ unsigned long offset = 0; unsigned long sig_len = sizeof("RSD PTR ") - 1; /* * Scan all 16-byte boundaries of the physical memory region for the * RSDP signature. */ for (offset = 0; offset < length; offset += 16) { if (strncmp((char *)(start + offset), "RSD PTR ", sig_len)) continue; return (start + offset); } return 0;}static int __init acpi_parse_sbf(struct acpi_table_header *table){ struct acpi_table_boot *sb; sb = (struct acpi_table_boot *)table; if (!sb) { printk(KERN_WARNING PREFIX "Unable to map SBF\n"); return -ENODEV; } sbf_port = sb->cmos_index; /* Save CMOS port */ return 0;}#ifdef CONFIG_HPET_TIMERstatic int __init acpi_parse_hpet(struct acpi_table_header *table){ struct acpi_table_hpet *hpet_tbl = (struct acpi_table_hpet *)table; if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) { printk(KERN_WARNING PREFIX "HPET timers must be located in " "memory.\n"); return -1; }#if 0/*def CONFIG_X86_64*/ vxtime.hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", hpet_tbl->id, vxtime.hpet_address);#else /* X86 */ { extern unsigned long hpet_address; hpet_address = hpet_tbl->address.address; printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet_address); }#endif /* X86 */ return 0;}#else#define acpi_parse_hpet NULL#endif#ifdef CONFIG_X86_PM_TIMERextern u32 pmtmr_ioport;#endif#ifdef CONFIG_ACPI_SLEEP#define acpi_fadt_copy_address(dst, src, len) do { \ if (fadt->header.revision >= FADT2_REVISION_ID) \ acpi_sinfo.dst##_blk = fadt->x##src##_block; \ if (!acpi_sinfo.dst##_blk.address) { \ acpi_sinfo.dst##_blk.address = fadt->src##_block; \ acpi_sinfo.dst##_blk.space_id = ACPI_ADR_SPACE_SYSTEM_IO; \ acpi_sinfo.dst##_blk.bit_width = fadt->len##_length << 3; \ acpi_sinfo.dst##_blk.bit_offset = 0; \ acpi_sinfo.dst##_blk.access_width = 0; \ } \} while (0)/* Get pm1x_cnt and pm1x_evt information for ACPI sleep */static void __initacpi_fadt_parse_sleep_info(struct acpi_table_fadt *fadt){ struct acpi_table_rsdp *rsdp; unsigned long rsdp_phys; struct acpi_table_facs *facs = NULL; uint64_t facs_pa; rsdp_phys = acpi_find_rsdp(); if (!rsdp_phys || acpi_disabled) goto bad; rsdp = __va(rsdp_phys); acpi_fadt_copy_address(pm1a_cnt, pm1a_control, pm1_control); acpi_fadt_copy_address(pm1b_cnt, pm1b_control, pm1_control); acpi_fadt_copy_address(pm1a_evt, pm1a_event, pm1_event); acpi_fadt_copy_address(pm1b_evt, pm1b_event, pm1_event); printk(KERN_INFO PREFIX "ACPI SLEEP INFO: pm1x_cnt[%"PRIx64",%"PRIx64"], " "pm1x_evt[%"PRIx64",%"PRIx64"]\n", acpi_sinfo.pm1a_cnt_blk.address, acpi_sinfo.pm1b_cnt_blk.address, acpi_sinfo.pm1a_evt_blk.address, acpi_sinfo.pm1b_evt_blk.address); /* Now FACS... */ if (fadt->header.revision >= FADT2_REVISION_ID) facs_pa = fadt->Xfacs; else facs_pa = (uint64_t)fadt->facs; facs = (struct acpi_table_facs *) __acpi_map_table(facs_pa, sizeof(struct acpi_table_facs)); if (!facs) goto bad; if (strncmp(facs->signature, "FACS", 4)) { printk(KERN_ERR PREFIX "Invalid FACS signature %.4s\n", facs->signature); goto bad; } if (facs->length < 24) { printk(KERN_ERR PREFIX "Invalid FACS table length: 0x%x", facs->length); goto bad; } if (facs->length < 64) printk(KERN_WARNING PREFIX "FACS is shorter than ACPI spec allow: 0x%x", facs->length); acpi_sinfo.wakeup_vector = facs_pa + offsetof(struct acpi_table_facs, firmware_waking_vector); acpi_sinfo.vector_width = 32; printk(KERN_INFO PREFIX " wakeup_vec[%"PRIx64"], vec_size[%x]\n", acpi_sinfo.wakeup_vector, acpi_sinfo.vector_width); return;bad: memset(&acpi_sinfo, 0, sizeof(acpi_sinfo));}#endifstatic int __init acpi_parse_fadt(struct acpi_table_header *table){ struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table;#ifdef CONFIG_ACPI_INTERPRETER /* initialize sci_int early for INT_SRC_OVR MADT parsing */ acpi_fadt.sci_int = fadt->sci_int; /* initialize rev and apic_phys_dest_mode for x86_64 genapic */ acpi_fadt.revision = fadt->revision; acpi_fadt.force_apic_physical_destination_mode = fadt->force_apic_physical_destination_mode;#endif#ifdef CONFIG_X86_PM_TIMER /* detect the location of the ACPI PM Timer */ if (fadt->header.revision >= FADT2_REVISION_ID) { /* FADT rev. 2 */ if (fadt->xpm_timer_block.space_id == ACPI_ADR_SPACE_SYSTEM_IO) pmtmr_ioport = fadt->xpm_timer_block.address; /* * "X" fields are optional extensions to the original V1.0 * fields, so we must selectively expand V1.0 fields if the * corresponding X field is zero. */ if (!pmtmr_ioport) pmtmr_ioport = fadt->pm_timer_block; } else { /* FADT rev. 1 */ pmtmr_ioport = fadt->pm_timer_block; } if (pmtmr_ioport) printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport);#endif acpi_smi_cmd = fadt->smi_command; acpi_enable_value = fadt->acpi_enable; acpi_disable_value = fadt->acpi_disable;#ifdef CONFIG_ACPI_SLEEP acpi_fadt_parse_sleep_info(fadt);#endif return 0;}unsigned long __init acpi_find_rsdp(void){ unsigned long rsdp_phys = 0;#if 0 if (efi_enabled) { if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) return efi.acpi20; else if (efi.acpi != EFI_INVALID_TABLE_ADDR) return efi.acpi; }#endif /* * Scan memory looking for the RSDP signature. First search EBDA (low * memory) paragraphs and then search upper memory (E0000-FFFFF). */ rsdp_phys = acpi_scan_rsdp(0, 0x400); if (!rsdp_phys)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -