mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
arm64 updates for 3.20:
- reimplementation of the virtual remapping of UEFI Runtime Services in
a way that is stable across kexec
- emulation of the "setend" instruction for 32-bit tasks (user
endianness switching trapped in the kernel, SCTLR_EL1.E0E bit set
accordingly)
- compat_sys_call_table implemented in C (from asm) and made it a
constant array together with sys_call_table
- export CPU cache information via /sys (like other architectures)
- DMA API implementation clean-up in preparation for IOMMU support
- macros clean-up for KVM
- dropped some unnecessary cache+tlb maintenance
- CONFIG_ARM64_CPU_SUSPEND clean-up
- defconfig update (CPU_IDLE)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJU25v3AAoJEGvWsS0AyF7xYjcP/j8ESvs+z0BPgeJ6XREfOnCh
cp+w/1rJ5BafJ5RRkibrciwTNOIJS4FGMivWyURtoh430lS0Rh7fxZ3Ouna3xjrT
Nf7AxenWoA8Lo6wHh+FlNUeGk3iWfX6WwA2tYrbKudK+LBJ1wHjwpE7cWQO0FgwJ
aFDahu+QD5/u45p/VcVctMtiEDvOxBdO8gfat6r+YkLm7pbRxQkZnpA/JE4Gps1p
Td5jvMNH9pXI5pffSbeR9Q+vs/r0yqKLXQg01Eb2bZgGDgwf9yzADrHuaKamZt35
X5flmLiTGC6swJCJvUkZC1Nuue33bXcvW5+vgvar+MNGyXsxv+B/wARLqGhiWhQZ
nLGwFpuNu6wdY9tGHb/XR8khcewkw1/lRH1hHKhchrmRyUqHvXcPgC5tamjLrY8C
BV3BAeQvRho8OKwWUmbXIlyON1vPux6CJdj4D/A5NL+qph2WHeVWJCXg6nVFx0Wc
Eb3bXbI4QRwTFL7pGRF8RyZJBAQtgYhQMKWMW2GHgUgn+r1EixG73BZoSwvpHrrw
FOR9AVNfVBqmNON8xiIb3DN4EViq76EF0jrsZh5I9EoWS2w5qtk60kJQgXE+M4EE
vOlmh3dhEVfCN2SxOn0bgoQmTulyjqGauTSSJKQbIBuinPFveukrJfGNFIWt0SZs
f38FBMo6sgU4VG85B+Fr
=X5x/
-----END PGP SIGNATURE-----
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Catalin Marinas:
"arm64 updates for 3.20:
- reimplementation of the virtual remapping of UEFI Runtime Services
in a way that is stable across kexec
- emulation of the "setend" instruction for 32-bit tasks (user
endianness switching trapped in the kernel, SCTLR_EL1.E0E bit set
accordingly)
- compat_sys_call_table implemented in C (from asm) and made it a
constant array together with sys_call_table
- export CPU cache information via /sys (like other architectures)
- DMA API implementation clean-up in preparation for IOMMU support
- macros clean-up for KVM
- dropped some unnecessary cache+tlb maintenance
- CONFIG_ARM64_CPU_SUSPEND clean-up
- defconfig update (CPU_IDLE)
The EFI changes going via the arm64 tree have been acked by Matt
Fleming. There is also a patch adding sys_*stat64 prototypes to
include/linux/syscalls.h, acked by Andrew Morton"
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (47 commits)
arm64: compat: Remove incorrect comment in compat_siginfo
arm64: Fix section mismatch on alloc_init_p[mu]d()
arm64: Avoid breakage caused by .altmacro in fpsimd save/restore macros
arm64: mm: use *_sect to check for section maps
arm64: drop unnecessary cache+tlb maintenance
arm64:mm: free the useless initial page table
arm64: Enable CPU_IDLE in defconfig
arm64: kernel: remove ARM64_CPU_SUSPEND config option
arm64: make sys_call_table const
arm64: Remove asm/syscalls.h
arm64: Implement the compat_sys_call_table in C
syscalls: Declare sys_*stat64 prototypes if __ARCH_WANT_(COMPAT_)STAT64
compat: Declare compat_sys_sigpending and compat_sys_sigprocmask prototypes
arm64: uapi: expose our struct ucontext to the uapi headers
smp, ARM64: Kill SMP single function call interrupt
arm64: Emulate SETEND for AArch32 tasks
arm64: Consolidate hotplug notifier for instruction emulation
arm64: Track system support for mixed endian EL0
arm64: implement generic IOMMU configuration
arm64: Combine coherent and non-coherent swiotlb dma_ops
...
This commit is contained in:
commit
6b00f7efb5
73 changed files with 1533 additions and 919 deletions
|
|
@ -297,10 +297,49 @@ static __init int match_config_table(efi_guid_t *guid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init efi_config_parse_tables(void *config_tables, int count, int sz,
|
||||
efi_config_table_type_t *arch_tables)
|
||||
{
|
||||
void *tablep;
|
||||
int i;
|
||||
|
||||
tablep = config_tables;
|
||||
pr_info("");
|
||||
for (i = 0; i < count; i++) {
|
||||
efi_guid_t guid;
|
||||
unsigned long table;
|
||||
|
||||
if (efi_enabled(EFI_64BIT)) {
|
||||
u64 table64;
|
||||
guid = ((efi_config_table_64_t *)tablep)->guid;
|
||||
table64 = ((efi_config_table_64_t *)tablep)->table;
|
||||
table = table64;
|
||||
#ifndef CONFIG_64BIT
|
||||
if (table64 >> 32) {
|
||||
pr_cont("\n");
|
||||
pr_err("Table located above 4GB, disabling EFI.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
guid = ((efi_config_table_32_t *)tablep)->guid;
|
||||
table = ((efi_config_table_32_t *)tablep)->table;
|
||||
}
|
||||
|
||||
if (!match_config_table(&guid, table, common_tables))
|
||||
match_config_table(&guid, table, arch_tables);
|
||||
|
||||
tablep += sz;
|
||||
}
|
||||
pr_cont("\n");
|
||||
set_bit(EFI_CONFIG_TABLES, &efi.flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init efi_config_init(efi_config_table_type_t *arch_tables)
|
||||
{
|
||||
void *config_tables, *tablep;
|
||||
int i, sz;
|
||||
void *config_tables;
|
||||
int sz, ret;
|
||||
|
||||
if (efi_enabled(EFI_64BIT))
|
||||
sz = sizeof(efi_config_table_64_t);
|
||||
|
|
@ -317,42 +356,11 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tablep = config_tables;
|
||||
pr_info("");
|
||||
for (i = 0; i < efi.systab->nr_tables; i++) {
|
||||
efi_guid_t guid;
|
||||
unsigned long table;
|
||||
ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
|
||||
arch_tables);
|
||||
|
||||
if (efi_enabled(EFI_64BIT)) {
|
||||
u64 table64;
|
||||
guid = ((efi_config_table_64_t *)tablep)->guid;
|
||||
table64 = ((efi_config_table_64_t *)tablep)->table;
|
||||
table = table64;
|
||||
#ifndef CONFIG_64BIT
|
||||
if (table64 >> 32) {
|
||||
pr_cont("\n");
|
||||
pr_err("Table located above 4GB, disabling EFI.\n");
|
||||
early_memunmap(config_tables,
|
||||
efi.systab->nr_tables * sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
guid = ((efi_config_table_32_t *)tablep)->guid;
|
||||
table = ((efi_config_table_32_t *)tablep)->table;
|
||||
}
|
||||
|
||||
if (!match_config_table(&guid, table, common_tables))
|
||||
match_config_table(&guid, table, arch_tables);
|
||||
|
||||
tablep += sz;
|
||||
}
|
||||
pr_cont("\n");
|
||||
early_memunmap(config_tables, efi.systab->nr_tables * sz);
|
||||
|
||||
set_bit(EFI_CONFIG_TABLES, &efi.flags);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EFI_VARS_MODULE
|
||||
|
|
|
|||
|
|
@ -295,3 +295,62 @@ fail_free_image:
|
|||
fail:
|
||||
return EFI_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the base address at which to start allocating virtual memory ranges
|
||||
* for UEFI Runtime Services. This is in the low TTBR0 range so that we can use
|
||||
* any allocation we choose, and eliminate the risk of a conflict after kexec.
|
||||
* The value chosen is the largest non-zero power of 2 suitable for this purpose
|
||||
* both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
|
||||
* be mapped efficiently.
|
||||
*/
|
||||
#define EFI_RT_VIRTUAL_BASE 0x40000000
|
||||
|
||||
/*
|
||||
* efi_get_virtmap() - create a virtual mapping for the EFI memory map
|
||||
*
|
||||
* This function populates the virt_addr fields of all memory region descriptors
|
||||
* in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
|
||||
* are also copied to @runtime_map, and their total count is returned in @count.
|
||||
*/
|
||||
void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
|
||||
unsigned long desc_size, efi_memory_desc_t *runtime_map,
|
||||
int *count)
|
||||
{
|
||||
u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
|
||||
efi_memory_desc_t *out = runtime_map;
|
||||
int l;
|
||||
|
||||
for (l = 0; l < map_size; l += desc_size) {
|
||||
efi_memory_desc_t *in = (void *)memory_map + l;
|
||||
u64 paddr, size;
|
||||
|
||||
if (!(in->attribute & EFI_MEMORY_RUNTIME))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Make the mapping compatible with 64k pages: this allows
|
||||
* a 4k page size kernel to kexec a 64k page size kernel and
|
||||
* vice versa.
|
||||
*/
|
||||
paddr = round_down(in->phys_addr, SZ_64K);
|
||||
size = round_up(in->num_pages * EFI_PAGE_SIZE +
|
||||
in->phys_addr - paddr, SZ_64K);
|
||||
|
||||
/*
|
||||
* Avoid wasting memory on PTEs by choosing a virtual base that
|
||||
* is compatible with section mappings if this region has the
|
||||
* appropriate size and physical alignment. (Sections are 2 MB
|
||||
* on 4k granule kernels)
|
||||
*/
|
||||
if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
|
||||
efi_virt_base = round_up(efi_virt_base, SZ_2M);
|
||||
|
||||
in->virt_addr = efi_virt_base + in->phys_addr - paddr;
|
||||
efi_virt_base += size;
|
||||
|
||||
memcpy(out, in, desc_size);
|
||||
out = (void *)out + desc_size;
|
||||
++*count;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@
|
|||
|
||||
static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
|
||||
|
||||
/*
|
||||
* Allow the platform to override the allocation granularity: this allows
|
||||
* systems that have the capability to run with a larger page size to deal
|
||||
* with the allocations for initrd and fdt more efficiently.
|
||||
*/
|
||||
#ifndef EFI_ALLOC_ALIGN
|
||||
#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
|
||||
#endif
|
||||
|
||||
struct file_info {
|
||||
efi_file_handle_t *handle;
|
||||
u64 size;
|
||||
|
|
@ -154,10 +163,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
|
|||
* a specific address. We are doing page-based allocations,
|
||||
* so we must be aligned to a page.
|
||||
*/
|
||||
if (align < EFI_PAGE_SIZE)
|
||||
align = EFI_PAGE_SIZE;
|
||||
if (align < EFI_ALLOC_ALIGN)
|
||||
align = EFI_ALLOC_ALIGN;
|
||||
|
||||
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
|
||||
nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
|
||||
again:
|
||||
for (i = 0; i < map_size / desc_size; i++) {
|
||||
efi_memory_desc_t *desc;
|
||||
|
|
@ -239,10 +248,10 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
|
|||
* a specific address. We are doing page-based allocations,
|
||||
* so we must be aligned to a page.
|
||||
*/
|
||||
if (align < EFI_PAGE_SIZE)
|
||||
align = EFI_PAGE_SIZE;
|
||||
if (align < EFI_ALLOC_ALIGN)
|
||||
align = EFI_ALLOC_ALIGN;
|
||||
|
||||
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
|
||||
nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
|
||||
for (i = 0; i < map_size / desc_size; i++) {
|
||||
efi_memory_desc_t *desc;
|
||||
unsigned long m = (unsigned long)map;
|
||||
|
|
@ -296,7 +305,7 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
|
|||
if (!size)
|
||||
return;
|
||||
|
||||
nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
|
||||
nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
|
||||
efi_call_early(free_pages, addr, nr_pages);
|
||||
}
|
||||
|
||||
|
|
@ -565,7 +574,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
|
|||
* to the preferred address. If that fails, allocate as low
|
||||
* as possible while respecting the required alignment.
|
||||
*/
|
||||
nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
|
||||
nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
|
||||
status = efi_call_early(allocate_pages,
|
||||
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
|
||||
nr_pages, &efi_addr);
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
|
||||
void *get_fdt(efi_system_table_t *sys_table);
|
||||
|
||||
void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
|
||||
unsigned long desc_size, efi_memory_desc_t *runtime_map,
|
||||
int *count);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include <linux/libfdt.h>
|
||||
#include <asm/efi.h>
|
||||
|
||||
#include "efistub.h"
|
||||
|
||||
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
|
||||
unsigned long orig_fdt_size,
|
||||
void *fdt, int new_fdt_size, char *cmdline_ptr,
|
||||
|
|
@ -193,9 +195,26 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
unsigned long map_size, desc_size;
|
||||
u32 desc_ver;
|
||||
unsigned long mmap_key;
|
||||
efi_memory_desc_t *memory_map;
|
||||
efi_memory_desc_t *memory_map, *runtime_map;
|
||||
unsigned long new_fdt_size;
|
||||
efi_status_t status;
|
||||
int runtime_entry_count = 0;
|
||||
|
||||
/*
|
||||
* Get a copy of the current memory map that we will use to prepare
|
||||
* the input for SetVirtualAddressMap(). We don't have to worry about
|
||||
* subsequent allocations adding entries, since they could not affect
|
||||
* the number of EFI_MEMORY_RUNTIME regions.
|
||||
*/
|
||||
status = efi_get_memory_map(sys_table, &runtime_map, &map_size,
|
||||
&desc_size, &desc_ver, &mmap_key);
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
pr_efi(sys_table,
|
||||
"Exiting boot services and installing virtual address map...\n");
|
||||
|
||||
/*
|
||||
* Estimate size of new FDT, and allocate memory for it. We
|
||||
|
|
@ -248,12 +267,48 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the memory map with virtual addresses. The function will also
|
||||
* populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
|
||||
* entries so that we can pass it straight into SetVirtualAddressMap()
|
||||
*/
|
||||
efi_get_virtmap(memory_map, map_size, desc_size, runtime_map,
|
||||
&runtime_entry_count);
|
||||
|
||||
/* Now we are ready to exit_boot_services.*/
|
||||
status = sys_table->boottime->exit_boot_services(handle, mmap_key);
|
||||
|
||||
if (status == EFI_SUCCESS) {
|
||||
efi_set_virtual_address_map_t *svam;
|
||||
|
||||
if (status == EFI_SUCCESS)
|
||||
return status;
|
||||
/* Install the new virtual address map */
|
||||
svam = sys_table->runtime->set_virtual_address_map;
|
||||
status = svam(runtime_entry_count * desc_size, desc_size,
|
||||
desc_ver, runtime_map);
|
||||
|
||||
/*
|
||||
* We are beyond the point of no return here, so if the call to
|
||||
* SetVirtualAddressMap() failed, we need to signal that to the
|
||||
* incoming kernel but proceed normally otherwise.
|
||||
*/
|
||||
if (status != EFI_SUCCESS) {
|
||||
int l;
|
||||
|
||||
/*
|
||||
* Set the virtual address field of all
|
||||
* EFI_MEMORY_RUNTIME entries to 0. This will signal
|
||||
* the incoming kernel that no virtual translation has
|
||||
* been installed.
|
||||
*/
|
||||
for (l = 0; l < map_size; l += desc_size) {
|
||||
efi_memory_desc_t *p = (void *)memory_map + l;
|
||||
|
||||
if (p->attribute & EFI_MEMORY_RUNTIME)
|
||||
p->virt_addr = 0;
|
||||
}
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
pr_efi_err(sys_table, "Exit boot services failed.\n");
|
||||
|
||||
|
|
@ -264,6 +319,7 @@ fail_free_new_fdt:
|
|||
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
|
||||
|
||||
fail:
|
||||
sys_table->boottime->free_pool(runtime_map);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue