summaryrefslogtreecommitdiff
path: root/arch/arm64/mm/ktext.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/mm/ktext.c')
-rw-r--r--arch/arm64/mm/ktext.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/arch/arm64/mm/ktext.c b/arch/arm64/mm/ktext.c
index dd7512171296..2c212fb02594 100644
--- a/arch/arm64/mm/ktext.c
+++ b/arch/arm64/mm/ktext.c
@@ -14,6 +14,7 @@
#include <asm/cacheflush.h>
#include <asm/ktext.h>
#include <asm/memory.h>
+#include <asm/pgalloc.h>
struct pgtables *pgtables[MAX_NUMNODES] = {
[0 ... MAX_NUMNODES - 1] = &pgtable_node0,
@@ -118,7 +119,7 @@ void ktext_replication_patch_alternative(__le32 *src, int nr_inst)
}
}
-/* Allocate memory for the replicated kernel texts. */
+/* Allocate page tables and memory for the replicated kernel texts. */
void __init ktext_replication_init(void)
{
size_t size = _etext - _stext;
@@ -149,5 +150,44 @@ void __init ktext_replication_init(void)
memcpy(kernel_texts[nid], _stext, size);
caches_clean_inval_pou((u64)kernel_texts[nid],
(u64)kernel_texts[nid] + size);
+
+ /* Allocate the pagetables for this node */
+ pgtables[nid] = memblock_alloc_node(sizeof(*pgtables[0]),
+ PGD_SIZE, nid);
+
+ /* Copy initial swapper page directory */
+ memcpy(pgtables[nid]->swapper_pg_dir, swapper_pg_dir, PGD_SIZE);
+ }
+}
+
+void ktext_replication_set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
+{
+ unsigned long idx = pgdp - swapper_pg_dir;
+ int nid;
+
+ if (WARN_ON_ONCE(idx >= PTRS_PER_PGD) ||
+ WARN_ON_ONCE(idx == pgd_index((phys_addr_t)KERNEL_START)))
+ return;
+
+ for_each_node(nid) {
+ if (pgtables[nid]->swapper_pg_dir == swapper_pg_dir)
+ continue;
+
+ WRITE_ONCE(pgtables[nid]->swapper_pg_dir[idx], pgd);
+ }
+}
+
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+void __init ktext_replication_init_tramp(void)
+{
+ int nid;
+
+ for_each_node(nid) {
+ /* Nothing to do for node 0 */
+ if (pgtables[nid]->tramp_pg_dir == tramp_pg_dir)
+ continue;
+
+ memcpy(pgtables[nid]->tramp_pg_dir, tramp_pg_dir, PGD_SIZE);
}
}
+#endif