diff mbox series

[v6,3/5] xen/arm64: mm: Introduce helpers to prepare/enable/disable the identity mapping

Message ID 20230302145916.44035-4-julien@xen.org (mailing list archive)
State Superseded
Headers show
Series xen/arm: Don't switch TTBR while the MMU is on | expand

Commit Message

Julien Grall March 2, 2023, 2:59 p.m. UTC
From: Julien Grall <jgrall@amazon.com>

In follow-up patches we will need to have part of Xen identity mapped in
order to safely switch the TTBR.

On some platform, the identity mapping may have to start at 0. If we always
keep the identity region mapped, NULL pointer dereference would lead to
access to valid mapping.

It would be possible to relocate Xen to avoid clashing with address 0.
However the identity mapping is only meant to be used in very limited
places. Therefore it would be better to keep the identity region invalid
for most of the time.

Two new external helpers are introduced:
    - arch_setup_page_tables() will setup the page-tables so it is
      easy to create the mapping afterwards.
    - update_identity_mapping() will create/remove the identity mapping

Signed-off-by: Julien Grall <jgrall@amazon.com>

----
    Changes in v6:
        - Correctly check the placement of the identity mapping (take
          2).
        - Fix typoes

    Changes in v5:
        - The reserved area for the identity mapping is 2TB (so 4 slots)
          rather than 512GB.

    Changes in v4:
        - Fix typo in a comment
        - Clarify which page-tables are updated

    Changes in v2:
        - Remove the arm32 part
        - Use a different logic for the boot page tables and runtime
          one because Xen may be running in a different place.
---
 xen/arch/arm/arm64/Makefile         |   1 +
 xen/arch/arm/arm64/mm.c             | 130 ++++++++++++++++++++++++++++
 xen/arch/arm/include/asm/arm32/mm.h |   4 +
 xen/arch/arm/include/asm/arm64/mm.h |  13 +++
 xen/arch/arm/include/asm/config.h   |   2 +
 xen/arch/arm/include/asm/setup.h    |  11 +++
 xen/arch/arm/mm.c                   |   6 +-
 7 files changed, 165 insertions(+), 2 deletions(-)
 create mode 100644 xen/arch/arm/arm64/mm.c

Comments

Henry Wang March 2, 2023, 3:15 p.m. UTC | #1
Hi Julien,

> -----Original Message-----
> Subject: [PATCH v6 3/5] xen/arm64: mm: Introduce helpers to
> prepare/enable/disable the identity mapping
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> In follow-up patches we will need to have part of Xen identity mapped in
> order to safely switch the TTBR.
> 
> On some platform, the identity mapping may have to start at 0. If we always
> keep the identity region mapped, NULL pointer dereference would lead to
> access to valid mapping.
> 
> It would be possible to relocate Xen to avoid clashing with address 0.
> However the identity mapping is only meant to be used in very limited
> places. Therefore it would be better to keep the identity region invalid
> for most of the time.
> 
> Two new external helpers are introduced:
>     - arch_setup_page_tables() will setup the page-tables so it is
>       easy to create the mapping afterwards.
>     - update_identity_mapping() will create/remove the identity mapping
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Reviewed-by: Henry Wang <Henry.Wang@arm.com>

Kind regards,
Henry
Bertrand Marquis March 3, 2023, 10:35 a.m. UTC | #2
Hi Julien,

> On 2 Mar 2023, at 15:59, Julien Grall <julien@xen.org> wrote:
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> In follow-up patches we will need to have part of Xen identity mapped in
> order to safely switch the TTBR.
> 
> On some platform, the identity mapping may have to start at 0. If we always
> keep the identity region mapped, NULL pointer dereference would lead to
> access to valid mapping.
> 
> It would be possible to relocate Xen to avoid clashing with address 0.
> However the identity mapping is only meant to be used in very limited
> places. Therefore it would be better to keep the identity region invalid
> for most of the time.
> 
> Two new external helpers are introduced:
>    - arch_setup_page_tables() will setup the page-tables so it is
>      easy to create the mapping afterwards.
>    - update_identity_mapping() will create/remove the identity mapping
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

