2020-09-18 01:37:15 +03:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 2020 Western Digital Corporation or its affiliates .
* Adapted from arch / arm64 / kernel / efi . c
*/
# include <linux/efi.h>
# include <linux/init.h>
# include <asm/efi.h>
# include <asm/pgtable.h>
# include <asm/pgtable-bits.h>
/*
* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
* executable , everything else can be mapped with the XN bits
* set . Also take the new ( optional ) RO / XP bits into account .
*/
static __init pgprot_t efimem_to_pgprot_map ( efi_memory_desc_t * md )
{
u64 attr = md - > attribute ;
u32 type = md - > type ;
if ( type = = EFI_MEMORY_MAPPED_IO )
return PAGE_KERNEL ;
/* R-- */
if ( ( attr & ( EFI_MEMORY_XP | EFI_MEMORY_RO ) ) = =
( EFI_MEMORY_XP | EFI_MEMORY_RO ) )
return PAGE_KERNEL_READ ;
/* R-X */
if ( attr & EFI_MEMORY_RO )
return PAGE_KERNEL_READ_EXEC ;
/* RW- */
if ( ( ( attr & ( EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP ) ) = =
EFI_MEMORY_XP ) | |
type ! = EFI_RUNTIME_SERVICES_CODE )
return PAGE_KERNEL ;
/* RWX */
return PAGE_KERNEL_EXEC ;
}
int __init efi_create_mapping ( struct mm_struct * mm , efi_memory_desc_t * md )
{
pgprot_t prot = __pgprot ( pgprot_val ( efimem_to_pgprot_map ( md ) ) &
~ ( _PAGE_GLOBAL ) ) ;
int i ;
/* RISC-V maps one page at a time */
for ( i = 0 ; i < md - > num_pages ; i + + )
create_pgd_mapping ( mm - > pgd , md - > virt_addr + i * PAGE_SIZE ,
md - > phys_addr + i * PAGE_SIZE ,
PAGE_SIZE , prot ) ;
return 0 ;
}
static int __init set_permissions ( pte_t * ptep , unsigned long addr , void * data )
{
efi_memory_desc_t * md = data ;
pte_t pte = READ_ONCE ( * ptep ) ;
unsigned long val ;
if ( md - > attribute & EFI_MEMORY_RO ) {
val = pte_val ( pte ) & ~ _PAGE_WRITE ;
2022-05-28 04:41:32 +03:00
val | = _PAGE_READ ;
2020-09-18 01:37:15 +03:00
pte = __pte ( val ) ;
}
if ( md - > attribute & EFI_MEMORY_XP ) {
val = pte_val ( pte ) & ~ _PAGE_EXEC ;
pte = __pte ( val ) ;
}
set_pte ( ptep , pte ) ;
return 0 ;
}
int __init efi_set_mapping_permissions ( struct mm_struct * mm ,
efi_memory_desc_t * md )
{
BUG_ON ( md - > type ! = EFI_RUNTIME_SERVICES_CODE & &
md - > type ! = EFI_RUNTIME_SERVICES_DATA ) ;
/*
* Calling apply_to_page_range ( ) is only safe on regions that are
* guaranteed to be mapped down to pages . Since we are only called
* for regions that have been mapped using efi_create_mapping ( ) above
* ( and this is checked by the generic Memory Attributes table parsing
* routines ) , there is no need to check that again here .
*/
return apply_to_page_range ( mm , md - > virt_addr ,
md - > num_pages < < EFI_PAGE_SHIFT ,
set_permissions , md ) ;
}