Skip to content

Page tables implementation on ARC

abrodkin edited this page Sep 12, 2014 · 2 revisions

Very nice article that explains details of page table management in Linux kernel: https://www.kernel.org/doc/gorman/html/understand/understand006.html

PTRS_PER_PGD - Number of entries in Page Global Directory (PGD). On ARC we we implement only 2 levels of tables: PGD and Page Table Entry (PTE). So PMD table is effectively PTE table.

PTRS_PER_PTE - Number of entries in PTE table.

Based on sources below it's easy to calculate sizes of PGD and PTE tables:

Parameter / page size 4kB 8kB 16kB
Kernel config option ARC_PAGE_SIZE_4K ARC_PAGE_SIZE_8K ARC_PAGE_SIZE_16K
BITS_IN_PAGE 12 13 14
BITS_FOR_PTE 9 8 8
BITS_FOR_PGD 32 - 9 - 12 = 11 32 - 8 - 13 = 11 32 - 8 - 14 = 10
PTE table size (entries) 2^9 = 512 2^8 = 256 2^8 = 256
PTE table size (kB) 2kB 1kB 1kB
PGD table size (entries) 2^11 = 2048 2^11 = 2048 2^10 = 1024
PGD table size (kB) 8kB 8kB 4kB

Note that PTE tables are much smaller compared to corresponding page size. This is done intentionally as an optimization for speed.

Originally this was clarified on ELCE 2014 talk by Vineet Gupta - http://elinux.org/images/2/24/ARC_Linux_From_a_Tumbling_Toddler_to_a_Graduating_Teen.pdf

Basic concept is as follows (let's consider page size is 8kB):

  1. PTE table that occupies entire physical page covers 8kB/32-bit per entry = 2048 entries = 2048*8kB = 16Mb.

  2. Knowing that addresses used by a process are widely distributed there's no point in having that large blocks, most of mentioned 16Mb won't be used anyway.

  3. So we use smaller PTE tables. PTE table of 256 entries covers 2Mb of physical area.

  4. This saves us a lot of CPU cycles when zeroing PTE page (256 vs 2048 "ST 0, [mem]") on its allocation.

arch/arc/include/uapi/asm/page.h

/* PAGE_SHIFT determines the page size */
#if defined(CONFIG_ARC_PAGE_SIZE_16K)
#define PAGE_SHIFT 14
#elif defined(CONFIG_ARC_PAGE_SIZE_4K)
#define PAGE_SHIFT 12
#else
/*
 * Default 8k
 * done this way (instead of under CONFIG_ARC_PAGE_SIZE_8K) because adhoc
 * user code (busybox appletlib.h) expects PAGE_SHIFT to be defined w/o
 * using the correct uClibc header and in their build our autoconf.h is
 * not available
 */
#define PAGE_SHIFT 13
#endif

#ifdef __ASSEMBLY__
#define PAGE_SIZE	(1 << PAGE_SHIFT)
#define PAGE_OFFSET	(0x80000000)
#else
#define PAGE_SIZE	(1UL << PAGE_SHIFT)	/* Default 8K */
#define PAGE_OFFSET	(0x80000000UL)	/* Kernel starts at 2G onwards */
#endif

#define PAGE_MASK	(~(PAGE_SIZE-1))
arch/arc/include/asm/pgtable.h

/****************************************************************
 * Page Table Lookup split
 *
 * We implement 2 tier paging and since this is all software, we are free
 * to customize the span of a PGD / PTE entry to suit us
 *
 *			32 bit virtual address
 * -------------------------------------------------------
 * | BITS_FOR_PGD    |  BITS_FOR_PTE    |  BITS_IN_PAGE  |
 * -------------------------------------------------------
 *       |                  |                |
 *       |                  |                --> off in page frame
 *       |		    |
 *       |                  ---> index into Page Table
 *       |
 *       ----> index into Page Directory
 */

#define BITS_IN_PAGE	PAGE_SHIFT

/* Optimal Sizing of Pg Tbl - based on MMU page size */
#if defined(CONFIG_ARC_PAGE_SIZE_8K)
#define BITS_FOR_PTE	8
#elif defined(CONFIG_ARC_PAGE_SIZE_16K)
#define BITS_FOR_PTE	8
#elif defined(CONFIG_ARC_PAGE_SIZE_4K)
#define BITS_FOR_PTE	9
#endif

#define BITS_FOR_PGD	(32 - BITS_FOR_PTE - BITS_IN_PAGE)

#define PGDIR_SHIFT	(BITS_FOR_PTE + BITS_IN_PAGE)
#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)	/* vaddr span, not PDG sz */
#define PGDIR_MASK	(~(PGDIR_SIZE-1))

#ifdef __ASSEMBLY__
#define	PTRS_PER_PTE	(1 << BITS_FOR_PTE)
#define	PTRS_PER_PGD	(1 << BITS_FOR_PGD)
#else
#define	PTRS_PER_PTE	(1UL << BITS_FOR_PTE)
#define	PTRS_PER_PGD	(1UL << BITS_FOR_PGD)
#endif
Clone this wiki locally