|
@@ -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;
|
|
|
}
|