In Arm internal CI this patch (or maybe an other in the serie) made one
of our test crash on qemu-arm64.

The error log is here after.

Cheers
Bertrand

- UART enabled -

- Boot CPU booting -

- Current EL 0000000000000008 -

- Initialize CPU -

- Turning on paging -

- Zero BSS -

- Ready -

(XEN) Checking for initrd in /chosen

(XEN) RAM: 0000000040000000 - 00000000bfffffff

(XEN) 

(XEN) MODULE[0]: 0000000040200000 - 00000000403590c8 Xen 

(XEN) MODULE[1]: 0000000048000000 - 0000000048008f20 Device Tree 

(XEN) MODULE[2]: 0000000045000000 - 00000000463e3200 Kernel 

(XEN) 

(XEN) 

(XEN) Command line: console=dtuart dtuart=/pl011@9000000 dom0_mem=512m

(XEN) Domain heap initialised

(XEN) Booting using Device Tree

(XEN) Platform: Generic System

(XEN) Looking for dtuart at "/pl011@9000000", options ""

Xen 4.18-unstable

(XEN) Xen version 4.18-unstable (@eu-west-1.compute.internal) (aarch64-poky-linux-gcc (GCC) 11.3.0) debug=y 2023-03-02

(XEN) Latest ChangeSet: 

(XEN) build-id: cc83f93cef7a75d303680ba1f98e756c07df5497

(XEN) Processor: 00000000411fd070: "ARM Limited", variant: 0x1, part 0xd07,rev 0x0

(XEN) 64-bit Execution:

(XEN) Processor Features: 0000000001000222 0000000000000000

(XEN) Exception Levels: EL3:No EL2:64+32 EL1:64+32 EL0:64+32

(XEN) Extensions: FloatingPoint AdvancedSIMD GICv3-SysReg

(XEN) Debug Features: 0000000010305106 0000000000000000

(XEN) Auxiliary Features: 0000000000000000 0000000000000000

(XEN) Memory Model Features: 0000000000001124 0000000000000000

(XEN) ISA Features: 0000000000011120 0000000000000000

(XEN) 32-bit Execution:

(XEN) Processor Features: 0000000000000131:0000000010011001

(XEN) Instruction Sets: AArch32 A32 Thumb Thumb-2 Jazelle

(XEN) Extensions: GenericTimer

(XEN) Debug Features: 0000000003010066

(XEN) Auxiliary Features: 0000000000000000

(XEN) Memory Model Features: 0000000010101105 0000000040000000

(XEN) 0000000001260000 0000000002102211

(XEN) ISA Features: 0000000002101110 0000000013112111 0000000021232042

(XEN) 0000000001112131 0000000000011142 0000000000011121

(XEN) Using SMC Calling Convention v1.0

(XEN) Using PSCI v0.2

(XEN) SMP: Allowing 4 CPUs

(XEN) enabled workaround for: ARM erratum 832075

(XEN) enabled workaround for: ARM erratum 834220

(XEN) enabled workaround for: ARM erratum 1319367

(XEN) Generic Timer IRQ: phys=30 hyp=26 virt=27 Freq: 62500 KHz

(XEN) GICv3 initialization:

(XEN) gic_dist_addr=0x00000008000000

(XEN) gic_maintenance_irq=25

(XEN) gic_rdist_stride=0

(XEN) gic_rdist_regions=1

(XEN) redistributor regions:

(XEN) - region 0: 0x000000080a0000 - 0x00000009000000

(XEN) GICv3: 256 lines, (IID 0000043b).

(XEN) GICv3: CPU0: Found redistributor in region 0 @000000004001c000

(XEN) XSM Framework v1.0.1 initialized

(XEN) Initialising XSM SILO mode

(XEN) Using scheduler: SMP Credit Scheduler rev2 (credit2)

(XEN) Initializing Credit2 scheduler

(XEN) load_precision_shift: 18

(XEN) load_window_shift: 30

(XEN) underload_balance_tolerance: 0

(XEN) overload_balance_tolerance: -3

(XEN) runqueues arrangement: socket

(XEN) cap enforcement granularity: 10ms

(XEN) load tracking window length 1073741824 ns

(XEN) Allocated console ring of 32 KiB.

(XEN) CPU0: Guest atomics will try 1 times before pausing the domain

(XEN) Bringing up CPU1

(XEN) arch/arm/mm.c:874: Changing MFN for a valid entry is not allowed (0x8284 -> 0x40200).

(XEN) Xen WARN at arch/arm/mm.c:874

(XEN) ----[ Xen-4.18-unstable arm64 debug=y Not tainted ]----

(XEN) CPU: 0

(XEN) PC: 0000020000272438 mm.c#xen_pt_update+0x6d0/0x82c

(XEN) LR: 0000020000272438

(XEN) SP: 000002000030fc60

(XEN) CPSR: 0000000080000249 MODE:64-bit EL2h (Hypervisor, handler)

(XEN) X0: 0000020000318038 X1: 0000000000000002 X2: 0000000000000000

(XEN) X3: 0000000000000003 X4: 00000200002be956 X5: 0000000000000002

(XEN) X6: 000080007ffe9360 X7: fefefefefefefefe X8: ffffffffffffffff

(XEN) X9: 0000000000000080 X10: 7f7f7f7f7f7f7f7f X11: 0101010101010101

(XEN) X12: 0000000000000008 X13: 0000000000000030 X14: 0000000000000005

(XEN) X15: 0000000000000000 X16: fffffff800000000 X17: 0000000000000001

(XEN) X18: 0180000000000000 X19: 0000800000326000 X20: 0000000000000003

(XEN) X21: 0000800000326000 X22: 000002000030fd5c X23: 000002000034f000

(XEN) X24: 0000000000000003 X25: 0000000000040200 X26: 000002000031b074

(XEN) X27: 0000000000000000 X28: 0000000000040200 FP: 000002000030fc60

(XEN) 

(XEN) VTCR_EL2: 0000000000000000

(XEN) VTTBR_EL2: 0000000000000000

(XEN) 

(XEN) SCTLR_EL2: 0000000030cd183d

(XEN) HCR_EL2: 0000000000000038

(XEN) TTBR0_EL2: 000000004034e000

(XEN) 

(XEN) ESR_EL2: 00000000f2000001

(XEN) HPFAR_EL2: 0000000000000000

(XEN) FAR_EL2: 0000000000000000

(XEN) 

(XEN) Xen stack trace from sp=000002000030fc60:

(XEN) 000002000030fd60 00000200002727f8 ff00000040200b80 0000000000000000

(XEN) 0000000000000001 000002000034f430 000002000034f000 00000200002aef18

(XEN) 00000200002f0d38 0000000000000001 0000000048000000 0000000000008f20

(XEN) 0000000000000001 0000020000000037 0000000000000001 0000000000000001

(XEN) 000000010030fd00 00000200002b4eb8 0000000000000001 000000000004034e

(XEN) 0000000000000020 0000020000000037 0000000000000000 0000000000000001

(XEN) 0000000000000000 000002000031b074 0000000040200000 0000000000000001

(XEN) 000002000030fd60 000002000024c710 0000000100000000 0000000000000001

(XEN) 000002000030fd70 0000020000265cac 000002000030fda0 0000020000265d38

(XEN) 0000000000000001 0000000000000000 0000000000000001 00000200002aef18

(XEN) 000002000030fdc0 00000200002787f4 0000000000000001 00000200002787ac

(XEN) 000002000030fe10 0000020000201f78 0000000000000001 0000000000000000

(XEN) 00000200002f0d38 00000200002dccf8 000002000030fe10 0000020000201f50

(XEN) 0000000000000001 00000200002c1358 000002000030fe40 00000200002dc92c

(XEN) 0000000000000001 00000200002b3000 00000000c0000000 00000200002bee58

(XEN) 0000000000000000 00000200002001bc 0000000040200000 fffffe0040000000

(XEN) 0000000048000000 0000000000000000 0000020000400000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) Xen call trace:

(XEN) [<0000020000272438>] mm.c#xen_pt_update+0x6d0/0x82c (PC)

(XEN) [<0000020000272438>] mm.c#xen_pt_update+0x6d0/0x82c (LR)

(XEN) [<00000200002727f8>] map_pages_to_xen+0x10/0x1c

(XEN) [<0000020000265cac>] update_identity_mapping+0x58/0x94

(XEN) [<0000020000265d38>] arch_cpu_up+0x30/0x78

(XEN) [<00000200002787f4>] __cpu_up+0x80/0x1d0

(XEN) [<0000020000201f78>] cpu_up+0xc8/0xf8

(XEN) [<00000200002dc92c>] start_xen+0x8fc/0xcb0

(XEN) [<00000200002001bc>] head.o#primary_switched+0x10/0x30

(XEN) 

(XEN) Xen BUG at arch/arm/arm64/mm.c:120

(XEN) ----[ Xen-4.18-unstable arm64 debug=y Not tainted ]----

(XEN) CPU: 0

(XEN) PC: 0000020000265ce4 update_identity_mapping+0x90/0x94

(XEN) LR: 0000020000265cac

(XEN) SP: 000002000030fd70

(XEN) CPSR: 0000000080000249 MODE:64-bit EL2h (Hypervisor, handler)

(XEN) X0: 00000000ffffffea X1: 0000000000000001 X2: 0000000000000000

(XEN) X3: 0000000000000002 X4: 00000200002bee06 X5: 0000000000000001

(XEN) X6: 000080007ffe9358 X7: fefefefefefefefe X8: ffffffffffffffff

(XEN) X9: 0000000000000080 X10: 7f7f7f7f7f7f7f7f X11: 0101010101010101

(XEN) X12: 0000000000000008 X13: 0000000000000030 X14: 0000000000000005

(XEN) X15: 0000000000000000 X16: fffffff800000000 X17: 0000000000000001

(XEN) X18: 0180000000000000 X19: ff00000040200b80 X20: 0000000000000000

(XEN) X21: 0000000000000001 X22: 000002000034f430 X23: 000002000034f000

(XEN) X24: 00000200002aef18 X25: 00000200002f0d38 X26: 0000000000000001

(XEN) X27: 0000000048000000 X28: 0000000000008f20 FP: 000002000030fd70

(XEN) 

(XEN) VTCR_EL2: 0000000000000000

(XEN) VTTBR_EL2: 0000000000000000

(XEN) 

(XEN) SCTLR_EL2: 0000000030cd183d

(XEN) HCR_EL2: 0000000000000038

(XEN) TTBR0_EL2: 000000004034e000

(XEN) 

(XEN) ESR_EL2: 00000000f2000001

(XEN) HPFAR_EL2: 0000000000000000

(XEN) FAR_EL2: 0000000000000000

(XEN) 

(XEN) Xen stack trace from sp=000002000030fd70:

(XEN) 000002000030fda0 0000020000265d38 0000000000000001 0000000000000000

(XEN) 0000000000000001 00000200002aef18 000002000030fdc0 00000200002787f4

(XEN) 0000000000000001 00000200002787ac 000002000030fe10 0000020000201f78

(XEN) 0000000000000001 0000000000000000 00000200002f0d38 00000200002dccf8

(XEN) 000002000030fe10 0000020000201f50 0000000000000001 00000200002c1358

(XEN) 000002000030fe40 00000200002dc92c 0000000000000001 00000200002b3000

(XEN) 00000000c0000000 00000200002bee58 0000000000000000 00000200002001bc

(XEN) 0000000040200000 fffffe0040000000 0000000048000000 0000000000000000

