📄 efi.c
字号:
#ifdef XENstatic void__efi_unmap_pal_code (void *pal_vaddr){ ia64_ptr(0x1, GRANULEROUNDDOWN((unsigned long)pal_vaddr), IA64_GRANULE_SHIFT);}voidefi_unmap_pal_code (void){ void *pal_vaddr = efi_get_pal_addr (); u64 psr; if (!pal_vaddr) return; /* * Cannot write to CRx with PSR.ic=1 */ psr = ia64_clear_ic(); __efi_unmap_pal_code(pal_vaddr); ia64_set_psr(psr); /* restore psr */ ia64_srlz_i();}#endifvoidefi_map_pal_code (void){ void *pal_vaddr = efi_get_pal_addr (); u64 psr; if (!pal_vaddr) return; /* * Cannot write to CRx with PSR.ic=1 */ psr = ia64_clear_ic();#ifdef XEN /* pal_vaddr must be unpinned before pinning * This is needed in the case of a nested EFI, PAL or SAL call */ __efi_unmap_pal_code(pal_vaddr);#endif ia64_itr(0x1, IA64_TR_PALCODE, GRANULEROUNDDOWN((unsigned long) pal_vaddr), pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)), IA64_GRANULE_SHIFT); ia64_set_psr(psr); /* restore psr */ ia64_srlz_i();}void __initefi_init (void){ void *efi_map_start, *efi_map_end; efi_config_table_t *config_tables; efi_char16_t *c16; u64 efi_desc_size; char *cp, vendor[100] = "unknown"; int i; /* it's too early to be able to use the standard kernel command line support... */#ifdef XEN extern char saved_command_line[]; for (cp = saved_command_line; *cp; ) {#else for (cp = boot_command_line; *cp; ) {#endif if (memcmp(cp, "mem=", 4) == 0) { mem_limit = memparse(cp + 4, &cp); } else if (memcmp(cp, "max_addr=", 9) == 0) { max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); } else if (memcmp(cp, "min_addr=", 9) == 0) { min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); } else { while (*cp != ' ' && *cp) ++cp; while (*cp == ' ') ++cp; } } if (min_addr != 0UL) printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20); if (max_addr != ~0UL) printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20); efi.systab = __va(ia64_boot_param->efi_systab); /* * Verify the EFI Table */ if (efi.systab == NULL) panic("Woah! Can't find EFI system table.\n"); if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) panic("Woah! EFI system table signature incorrect\n"); if ((efi.systab->hdr.revision >> 16) == 0) printk(KERN_WARNING "Warning: EFI system table version " "%d.%02d, expected 1.00 or greater\n", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff); config_tables = __va(efi.systab->tables); /* Show what we know for posterity */ c16 = __va(efi.systab->fw_vendor); if (c16) { for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i) vendor[i] = *c16++; vendor[i] = '\0'; } printk(KERN_INFO "EFI v%u.%.02u by %s:", efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor); efi.mps = EFI_INVALID_TABLE_ADDR; efi.acpi = EFI_INVALID_TABLE_ADDR; efi.acpi20 = EFI_INVALID_TABLE_ADDR; efi.smbios = EFI_INVALID_TABLE_ADDR; efi.sal_systab = EFI_INVALID_TABLE_ADDR; efi.boot_info = EFI_INVALID_TABLE_ADDR; efi.hcdp = EFI_INVALID_TABLE_ADDR; efi.uga = EFI_INVALID_TABLE_ADDR; for (i = 0; i < (int) efi.systab->nr_tables; i++) { if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { efi.mps = config_tables[i].table; printk(" MPS=0x%lx", config_tables[i].table); } else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) { efi.acpi20 = config_tables[i].table; printk(" ACPI 2.0=0x%lx", config_tables[i].table); } else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) { efi.acpi = config_tables[i].table; printk(" ACPI=0x%lx", config_tables[i].table); } else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) { efi.smbios = config_tables[i].table; printk(" SMBIOS=0x%lx", config_tables[i].table); } else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) { efi.sal_systab = config_tables[i].table; printk(" SALsystab=0x%lx", config_tables[i].table); } else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { efi.hcdp = config_tables[i].table; printk(" HCDP=0x%lx", config_tables[i].table); } } printk("\n"); runtime = __va(efi.systab->runtime); efi.get_time = phys_get_time; efi.set_time = phys_set_time; efi.get_wakeup_time = phys_get_wakeup_time; efi.set_wakeup_time = phys_set_wakeup_time; efi.get_variable = phys_get_variable; efi.get_next_variable = phys_get_next_variable; efi.set_variable = phys_set_variable; efi.get_next_high_mono_count = phys_get_next_high_mono_count; efi.reset_system = phys_reset_system; 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;#if EFI_DEBUG /* print EFI memory map: */ { efi_memory_desc_t *md; void *p; for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { md = p; printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", i, md->type, md->attribute, md->phys_addr, md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), md->num_pages >> (20 - EFI_PAGE_SHIFT)); } }#endif#ifndef XEN efi_map_pal_code();#endif efi_enter_virtual_mode();}voidefi_enter_virtual_mode (void){ void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; efi_status_t status; u64 efi_desc_size; 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) { md = p;#ifdef XEN if (md->attribute & EFI_MEMORY_RUNTIME) { if (md->attribute & EFI_MEMORY_WB) md->virt_addr = __IA64_EFI_CACHED_OFFSET| md->phys_addr; else if (md->attribute & (EFI_MEMORY_UC|EFI_MEMORY_WC| EFI_MEMORY_WT)) md->virt_addr = __IA64_EFI_UNCACHED_OFFSET| md->phys_addr; }#else if (md->attribute & EFI_MEMORY_RUNTIME) { /* * Some descriptors have multiple bits set, so the order of * the tests is relevant. */ if (md->attribute & EFI_MEMORY_WB) { md->virt_addr = (u64) __va(md->phys_addr); } else if (md->attribute & EFI_MEMORY_UC) { md->virt_addr = (u64) ioremap(md->phys_addr, 0); } else if (md->attribute & EFI_MEMORY_WC) {#if 0 md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WC | _PAGE_PL_0 | _PAGE_AR_RW));#else printk(KERN_INFO "EFI_MEMORY_WC mapping\n"); md->virt_addr = (u64) ioremap(md->phys_addr, 0);#endif } else if (md->attribute & EFI_MEMORY_WT) {#if 0 md->virt_addr = ia64_remap(md->phys_addr, (_PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WT | _PAGE_PL_0 | _PAGE_AR_RW));#else printk(KERN_INFO "EFI_MEMORY_WT mapping\n"); md->virt_addr = (u64) ioremap(md->phys_addr, 0);#endif } }#endif } status = efi_call_phys(__va(runtime->set_virtual_address_map), ia64_boot_param->efi_memmap_size, efi_desc_size, ia64_boot_param->efi_memdesc_version, ia64_boot_param->efi_memmap); if (status != EFI_SUCCESS) { printk(KERN_WARNING "warning: unable to switch EFI into virtual mode " "(status=%lu)\n", status); return; } /* * Now that EFI is in virtual mode, we call the EFI functions more efficiently: */ efi.get_time = virt_get_time; efi.set_time = virt_set_time; efi.get_wakeup_time = virt_get_wakeup_time; efi.set_wakeup_time = virt_set_wakeup_time; efi.get_variable = virt_get_variable; efi.get_next_variable = virt_get_next_variable; efi.set_variable = virt_set_variable; efi.get_next_high_mono_count = virt_get_next_high_mono_count; efi.reset_system = virt_reset_system;}/* * Walk the EFI memory map looking for the I/O port range. There can only be one entry of * this type, other I/O port ranges should be described via ACPI. */u64efi_get_iobase (void){ void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; u64 efi_desc_size; 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) { md = p; if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) { if (md->attribute & EFI_MEMORY_UC) return md->phys_addr; } } return 0;}static struct kern_memdesc *kern_memory_descriptor (unsigned long phys_addr){ struct kern_memdesc *md; for (md = kern_memmap; md->start != ~0UL; md++) { if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT)) return md; } return NULL;}static efi_memory_desc_t *efi_memory_descriptor (unsigned long phys_addr){ void *efi_map_start, *efi_map_end, *p; efi_memory_desc_t *md; u64 efi_desc_size; 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) { md = p; if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) return md; } return NULL;}u32efi_mem_type (unsigned long phys_addr){ efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); if (md) return md->type; return 0;}u64efi_mem_attributes (unsigned long phys_addr){ efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); if (md) return md->attribute; return 0;}EXPORT_SYMBOL(efi_mem_attributes);u64efi_mem_attribute (unsigned long phys_addr, unsigned long size){ unsigned long end = phys_addr + size; efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); u64 attr; if (!md) return 0; /* * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells * the kernel that firmware needs this region mapped. */ attr = md->attribute & ~EFI_MEMORY_RUNTIME; do { unsigned long md_end = efi_md_end(md); if (end <= md_end) return attr; md = efi_memory_descriptor(md_end); if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr) return 0; } while (md); return 0;}u64kern_mem_attribute (unsigned long phys_addr, unsigned long size){ unsigned long end = phys_addr + size; struct kern_memdesc *md; u64 attr; /* * This is a hack for ioremap calls before we set up kern_memmap. * Maybe we should do efi_memmap_init() earlier instead. */ if (!kern_memmap) { attr = efi_mem_attribute(phys_addr, size); if (attr & EFI_MEMORY_WB) return EFI_MEMORY_WB; return 0; } md = kern_memory_descriptor(phys_addr); if (!md) return 0; attr = md->attribute; do { unsigned long md_end = kmd_end(md); if (end <= md_end) return attr; md = kern_memory_descriptor(md_end); if (!md || md->attribute != attr) return 0; } while (md); return 0;}EXPORT_SYMBOL(kern_mem_attribute);#ifndef XENintvalid_phys_addr_range (unsigned long phys_addr, unsigned long size){ u64 attr; /* * /dev/mem reads and writes use copy_to_user(), which implicitly * uses a granule-sized kernel identity mapping. It's really * only safe to do this for regions in kern_memmap. For more * details, see Documentation/ia64/aliasing.txt. */ attr = kern_mem_attribute(phys_addr, size); if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) return 1; return 0;}intvalid_mmap_phys_addr_range (unsigned long pfn, unsigned long size){ /* * MMIO regions are often missing from the EFI memory map. * We must allow mmap of them for programs like X, so we * currently can't do any useful validation. */ return 1;}pgprot_tphys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot){ unsigned long phys_addr = pfn << PAGE_SHIFT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -