@@ -19,6 +19,7 @@ void mte_clear_page_tags(void *addr, size_t size);
#define PG_mte_tagged PG_arch_2
void mte_sync_tags(pte_t *ptep, pte_t pte);
+void mte_copy_page_tags(void *kto, const void *kfrom);
void flush_mte_state(void);
#else
@@ -29,6 +30,9 @@ void flush_mte_state(void);
static inline void mte_sync_tags(pte_t *ptep, pte_t pte)
{
}
+static inline void mte_copy_page_tags(void *kto, const void *kfrom)
+{
+}
static inline void flush_mte_state(void)
{
}
@@ -5,6 +5,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/page.h>
.arch armv8.5-a+memtag
@@ -21,3 +22,21 @@ SYM_FUNC_START(mte_clear_page_tags)
cbnz x1, 1b
ret
SYM_FUNC_END(mte_clear_page_tags)
+
+/*
+ * Copy the tags from the source page to the destination one
+ * x0 - address of the destination page
+ * x1 - address of the source page
+ */
+SYM_FUNC_START(mte_copy_page_tags)
+ mov x2, x0
+ mov x3, x1
+ multitag_transfer_size x5, x6
+1: ldgm x4, [x3]
+ stgm x4, [x2]
+ add x2, x2, x5
+ add x3, x3, x5
+ tst x2, #(PAGE_SIZE - 1)
+ b.ne 1b
+2:
+SYM_FUNC_END(mte_copy_page_tags)
@@ -6,16 +6,26 @@
* Copyright (C) 2012 ARM Ltd.
*/
+#include <linux/bitops.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
+#include <asm/mte.h>
void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
- struct page *page = virt_to_page(kto);
+ struct page *to_page = virt_to_page(kto);
+ struct page *from_page = virt_to_page(kfrom);
+
copy_page(kto, kfrom);
- flush_dcache_page(page);
+ if (system_supports_mte() &&
+ test_bit(PG_mte_tagged, &from_page->flags)) {
+ mte_copy_page_tags(kto, kfrom);
+ set_bit(PG_mte_tagged, &to_page->flags);
+ }
+ flush_dcache_page(to_page);
}
EXPORT_SYMBOL_GPL(__cpu_copy_user_page);