(XEN) 0000020000400000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000

(XEN) 0000000000000000 0000000000000000

(XEN) Xen call trace:

(XEN) [<0000020000265ce4>] update_identity_mapping+0x90/0x94 (PC)

(XEN) [<0000020000265cac>] update_identity_mapping+0x58/0x94 (LR)

(XEN) [<0000020000265d38>] arch_cpu_up+0x30/0x78

(XEN) [<00000200002787f4>] __cpu_up+0x80/0x1d0

(XEN) [<0000020000201f78>] cpu_up+0xc8/0xf8

(XEN) [<00000200002dc92c>] start_xen+0x8fc/0xcb0

(XEN) [<00000200002001bc>] head.o#primary_switched+0x10/0x30

(XEN) 

(XEN) 

(XEN) ****************************************

(XEN) Panic on CPU 0:

(XEN) Xen BUG at arch/arm/arm64/mm.c:120

(XEN) ****************************************

(XEN) 

(XEN) Reboot in five seconds...
Julien Grall March 25, 2023, 12:04 p.m. UTC | #3
Hi Bertrand,

On 03/03/2023 10:35, Bertrand Marquis wrote:
> Hi Julien,
> 
>> On 2 Mar 2023, at 15:59, Julien Grall <julien@xen.org> wrote:
>>
>> From: Julien Grall <jgrall@amazon.com>
>>
>> In follow-up patches we will need to have part of Xen identity mapped in
>> order to safely switch the TTBR.
>>
>> On some platform, the identity mapping may have to start at 0. If we always
>> keep the identity region mapped, NULL pointer dereference would lead to
>> access to valid mapping.
>>
>> It would be possible to relocate Xen to avoid clashing with address 0.
>> However the identity mapping is only meant to be used in very limited
>> places. Therefore it would be better to keep the identity region invalid
>> for most of the time.
>>
>> Two new external helpers are introduced:
>>     - arch_setup_page_tables() will setup the page-tables so it is
>>       easy to create the mapping afterwards.
>>     - update_identity_mapping() will create/remove the identity mapping
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> In Arm internal CI this patch (or maybe an other in the serie) made one
> of our test crash on qemu-arm64.

Thanks for the report. I managed  to reproduce it by tweaking the QEMU 
command line option I was using:

42sh> qemu/build/qemu-system-aarch64 -machine virt,gic-version=3 
-machine virtualization=true -cpu cortex-a57 -smp 4 -m 2048 -serial 
mon:stdio -serial null -nographic -kernel xen/xen/xen

The problem is in patch #2 because I didn't adjust the address of the 
vmap/frametable areas. So they effectively are still right in the middle 
of the reserved region for identity mapping.

I will update patch #2. I am also thinking to add a check in 
xen_pt_update() to ensure no-one can create a non 1:1 mapping in the 
reserved area for identity mapping.

Cheers,
diff mbox series

Patch

diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 6d507da0d44d..28481393e98f 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -10,6 +10,7 @@  obj-y += entry.o
 obj-y += head.o
 obj-y += insn.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
+obj-y += mm.o
 obj-y += smc.o
 obj-y += smpboot.o
 obj-y += traps.o
