mbox series

[0/1] THP_SWAP support for ARM64 SoC with MTE

Message ID 20240322114136.61386-1-21cnbao@gmail.com (mailing list archive)
Headers show
Series THP_SWAP support for ARM64 SoC with MTE | expand

Message

Barry Song March 22, 2024, 11:41 a.m. UTC
From: Barry Song <v-songbaohua@oppo.com>

The patch has been extracted from the larger folios swap-in series [1],
incorporating some new modifications.

Introducing THP_SWAP support for ARM64 SoCs with MTE is essential, particularly
due to its significance for widely used ARM64 products in the market. Without
this support, Ryan's mTHP swap-out without splitting series won't operate
effectively on these SoCs.

Therefore, it's imperative for this update to be implemented sooner
rather than later.

There are a couple of differences with the code in [1]:
1. minor code cleanup, Ryan
2. always pass the first swap entry of a folio to arch_swap_restore, Ryan

[1] https://lore.kernel.org/linux-mm/20240304081348.197341-2-21cnbao@gmail.com/

Barry Song (1):
  arm64: mm: swap: support THP_SWAP on hardware with MTE

 arch/arm64/include/asm/pgtable.h | 19 ++------------
 arch/arm64/mm/mteswap.c          | 45 ++++++++++++++++++++++++++++++++
 include/linux/huge_mm.h          | 12 ---------
 include/linux/pgtable.h          |  2 +-
 mm/internal.h                    | 14 ++++++++++
 mm/memory.c                      |  2 +-
 mm/page_io.c                     |  2 +-
 mm/shmem.c                       |  2 +-
 mm/swap_slots.c                  |  2 +-
 mm/swapfile.c                    |  2 +-
 10 files changed, 67 insertions(+), 35 deletions(-)

Appendix

I also have a small test program specifically designed for running MTE
on a THP that I can share with those who are interested in this subject.

 /*
  * To be compiled with -march=armv8.5-a+memtag
  */
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/auxv.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 
 /*
  * From arch/arm64/include/uapi/asm/hwcap.h
  */
 #define HWCAP2_MTE              (1 << 18)
 
 /*
  * From arch/arm64/include/uapi/asm/mman.h
  */
 #define PROT_MTE                 0x20
 
 /*
  * From include/uapi/linux/prctl.h
  */
 #define PR_SET_TAGGED_ADDR_CTRL 55
 #define PR_GET_TAGGED_ADDR_CTRL 56
 # define PR_TAGGED_ADDR_ENABLE  (1UL << 0)
 # define PR_MTE_TCF_SHIFT       1
 # define PR_MTE_TCF_NONE        (0UL << PR_MTE_TCF_SHIFT)
 # define PR_MTE_TCF_SYNC        (1UL << PR_MTE_TCF_SHIFT)
 # define PR_MTE_TCF_ASYNC       (2UL << PR_MTE_TCF_SHIFT)
 # define PR_MTE_TCF_MASK        (3UL << PR_MTE_TCF_SHIFT)
 # define PR_MTE_TAG_SHIFT       3
 # define PR_MTE_TAG_MASK        (0xffffUL << PR_MTE_TAG_SHIFT)
 
 /*
  * Insert a random logical tag into the given pointer.
  */
 #define insert_random_tag(ptr) ({                       \
 		uint64_t __val;                                 \
 		asm("irg %0, %1" : "=r" (__val) : "r" (ptr));   \
 		__val;                                          \
 		})
 
 /*
  * Set the allocation tag on the destination address.
  */
 #define set_tag(tagged_addr) do {                                      \
 	asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
 } while (0)
 
 int main()
 {
 	unsigned char *a, *p[512];
 	unsigned long page_sz = 4 * 1024UL;
 	unsigned long mem_sz = 2 * 1024 * 1024UL;
 	unsigned long hwcap2 = getauxval(AT_HWCAP2);
 	int i;
 
 	if (!(hwcap2 & HWCAP2_MTE))
 		return EXIT_FAILURE;
 
 	if (prctl(PR_SET_TAGGED_ADDR_CTRL,
 				PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC |
 				(0xfffe << PR_MTE_TAG_SHIFT),
 				0, 0, 0)) {
 		perror("prctl() failed");
 		return EXIT_FAILURE;
 	}
 
 	a = mmap(0, mem_sz * 2, PROT_READ | PROT_WRITE,
 			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 	if (a == MAP_FAILED) {
 		perror("mmap() failed");
 		return EXIT_FAILURE;
 	}
 
 	/* make sure a is aligned with 2MiB THP */
 	a = (unsigned char *)(((unsigned long)a + mem_sz - 1) & ~(mem_sz - 1));
 	madvise(a, mem_sz, MADV_HUGEPAGE);
 	memset(a, 0x11, mem_sz);
 
 	if (mprotect(a, mem_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
 		perror("mprotect() failed");
 		return EXIT_FAILURE;
 	}
 
 	printf("set tag for each 4KiB page\n");
 	for (i = 0; i < 512; i++) {
 		p[i] = a + i * page_sz;
 		p[i] = (unsigned char *)insert_random_tag(p[i]);
 		set_tag(p[i]);
 		p[i][0] = 0x33;
 	}
 
 	printf("swap-out the whole THP\n");
 	madvise(a, mem_sz, MADV_PAGEOUT);
 
 	printf("swap-in each page of the original THP\n");
 	for (i = 0; i < 512; i++) {
 		if (p[i][0] != 0x33) {
 			printf("test fails, unmatched value after swap-in\n");
 			return EXIT_FAILURE;
 		}
 	}
 	printf("we should get here\n");
 
 	for (i = 0; i < 512; i++) {
 		printf("page :%d val: expect segment fault, is %02x\n", i, p[i][16]);
 	}
 
 	printf("we shouldn't get here\n");
 
 	return EXIT_FAILURE;
 }