diff options
Diffstat (limited to 'arch/arm/kernel/efi.c')
| -rw-r--r-- | arch/arm/kernel/efi.c | 41 | 
1 files changed, 41 insertions, 0 deletions
diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c index ff8a9d8acfac..9f43ba012d10 100644 --- a/arch/arm/kernel/efi.c +++ b/arch/arm/kernel/efi.c @@ -11,6 +11,41 @@  #include <asm/mach/map.h>  #include <asm/mmu_context.h> +static int __init set_permissions(pte_t *ptep, pgtable_t token, +				  unsigned long addr, void *data) +{ +	efi_memory_desc_t *md = data; +	pte_t pte = *ptep; + +	if (md->attribute & EFI_MEMORY_RO) +		pte = set_pte_bit(pte, __pgprot(L_PTE_RDONLY)); +	if (md->attribute & EFI_MEMORY_XP) +		pte = set_pte_bit(pte, __pgprot(L_PTE_XN)); +	set_pte_ext(ptep, pte, PTE_EXT_NG); +	return 0; +} + +int __init efi_set_mapping_permissions(struct mm_struct *mm, +				       efi_memory_desc_t *md) +{ +	unsigned long base, size; + +	base = md->virt_addr; +	size = md->num_pages << EFI_PAGE_SHIFT; + +	/* +	 * We can only use apply_to_page_range() if we can guarantee that the +	 * entire region was mapped using pages. This should be the case if the +	 * region does not cover any naturally aligned SECTION_SIZE sized +	 * blocks. +	 */ +	if (round_down(base + size, SECTION_SIZE) < +	    round_up(base, SECTION_SIZE) + SECTION_SIZE) +		return apply_to_page_range(mm, base, size, set_permissions, md); + +	return 0; +} +  int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)  {  	struct map_desc desc = { @@ -34,5 +69,11 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)  		desc.type = MT_DEVICE;  	create_mapping_late(mm, &desc, true); + +	/* +	 * If stricter permissions were specified, apply them now. +	 */ +	if (md->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP)) +		return efi_set_mapping_permissions(mm, md);  	return 0;  }  | 