diff --git a/xen/arch/arm/arm64/mm.c b/xen/arch/arm/arm64/mm.c
new file mode 100644
index 000000000000..56b9e9b8d3ef
--- /dev/null
+++ b/xen/arch/arm/arm64/mm.c
@@ -0,0 +1,130 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <xen/init.h>
+#include <xen/mm.h>
+
+#include <asm/setup.h>
+
+/* Override macros from asm/page.h to make them work with mfn_t */
+#undef virt_to_mfn
+#define virt_to_mfn(va) _mfn(__virt_to_mfn(va))
+
+static DEFINE_PAGE_TABLE(xen_first_id);
+static DEFINE_PAGE_TABLE(xen_second_id);
+static DEFINE_PAGE_TABLE(xen_third_id);
+
+/*
+ * The identity mapping may start at physical address 0. So we don't want
+ * to keep it mapped longer than necessary.
+ *
+ * When this is called, we are still using the boot_pgtable.
+ *
+ * We need to prepare the identity mapping for both the boot page tables
+ * and runtime page tables.
+ *
+ * The logic to create the entry is slightly different because Xen may
+ * be running at a different location at runtime.
+ */
+static void __init prepare_boot_identity_mapping(void)
+{
+    paddr_t id_addr = virt_to_maddr(_start);
+    lpae_t pte;
+    DECLARE_OFFSETS(id_offsets, id_addr);
+
+    /*
+     * We will be re-using the boot ID tables. They may not have been
+     * zeroed but they should be unlinked. So it is fine to use
+     * clear_page().
+     */
+    clear_page(boot_first_id);
+    clear_page(boot_second_id);
+    clear_page(boot_third_id);
+
+    if ( id_offsets[0] >= IDENTITY_MAPPING_AREA_NR_L0 )
+        panic("Cannot handle ID mapping above 2TB\n");
+
+    /* Link first ID table */
+    pte = mfn_to_xen_entry(virt_to_mfn(boot_first_id), MT_NORMAL);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&boot_pgtable[id_offsets[0]], pte);
+
+    /* Link second ID table */
+    pte = mfn_to_xen_entry(virt_to_mfn(boot_second_id), MT_NORMAL);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&boot_first_id[id_offsets[1]], pte);
+
+    /* Link third ID table */
+    pte = mfn_to_xen_entry(virt_to_mfn(boot_third_id), MT_NORMAL);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&boot_second_id[id_offsets[2]], pte);
+
+    /* The mapping in the third table will be created at a later stage */
+}
+
+static void __init prepare_runtime_identity_mapping(void)
+{
+    paddr_t id_addr = virt_to_maddr(_start);
+    lpae_t pte;
+    DECLARE_OFFSETS(id_offsets, id_addr);
+
+    if ( id_offsets[0] >= IDENTITY_MAPPING_AREA_NR_L0 )
+        panic("Cannot handle ID mapping above 2TB\n");
+
+    /* Link first ID table */
+    pte = pte_of_xenaddr((vaddr_t)xen_first_id);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&xen_pgtable[id_offsets[0]], pte);
+
+    /* Link second ID table */
+    pte = pte_of_xenaddr((vaddr_t)xen_second_id);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&xen_first_id[id_offsets[1]], pte);
+
+    /* Link third ID table */
+    pte = pte_of_xenaddr((vaddr_t)xen_third_id);
+    pte.pt.table = 1;
+    pte.pt.xn = 0;
+
+    write_pte(&xen_second_id[id_offsets[2]], pte);
+
+    /* The mapping in the third table will be created at a later stage */
+}
+
+void __init arch_setup_page_tables(void)
+{
+    prepare_boot_identity_mapping();
+    prepare_runtime_identity_mapping();
+}
+
+void update_identity_mapping(bool enable)
+{
+    paddr_t id_addr = virt_to_maddr(_start);
+    int rc;
+
+    if ( enable )
+        rc = map_pages_to_xen(id_addr, maddr_to_mfn(id_addr), 1,
+                              PAGE_HYPERVISOR_RX);
+    else
+        rc = destroy_xen_mappings(id_addr, id_addr + PAGE_SIZE);
+
+    BUG_ON(rc);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/include/asm/arm32/mm.h b/xen/arch/arm/include/asm/arm32/mm.h
index 8bfc906e7178..856f2dbec4ad 100644
--- a/xen/arch/arm/include/asm/arm32/mm.h
+++ b/xen/arch/arm/include/asm/arm32/mm.h
@@ -18,6 +18,10 @@  static inline bool arch_mfns_in_directmap(unsigned long mfn, unsigned long nr)
 
 bool init_domheap_mappings(unsigned int cpu);
 
+static inline void arch_setup_page_tables(void)
+{
+}
+
 #endif /* __ARM_ARM32_MM_H__ */
 
 /*
diff --git a/xen/arch/arm/include/asm/arm64/mm.h b/xen/arch/arm/include/asm/arm64/mm.h
index aa2adac63189..e0bd23a6ed0c 100644
--- a/xen/arch/arm/include/asm/arm64/mm.h
+++ b/xen/arch/arm/include/asm/arm64/mm.h
@@ -1,6 +1,8 @@ 
 #ifndef __ARM_ARM64_MM_H__
 #define __ARM_ARM64_MM_H__
 
+extern DEFINE_PAGE_TABLE(xen_pgtable);
+
 /*
  * On ARM64, all the RAM is currently direct mapped in Xen.
  * Hence return always true.
@@ -10,6 +12,17 @@  static inline bool arch_mfns_in_directmap(unsigned long mfn, unsigned long nr)
     return true;
 }
 
+void arch_setup_page_tables(void);
+
+/*
+ * Enable/disable the identity mapping in the live page-tables (i.e.
+ * the one pointed by TTBR_EL2).
+ *
+ * Note that nested call (e.g. enable=true, enable=true) is not
+ * supported.
+ */
+void update_identity_mapping(bool enable);
+
 #endif /* __ARM_ARM64_MM_H__ */
 
 /*
diff --git a/xen/arch/arm/include/asm/config.h b/xen/arch/arm/include/asm/config.h
index e388462c23d1..f02733e40a87 100644
--- a/xen/arch/arm/include/asm/config.h
+++ b/xen/arch/arm/include/asm/config.h
@@ -179,6 +179,8 @@ 
 
 #else /* ARM_64 */
 
+#define IDENTITY_MAPPING_AREA_NR_L0  4
+
 #define VMAP_VIRT_START  GB(1)
 #define VMAP_VIRT_SIZE   GB(1)
 
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index a926f30a2be4..66b27f2b57c1 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -166,6 +166,17 @@  u32 device_tree_get_u32(const void *fdt, int node,
 int map_range_to_domain(const struct dt_device_node *dev,
                         u64 addr, u64 len, void *data);
 
+extern DEFINE_BOOT_PAGE_TABLE(boot_pgtable);
+
+#ifdef CONFIG_ARM_64
+extern DEFINE_BOOT_PAGE_TABLE(boot_first_id);
+#endif
+extern DEFINE_BOOT_PAGE_TABLE(boot_second_id);
+extern DEFINE_BOOT_PAGE_TABLE(boot_third_id);
+
+/* Find where Xen will be residing at runtime and return a PT entry */
+lpae_t pte_of_xenaddr(vaddr_t);
+
 extern const char __ro_after_init_start[], __ro_after_init_end[];
 
 struct init_info
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 9263fedc3b7d..265bc082567e 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -93,7 +93,7 @@  DEFINE_BOOT_PAGE_TABLE(boot_third);
 
 #ifdef CONFIG_ARM_64
 #define HYP_PT_ROOT_LEVEL 0
-static DEFINE_PAGE_TABLE(xen_pgtable);
+DEFINE_PAGE_TABLE(xen_pgtable);
 static DEFINE_PAGE_TABLE(xen_first);
 #define THIS_CPU_PGTABLE xen_pgtable
 #else
@@ -388,7 +388,7 @@  void flush_page_to_ram(unsigned long mfn, bool sync_icache)
         invalidate_icache();
 }
 
-static inline lpae_t pte_of_xenaddr(vaddr_t va)
+lpae_t pte_of_xenaddr(vaddr_t va)
 {
     paddr_t ma = va + phys_offset;
 
@@ -495,6 +495,8 @@  void __init setup_pagetables(unsigned long boot_phys_offset)
 
     phys_offset = boot_phys_offset;
 
+    arch_setup_page_tables();
+
 #ifdef CONFIG_ARM_64
     pte = pte_of_xenaddr((uintptr_t)xen_first);
     pte.pt.table = 1;