]> xenbits.xensource.com Git - xen.git/commitdiff
arm/mm: Introduce modify_xen_mappings
authorKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Tue, 9 Aug 2016 03:14:33 +0000 (23:14 -0400)
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Fri, 16 Sep 2016 15:36:35 +0000 (11:36 -0400)
Which is only used by Livepatch code. The purpose behind
this call is to modify the page table entries flags.

Specifically the .ro and .nx flags. The current mechanism
puts cache attributes in the flags and the .ro and .nx are
locked down and assumed to be .ro=0, nx=1.

Livepatch needs .nx=0 and also .ro to be set to 1.

We introduce a new 'flags' where various bits determine
whether .ro and .nx bits are set or cleared. We can't use
an enum as the function prototype would diverge from x86.

Reviewed-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
xen/arch/arm/mm.c
xen/include/asm-arm/page.h

index 7ae9f6369a3bd366da3a701b3571cbf6146fe687..07e2037e9bb788175e4abe30142ae9295e60d3cd 100644 (file)
@@ -836,6 +836,7 @@ static int create_xen_table(lpae_t *entry)
 enum xenmap_operation {
     INSERT,
     REMOVE,
+    MODIFY,
     RESERVE
 };
 
@@ -881,14 +882,28 @@ static int create_xen_entries(enum xenmap_operation op,
                 pte.pt.table = 1;
                 write_pte(&third[third_table_offset(addr)], pte);
                 break;
+            case MODIFY:
             case REMOVE:
                 if ( !third[third_table_offset(addr)].pt.valid )
                 {
-                    printk("create_xen_entries: trying to remove a non-existing mapping addr=%lx\n",
-                           addr);
+                    printk("create_xen_entries: trying to %s a non-existing mapping addr=%lx\n",
+                           op == REMOVE ? "remove" : "modify", addr);
                     return -EINVAL;
                 }
-                pte.bits = 0;
+                if ( op == REMOVE )
+                    pte.bits = 0;
+                else
+                {
+                    pte = third[third_table_offset(addr)];
+                    pte.pt.ro = PTE_RO_MASK(ai);
+                    pte.pt.xn = PTE_NX_MASK(ai);
+                    if ( !pte.pt.ro && !pte.pt.xn )
+                    {
+                        printk("create_xen_entries: Incorrect combination for addr=%lx\n",
+                               addr);
+                        return -EINVAL;
+                    }
+                }
                 write_pte(&third[third_table_offset(addr)], pte);
                 break;
             default:
@@ -922,6 +937,12 @@ int destroy_xen_mappings(unsigned long v, unsigned long e)
     return create_xen_entries(REMOVE, v, 0, (e - v) >> PAGE_SHIFT, 0);
 }
 
+int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int flags)
+{
+    ASSERT((flags & (PTE_NX | PTE_RO)) == flags);
+    return create_xen_entries(MODIFY, s, 0, (e - s) >> PAGE_SHIFT, flags);
+}
+
 enum mg { mg_clear, mg_ro, mg_rw, mg_rx };
 static void set_pte_flags_on_range(const char *p, unsigned long l, enum mg mg)
 {
index 05d9f82d0dfa9a9d19ce6127b6380326dba044e8..015ed6307a7b704a790882f3d160849111b42c4c 100644 (file)
 #define PAGE_HYPERVISOR_NOCACHE (DEV_SHARED)
 #define PAGE_HYPERVISOR_WC      (DEV_WC)
 
+/*
+ * Defines for changing the hypervisor PTE .ro and .nx bits. This is only to be
+ * used with modify_xen_mappings.
+ */
+#define _PTE_NX_BIT     0U
+#define _PTE_RO_BIT     1U
+#define PTE_NX          (1U << _PTE_NX_BIT)
+#define PTE_RO          (1U << _PTE_RO_BIT)
+#define PTE_NX_MASK(x)  (((x) >> _PTE_NX_BIT) & 0x1U)
+#define PTE_RO_MASK(x)  (((x) >> _PTE_RO_BIT) & 0x1U)
+
 /*
  * Stage 2 Memory Type.
  *