Move the global variables and functions that can be moved as-is from the common boot.c file to the x86 implementation header file.
Signed-off-by: Roy Franz roy.franz@linaro.org --- xen/common/efi/boot.c | 460 ++--------------------------------------- xen/include/asm-x86/efi-boot.h | 455 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 468 insertions(+), 447 deletions(-) create mode 100644 xen/include/asm-x86/efi-boot.h
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 14e2f46..ca604be 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -18,16 +18,6 @@ #include <xen/string.h> #include <xen/stringify.h> #include <xen/vga.h> -#include <asm/e820.h> -#include <asm/edd.h> -#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ -#include <asm/fixmap.h> -#undef __ASSEMBLY__ -#include <asm/msr.h> -#include <asm/processor.h> - -/* Using SetVirtualAddressMap() is incompatible with kexec: */ -#undef USE_SET_VIRTUAL_ADDRESS_MAP
#define SHIM_LOCK_PROTOCOL_GUID \ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } @@ -41,8 +31,10 @@ typedef struct { EFI_SHIM_LOCK_VERIFY Verify; } EFI_SHIM_LOCK_PROTOCOL;
-extern char start[]; -extern u32 cpuid_ext_features; +static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer); +static CHAR16 *__init FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer); +static void __init DisplayUint(UINT64 Val, INTN Width); +static CHAR16 *__init wstrcpy(CHAR16 *d, const CHAR16 *s);
union string { CHAR16 *w; @@ -69,19 +61,18 @@ static UINT32 __initdata mdesc_ver; static struct file __initdata cfg; static struct file __initdata kernel; static struct file __initdata ramdisk; -static struct file __initdata ucode; static struct file __initdata xsm; - -static multiboot_info_t __initdata mbi = { - .flags = MBI_MODULES | MBI_LOADERNAME -}; -static module_t __initdata mb_modules[3]; - static CHAR16 __initdata newline[] = L"\r\n";
#define PrintStr(s) StdOut->OutputString(StdOut, s) #define PrintErr(s) StdErr->OutputString(StdErr, s)
+/* + * Include architecture specific implementation here, which references the + * static globals defined above. + */ +#include <asm/efi-boot.h> + static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer) { if ( Val >= 10 ) @@ -255,32 +246,6 @@ static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode) blexit(mesg); }
-static void __init place_string(u32 *addr, const char *s) -{ - static char *__initdata alloc = start; - - if ( s && *s ) - { - size_t len1 = strlen(s) + 1; - const char *old = (char *)(long)*addr; - size_t len2 = *addr ? strlen(old) + 1 : 0; - - alloc -= len1 + len2; - /* - * Insert new string before already existing one. This is needed - * for options passed on the command line to override options from - * the configuration file. - */ - memcpy(alloc, s, len1); - if ( *addr ) - { - alloc[len1 - 1] = ' '; - memcpy(alloc + len1, old, len2); - } - } - *addr = (long)alloc; -} - static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, CHAR16 *cmdline, UINTN cmdsize) { @@ -574,104 +539,6 @@ static void __init split_value(char *s) *s = 0; }
-static void __init edd_put_string(u8 *dst, size_t n, const char *src) -{ - while ( n-- && *src ) - *dst++ = *src++; - if ( *src ) - PrintErrMesg(L"Internal error populating EDD info", - EFI_BUFFER_TOO_SMALL); - while ( n-- ) - *dst++ = ' '; -} -#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) - -static void __init setup_efi_pci(void) -{ - EFI_STATUS status; - EFI_HANDLE *handles; - static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; - UINTN i, nr_pci, size = 0; - struct efi_pci_rom *last = NULL; - - status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, NULL); - if ( status == EFI_BUFFER_TOO_SMALL ) - status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles); - if ( !EFI_ERROR(status) ) - status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - - nr_pci = size / sizeof(*handles); - for ( i = 0; i < nr_pci; ++i ) - { - EFI_PCI_IO *pci = NULL; - u64 attributes; - struct efi_pci_rom *rom, *va; - UINTN segment, bus, device, function; - - status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); - if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) - continue; - - status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, - &attributes); - if ( EFI_ERROR(status) || - !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || - EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, - &function)) ) - continue; - - DisplayUint(segment, 4); - PrintStr(L":"); - DisplayUint(bus, 2); - PrintStr(L":"); - DisplayUint(device, 2); - PrintStr(L"."); - DisplayUint(function, 1); - PrintStr(L": ROM: "); - DisplayUint(pci->RomSize, 0); - PrintStr(L" bytes at "); - DisplayUint((UINTN)pci->RomImage, 0); - PrintStr(newline); - - size = pci->RomSize + sizeof(*rom); - status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, - (void **)&rom); - if ( EFI_ERROR(status) ) - continue; - - rom->next = NULL; - rom->size = pci->RomSize; - - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, - &rom->vendor); - if ( !EFI_ERROR(status) ) - status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, - &rom->devid); - if ( EFI_ERROR(status) ) - { - efi_bs->FreePool(rom); - continue; - } - - rom->segment = segment; - rom->bus = bus; - rom->devfn = (device << 3) | function; - memcpy(rom->data, pci->RomImage, pci->RomSize); - - va = (void *)rom + DIRECTMAP_VIRT_START; - if ( last ) - last->next = va; - else - efi_pci_roms = va; - last = rom; - } - - efi_bs->FreePool(handles); -} - static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) { if ( bpp < 0 ) @@ -687,82 +554,6 @@ static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) return max(*pos + *sz, bpp); }
-extern const intpte_t __page_tables_start[], __page_tables_end[]; -#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ - (intpte_t *)(v) < __page_tables_end) - -#define PE_BASE_RELOC_ABS 0 -#define PE_BASE_RELOC_HIGHLOW 3 -#define PE_BASE_RELOC_DIR64 10 - -extern const struct pe_base_relocs { - u32 rva; - u32 size; - u16 entries[]; -} __base_relocs_start[], __base_relocs_end[]; - -static void __init relocate_image(unsigned long delta) -{ - const struct pe_base_relocs *base_relocs; - - for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; ) - { - unsigned int i, n; - - n = (base_relocs->size - sizeof(*base_relocs)) / - sizeof(*base_relocs->entries); - for ( i = 0; i < n; ++i ) - { - unsigned long addr = xen_phys_start + base_relocs->rva + - (base_relocs->entries[i] & 0xfff); - - switch ( base_relocs->entries[i] >> 12 ) - { - case PE_BASE_RELOC_ABS: - break; - case PE_BASE_RELOC_HIGHLOW: - if ( delta ) - { - *(u32 *)addr += delta; - if ( in_page_tables(addr) ) - *(u32 *)addr += xen_phys_start; - } - break; - case PE_BASE_RELOC_DIR64: - if ( delta ) - { - *(u64 *)addr += delta; - if ( in_page_tables(addr) ) - *(intpte_t *)addr += xen_phys_start; - } - break; - default: - blexit(L"Unsupported relocation type"); - } - } - base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); - } -} - -extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; -extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; - -static void __init relocate_trampoline(unsigned long phys) -{ - const s32 *trampoline_ptr; - - trampoline_phys = phys; - /* Apply relocations to trampoline. */ - for ( trampoline_ptr = __trampoline_rel_start; - trampoline_ptr < __trampoline_rel_stop; - ++trampoline_ptr ) - *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; - for ( trampoline_ptr = __trampoline_seg_start; - trampoline_ptr < __trampoline_seg_stop; - ++trampoline_ptr ) - *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; -} - void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { @@ -879,7 +670,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION) XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n");
- relocate_image(0); + efi_arch_relocate_image(0);
if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode, &cols, &rows) == EFI_SUCCESS ) @@ -1258,7 +1049,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) dmi_efi_get_table((void *)(long)efi.smbios);
/* Collect PCI ROM contents. */ - setup_efi_pci(); + efi_arch_pci();
/* Get snapshot of variable store parameters. */ status = (efi_rs->Hdr.Revision >> 16) >= 2 ? @@ -1460,7 +1251,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_memmap = (void *)efi_memmap + DIRECTMAP_VIRT_START; efi_fw_vendor = (void *)efi_fw_vendor + DIRECTMAP_VIRT_START;
- relocate_image(__XEN_VIRT_START - xen_phys_start); + efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); memcpy((void *)trampoline_phys, trampoline_start, cfg.size);
/* Set system registers and transfer control. */ @@ -1496,228 +1287,3 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) for( ; ; ); /* not reached */ }
-#ifndef USE_SET_VIRTUAL_ADDRESS_MAP -static __init void copy_mapping(unsigned long mfn, unsigned long end, - bool_t (*is_valid)(unsigned long smfn, - unsigned long emfn)) -{ - unsigned long next; - - for ( ; mfn < end; mfn = next ) - { - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; - l3_pgentry_t *l3src, *l3dst; - unsigned long va = (unsigned long)mfn_to_virt(mfn); - - next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); - if ( !is_valid(mfn, min(next, end)) ) - continue; - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - l3dst = alloc_xen_pagetable(); - BUG_ON(!l3dst); - clear_page(l3dst); - efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = - l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); - } - else - l3dst = l4e_to_l3e(l4e); - l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); - l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; - } -} - -static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) -{ - unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; - - return !(smfn & pfn_hole_mask) && - find_next_bit(pdx_group_valid, sz, - pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; -} - -static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) -{ - return 1; -} -#endif - -#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ - (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) - -void __init efi_init_memory(void) -{ - unsigned int i; -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - struct rt_extra { - struct rt_extra *next; - unsigned long smfn, emfn; - unsigned int prot; - } *extra, *extra_head = NULL; -#endif - - printk(XENLOG_INFO "EFI memory map:\n"); - for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) - { - EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; - u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT; - unsigned long smfn, emfn; - unsigned int prot = PAGE_HYPERVISOR; - - printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64 - " type=%u attr=%016" PRIx64 "\n", - desc->PhysicalStart, desc->PhysicalStart + len - 1, - desc->Type, desc->Attribute); - - if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) ) - continue; - - desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; - - smfn = PFN_DOWN(desc->PhysicalStart); - emfn = PFN_UP(desc->PhysicalStart + len); - - if ( desc->Attribute & EFI_MEMORY_WB ) - /* nothing */; - else if ( desc->Attribute & EFI_MEMORY_WT ) - prot |= _PAGE_PWT | MAP_SMALL_PAGES; - else if ( desc->Attribute & EFI_MEMORY_WC ) - prot |= _PAGE_PAT | MAP_SMALL_PAGES; - else if ( desc->Attribute & (EFI_MEMORY_UC | EFI_MEMORY_UCE) ) - prot |= _PAGE_PWT | _PAGE_PCD | MAP_SMALL_PAGES; - else - { - printk(XENLOG_ERR "Unknown cachability for MFNs %#lx-%#lx\n", - smfn, emfn - 1); - continue; - } - - if ( desc->Attribute & EFI_MEMORY_WP ) - prot &= _PAGE_RW; - if ( desc->Attribute & EFI_MEMORY_XP ) - prot |= _PAGE_NX_BIT; - - if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) && - !(smfn & pfn_hole_mask) && - !((smfn ^ (emfn - 1)) & ~pfn_pdx_bottom_mask) ) - { - if ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) - prot &= ~_PAGE_GLOBAL; - if ( map_pages_to_xen((unsigned long)mfn_to_virt(smfn), - smfn, emfn - smfn, prot) == 0 ) - desc->VirtualStart = - (unsigned long)maddr_to_virt(desc->PhysicalStart); - else - printk(XENLOG_ERR "Could not map MFNs %#lx-%#lx\n", - smfn, emfn - 1); - } -#ifndef USE_SET_VIRTUAL_ADDRESS_MAP - else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && - (extra = xmalloc(struct rt_extra)) != NULL ) - { - extra->smfn = smfn; - extra->emfn = emfn; - extra->prot = prot & ~_PAGE_GLOBAL; - extra->next = extra_head; - extra_head = extra; - desc->VirtualStart = desc->PhysicalStart; - } -#endif - else - { -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - /* XXX allocate e.g. down from FIXADDR_START */ -#endif - printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", - smfn, emfn - 1); - } - } - -#ifdef USE_SET_VIRTUAL_ADDRESS_MAP - efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, - mdesc_ver, efi_memmap); -#else - /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ - efi_l4_pgtable = alloc_xen_pagetable(); - BUG_ON(!efi_l4_pgtable); - clear_page(efi_l4_pgtable); - - copy_mapping(0, max_page, ram_range_valid); - - /* Insert non-RAM runtime mappings inside the direct map. */ - for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) - { - const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; - - if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && - desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && - desc->VirtualStart != desc->PhysicalStart ) - copy_mapping(PFN_DOWN(desc->PhysicalStart), - PFN_UP(desc->PhysicalStart + - (desc->NumberOfPages << EFI_PAGE_SHIFT)), - rt_range_valid); - } - - /* Insert non-RAM runtime mappings outside of the direct map. */ - while ( (extra = extra_head) != NULL ) - { - unsigned long addr = extra->smfn << PAGE_SHIFT; - l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; - l3_pgentry_t *pl3e; - l2_pgentry_t *pl2e; - l1_pgentry_t *l1t; - - if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) - { - pl3e = alloc_xen_pagetable(); - BUG_ON(!pl3e); - clear_page(pl3e); - efi_l4_pgtable[l4_table_offset(addr)] = - l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); - } - else - pl3e = l4e_to_l3e(l4e); - pl3e += l3_table_offset(addr); - if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) - { - pl2e = alloc_xen_pagetable(); - BUG_ON(!pl2e); - clear_page(pl2e); - *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); - pl2e = l3e_to_l2e(*pl3e); - } - pl2e += l2_table_offset(addr); - if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) - { - l1t = alloc_xen_pagetable(); - BUG_ON(!l1t); - clear_page(l1t); - *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); - } - else - { - BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); - l1t = l2e_to_l1e(*pl2e); - } - for ( i = l1_table_offset(addr); - i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; - ++i, ++extra->smfn ) - l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); - - if ( extra->smfn == extra->emfn ) - { - extra_head = extra->next; - xfree(extra); - } - } - - /* Insert Xen mappings. */ - for ( i = l4_table_offset(HYPERVISOR_VIRT_START); - i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) - efi_l4_pgtable[i] = idle_pg_table[i]; -#endif -} diff --git a/xen/include/asm-x86/efi-boot.h b/xen/include/asm-x86/efi-boot.h new file mode 100644 index 0000000..5b91697 --- /dev/null +++ b/xen/include/asm-x86/efi-boot.h @@ -0,0 +1,455 @@ +/* + * Architecture specific implementation for EFI boot code. This file + * is intended to be included by XXX _only_, and therefore can define + * arch specific global variables. + */ +#include <asm/e820.h> +#include <asm/edd.h> +#define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ +#include <asm/fixmap.h> +#undef __ASSEMBLY__ +#include <asm/msr.h> +#include <asm/processor.h> + +static struct file __initdata ucode; +static multiboot_info_t __initdata mbi = { + .flags = MBI_MODULES | MBI_LOADERNAME +}; +static module_t __initdata mb_modules[3]; + +static void noreturn blexit(const CHAR16 *str); +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode); + +/* Using SetVirtualAddressMap() is incompatible with kexec: */ +#undef USE_SET_VIRTUAL_ADDRESS_MAP +extern char start[]; +extern u32 cpuid_ext_features; + +static void __init edd_put_string(u8 *dst, size_t n, const char *src) +{ + while ( n-- && *src ) + *dst++ = *src++; + if ( *src ) + PrintErrMesg(L"Internal error populating EDD info", + EFI_BUFFER_TOO_SMALL); + while ( n-- ) + *dst++ = ' '; +} +#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) + +static void __init efi_arch_pci(void) +{ + EFI_STATUS status; + EFI_HANDLE *handles; + static EFI_GUID __initdata pci_guid = EFI_PCI_IO_PROTOCOL; + UINTN i, nr_pci, size = 0; + struct efi_pci_rom *last = NULL; + + status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, NULL); + if ( status == EFI_BUFFER_TOO_SMALL ) + status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles); + if ( !EFI_ERROR(status) ) + status = efi_bs->LocateHandle(ByProtocol, &pci_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + + nr_pci = size / sizeof(*handles); + for ( i = 0; i < nr_pci; ++i ) + { + EFI_PCI_IO *pci = NULL; + u64 attributes; + struct efi_pci_rom *rom, *va; + UINTN segment, bus, device, function; + + status = efi_bs->HandleProtocol(handles[i], &pci_guid, (void **)&pci); + if ( EFI_ERROR(status) || !pci || !pci->RomImage || !pci->RomSize ) + continue; + + status = pci->Attributes(pci, EfiPciIoAttributeOperationGet, 0, + &attributes); + if ( EFI_ERROR(status) || + !(attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) || + EFI_ERROR(pci->GetLocation(pci, &segment, &bus, &device, + &function)) ) + continue; + + DisplayUint(segment, 4); + PrintStr(L":"); + DisplayUint(bus, 2); + PrintStr(L":"); + DisplayUint(device, 2); + PrintStr(L"."); + DisplayUint(function, 1); + PrintStr(L": ROM: "); + DisplayUint(pci->RomSize, 0); + PrintStr(L" bytes at "); + DisplayUint((UINTN)pci->RomImage, 0); + PrintStr(newline); + + size = pci->RomSize + sizeof(*rom); + status = efi_bs->AllocatePool(EfiRuntimeServicesData, size, + (void **)&rom); + if ( EFI_ERROR(status) ) + continue; + + rom->next = NULL; + rom->size = pci->RomSize; + + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, + &rom->vendor); + if ( !EFI_ERROR(status) ) + status = pci->Pci.Read(pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, + &rom->devid); + if ( EFI_ERROR(status) ) + { + efi_bs->FreePool(rom); + continue; + } + + rom->segment = segment; + rom->bus = bus; + rom->devfn = (device << 3) | function; + memcpy(rom->data, pci->RomImage, pci->RomSize); + + va = (void *)rom + DIRECTMAP_VIRT_START; + if ( last ) + last->next = va; + else + efi_pci_roms = va; + last = rom; + } + + efi_bs->FreePool(handles); +} + + +extern const intpte_t __page_tables_start[], __page_tables_end[]; +#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ + (intpte_t *)(v) < __page_tables_end) + +#define PE_BASE_RELOC_ABS 0 +#define PE_BASE_RELOC_HIGHLOW 3 +#define PE_BASE_RELOC_DIR64 10 + +extern const struct pe_base_relocs { + u32 rva; + u32 size; + u16 entries[]; +} __base_relocs_start[], __base_relocs_end[]; + +static void __init efi_arch_relocate_image(unsigned long delta) +{ + const struct pe_base_relocs *base_relocs; + + for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; ) + { + unsigned int i, n; + + n = (base_relocs->size - sizeof(*base_relocs)) / + sizeof(*base_relocs->entries); + for ( i = 0; i < n; ++i ) + { + unsigned long addr = xen_phys_start + base_relocs->rva + + (base_relocs->entries[i] & 0xfff); + + switch ( base_relocs->entries[i] >> 12 ) + { + case PE_BASE_RELOC_ABS: + break; + case PE_BASE_RELOC_HIGHLOW: + if ( delta ) + { + *(u32 *)addr += delta; + if ( in_page_tables(addr) ) + *(u32 *)addr += xen_phys_start; + } + break; + case PE_BASE_RELOC_DIR64: + if ( delta ) + { + *(u64 *)addr += delta; + if ( in_page_tables(addr) ) + *(intpte_t *)addr += xen_phys_start; + } + break; + default: + blexit(L"Unsupported relocation type"); + } + } + base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); + } +} + +extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; +extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; + +static void __init relocate_trampoline(unsigned long phys) +{ + const s32 *trampoline_ptr; + + trampoline_phys = phys; + /* Apply relocations to trampoline. */ + for ( trampoline_ptr = __trampoline_rel_start; + trampoline_ptr < __trampoline_rel_stop; + ++trampoline_ptr ) + *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; + for ( trampoline_ptr = __trampoline_seg_start; + trampoline_ptr < __trampoline_seg_stop; + ++trampoline_ptr ) + *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; +} + + +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP +static __init void copy_mapping(unsigned long mfn, unsigned long end, + bool_t (*is_valid)(unsigned long smfn, + unsigned long emfn)) +{ + unsigned long next; + + for ( ; mfn < end; mfn = next ) + { + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)]; + l3_pgentry_t *l3src, *l3dst; + unsigned long va = (unsigned long)mfn_to_virt(mfn); + + next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT)); + if ( !is_valid(mfn, min(next, end)) ) + continue; + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + l3dst = alloc_xen_pagetable(); + BUG_ON(!l3dst); + clear_page(l3dst); + efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] = + l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR); + } + else + l3dst = l4e_to_l3e(l4e); + l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]); + l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)]; + } +} + +static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn) +{ + unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1; + + return !(smfn & pfn_hole_mask) && + find_next_bit(pdx_group_valid, sz, + pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz; +} + +static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn) +{ + return 1; +} +#endif + +#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \ + (EFI_PAGE_SHIFT + BITS_PER_LONG - 32)) + +void __init efi_init_memory(void) +{ + unsigned int i; +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + struct rt_extra { + struct rt_extra *next; + unsigned long smfn, emfn; + unsigned int prot; + } *extra, *extra_head = NULL; +#endif + + printk(XENLOG_INFO "EFI memory map:\n"); + for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) + { + EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; + u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT; + unsigned long smfn, emfn; + unsigned int prot = PAGE_HYPERVISOR; + + printk(XENLOG_INFO " %013" PRIx64 "-%013" PRIx64 + " type=%u attr=%016" PRIx64 "\n", + desc->PhysicalStart, desc->PhysicalStart + len - 1, + desc->Type, desc->Attribute); + + if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) ) + continue; + + desc->VirtualStart = INVALID_VIRTUAL_ADDRESS; + + smfn = PFN_DOWN(desc->PhysicalStart); + emfn = PFN_UP(desc->PhysicalStart + len); + + if ( desc->Attribute & EFI_MEMORY_WB ) + /* nothing */; + else if ( desc->Attribute & EFI_MEMORY_WT ) + prot |= _PAGE_PWT | MAP_SMALL_PAGES; + else if ( desc->Attribute & EFI_MEMORY_WC ) + prot |= _PAGE_PAT | MAP_SMALL_PAGES; + else if ( desc->Attribute & (EFI_MEMORY_UC | EFI_MEMORY_UCE) ) + prot |= _PAGE_PWT | _PAGE_PCD | MAP_SMALL_PAGES; + else + { + printk(XENLOG_ERR "Unknown cachability for MFNs %#lx-%#lx\n", + smfn, emfn - 1); + continue; + } + + if ( desc->Attribute & EFI_MEMORY_WP ) + prot &= _PAGE_RW; + if ( desc->Attribute & EFI_MEMORY_XP ) + prot |= _PAGE_NX_BIT; + + if ( pfn_to_pdx(emfn - 1) < (DIRECTMAP_SIZE >> PAGE_SHIFT) && + !(smfn & pfn_hole_mask) && + !((smfn ^ (emfn - 1)) & ~pfn_pdx_bottom_mask) ) + { + if ( (unsigned long)mfn_to_virt(emfn - 1) >= HYPERVISOR_VIRT_END ) + prot &= ~_PAGE_GLOBAL; + if ( map_pages_to_xen((unsigned long)mfn_to_virt(smfn), + smfn, emfn - smfn, prot) == 0 ) + desc->VirtualStart = + (unsigned long)maddr_to_virt(desc->PhysicalStart); + else + printk(XENLOG_ERR "Could not map MFNs %#lx-%#lx\n", + smfn, emfn - 1); + } +#ifndef USE_SET_VIRTUAL_ADDRESS_MAP + else if ( !((desc->PhysicalStart + len - 1) >> (VADDR_BITS - 1)) && + (extra = xmalloc(struct rt_extra)) != NULL ) + { + extra->smfn = smfn; + extra->emfn = emfn; + extra->prot = prot & ~_PAGE_GLOBAL; + extra->next = extra_head; + extra_head = extra; + desc->VirtualStart = desc->PhysicalStart; + } +#endif + else + { +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + /* XXX allocate e.g. down from FIXADDR_START */ +#endif + printk(XENLOG_ERR "No mapping for MFNs %#lx-%#lx\n", + smfn, emfn - 1); + } + } + +#ifdef USE_SET_VIRTUAL_ADDRESS_MAP + efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size, + mdesc_ver, efi_memmap); +#else + /* Set up 1:1 page tables to do runtime calls in "physical" mode. */ + efi_l4_pgtable = alloc_xen_pagetable(); + BUG_ON(!efi_l4_pgtable); + clear_page(efi_l4_pgtable); + + copy_mapping(0, max_page, ram_range_valid); + + /* Insert non-RAM runtime mappings inside the direct map. */ + for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) + { + const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; + + if ( (desc->Attribute & EFI_MEMORY_RUNTIME) && + desc->VirtualStart != INVALID_VIRTUAL_ADDRESS && + desc->VirtualStart != desc->PhysicalStart ) + copy_mapping(PFN_DOWN(desc->PhysicalStart), + PFN_UP(desc->PhysicalStart + + (desc->NumberOfPages << EFI_PAGE_SHIFT)), + rt_range_valid); + } + + /* Insert non-RAM runtime mappings outside of the direct map. */ + while ( (extra = extra_head) != NULL ) + { + unsigned long addr = extra->smfn << PAGE_SHIFT; + l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(addr)]; + l3_pgentry_t *pl3e; + l2_pgentry_t *pl2e; + l1_pgentry_t *l1t; + + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) + { + pl3e = alloc_xen_pagetable(); + BUG_ON(!pl3e); + clear_page(pl3e); + efi_l4_pgtable[l4_table_offset(addr)] = + l4e_from_paddr(virt_to_maddr(pl3e), __PAGE_HYPERVISOR); + } + else + pl3e = l4e_to_l3e(l4e); + pl3e += l3_table_offset(addr); + if ( !(l3e_get_flags(*pl3e) & _PAGE_PRESENT) ) + { + pl2e = alloc_xen_pagetable(); + BUG_ON(!pl2e); + clear_page(pl2e); + *pl3e = l3e_from_paddr(virt_to_maddr(pl2e), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l3e_get_flags(*pl3e) & _PAGE_PSE); + pl2e = l3e_to_l2e(*pl3e); + } + pl2e += l2_table_offset(addr); + if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) ) + { + l1t = alloc_xen_pagetable(); + BUG_ON(!l1t); + clear_page(l1t); + *pl2e = l2e_from_paddr(virt_to_maddr(l1t), __PAGE_HYPERVISOR); + } + else + { + BUG_ON(l2e_get_flags(*pl2e) & _PAGE_PSE); + l1t = l2e_to_l1e(*pl2e); + } + for ( i = l1_table_offset(addr); + i < L1_PAGETABLE_ENTRIES && extra->smfn < extra->emfn; + ++i, ++extra->smfn ) + l1t[i] = l1e_from_pfn(extra->smfn, extra->prot); + + if ( extra->smfn == extra->emfn ) + { + extra_head = extra->next; + xfree(extra); + } + } + + /* Insert Xen mappings. */ + for ( i = l4_table_offset(HYPERVISOR_VIRT_START); + i < l4_table_offset(DIRECTMAP_VIRT_END); ++i ) + efi_l4_pgtable[i] = idle_pg_table[i]; +#endif +} + +static void __init place_string(u32 *addr, const char *s) +{ + static char *__initdata alloc = start; + + if ( s && *s ) + { + size_t len1 = strlen(s) + 1; + const char *old = (char *)(long)*addr; + size_t len2 = *addr ? strlen(old) + 1 : 0; + + alloc -= len1 + len2; + /* + * Insert new string before already existing one. This is needed + * for options passed on the command line to override options from + * the configuration file. + */ + memcpy(alloc, s, len1); + if ( *addr ) + { + alloc[len1 - 1] = ' '; + memcpy(alloc + len1, old, len2); + } + } + *addr = (long)alloc; +} +