SH4A続き。前回は64MBページ8枚で512MBをマップした。今度はKB単位のページ
でマップしてみよう。
アドレス変換のエリアはU0,P0,P3の3エリアでそれぞれ
U0 2GB
P0 2GB
P3 512MB
だ。なので2GBをマップできる用意をすればいい。
これをページサイズ4KBでマップすると2GB/4KBで524288エントリ必要だ。
それぞれのエントリを32bitで済ませば2MB。64bit使えば4MBがそのために必要。
2GBほとんどを使うアプリケーションでなければ、2GBのうちマップされるのは
数少なくなるため、昔からここはPTEエントリ自体も必要になった時にページを
確保するという戦略になっている。
ページサイズがnKBで、ここに登録されるエントリのサイズがmByteとすると、
一つのページをページテーブルにすると、PTE/PAGEはn * 1024 / m。それぞれの
PTEがnKBをマップするので、一つのページテーブルでn * 1024 * (n * 1024 / m)
をマップできることになる。
これで2GBをマップするには2 * 1024 * m / (n * n)のページテーブルページが
あればいい。
NetBSDではページサイズに4KB、PTEのサイズが4Byteなので、512個。2KBの領域
をスタティックにとっている。
SH4Aの場合、ページサイズを8KBにすればキャッシュエイリアス問題が生じなく
て都合がいい。そしてPTEにはPTELとPTEAの両方を設定できるといいので8Byte
がいいだろう。
ページサイズ8KB PTEサイズ8Bとなると、ページテーブルページのエントリは256。
そのエントリにはPTEが入るので、256*8で2KB必要。
いろいろな例。
これはNetBSD
/*
Page size: 4KB
Page table entry size: 4B
4MB / page table page.
512 page table page entry required. (total 2048byte)
page offset:
....................|||||||||||| 11 10 9 8 7 6 5 4 3 2 1 0 [0x00000fff] 4095
page table page offset. shift=12 mask=0x3ff
..........||||||||||............ 21 20 19 18 17 16 15 14 13 12 [0x003ff000] 4190208
page table page index. shift=22, mask=0x1ff
.|||||||||...................... 30 29 28 27 26 25 24 23 22 [0x7fc00000] 2143289344
*/
#define PAGE_SIZE 0x1000
#define PTE_SIZE 4
#define PTP_OFFSET 0x3ff000
#define PTP_OFFSET_SHIFT 12
#define PTP_OFFSET_MASK 0x3ff
#define PTP_INDEX 0x7fc00000
#define PTP_INDEX_SHIFT 22
#define PTP_INDEX_MASK 0x1ff
#define PTP_ENTRY 512
これはSH4Aに理想的じゃないかと思っているセッティング。
/*
Page size: 8KB
Page table entry size: 8B
8MB / page table page.
256 page table page entry required. (total 2048byte)
page offset:
...................||||||||||||| 12 11 10 9 8 7 6 5 4 3 2 1 0 [0x00001fff] 8191
page table page offset. shift=13 mask=0x3ff
.........||||||||||............. 22 21 20 19 18 17 16 15 14 13 [0x007fe000] 8380416
page table page index. shift=23, mask=0xff
.||||||||....................... 30 29 28 27 26 25 24 23 [0x7f800000] 2139095040
*/
#define PAGE_SIZE 0x2000
#define PTE_SIZE 8
#define PTP_OFFSET 0x7fe000
#define PTP_OFFSET_SHIFT 13
#define PTP_OFFSET_MASK 0x3ff
#define PTP_INDEX 0x7f800000
#define PTP_INDEX_SHIFT 23
#define PTP_INDEX_MASK 0xff
#define PTP_ENTRY 256
今日日このくらいの方がいいのでは?という挑戦的なセッティング。
/*
Page size: 64KB
Page table entry size: 8B
512MB / page table page.
4 page table page entry required. (total 32byte)
page offset:
................|||||||||||||||| 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 [0x0000ffff] 65535
page table page offset. shift=16 mask=0x1fff
...|||||||||||||................ 28 27 26 25 24 23 22 21 20 19 18 17 16 [0x1fff0000] 536805376
page table page index. shift=29, mask=0x3
.||............................. 30 29 [0x60000000] 1610612736
*/
#define PAGE_SIZE 0x10000
#define PTE_SIZE 8
#define PTP_OFFSET 0x1fff0000
#define PTP_OFFSET_SHIFT 16
#define PTP_OFFSET_MASK 0x1fff
#define PTP_INDEX 0x60000000
#define PTP_INDEX_SHIFT 29
#define PTP_INDEX_MASK 0x3
#define PTP_ENTRY 4
この64KBページならむしろ、PTPはスタティックに64KB*4=256KBとってしまって
もいいかも。そしてページテーブルページが絶対メモリの中にあるならかなり
見通しがいい。
これらの#defineはSHIFTとMASKがどうしてもプリプロセッサでできないので、
これらの設定を吐き出すプログラムを先に作りました。
#include <sys/types.h>
#include <stdio.h>
#define __BEGIN_MACRO do {
#define __END_MACRO } while (/*CONSTCOND*/0)
#define __bitdisp(a, s, e, m, c) \
__BEGIN_MACRO \
u_int32_t __j, __j1; \
int __i, __s, __e, __n; \
__n = sizeof(typeof(a)) * NBBY - 1; \
__j1 = 1 << __n; \
__e = e ? e : __n; \
__s = s; \
for (__j = __j1, __i = __n; __j > 0; __j >>=1, __i--) { \
if (__i > __e || __i < __s) { \
printf("%c", a & __j ? '+' : '-'); \
} else { \
printf("%c", a & __j ? '|' : '.'); \
} \
} \
if (m) { \
printf("[%s]", (char*)m); \
} \
if (c) { \
for (__j = __j1, __i = __n; __j > 0; __j >>=1, __i--) { \
if (!(__i > __e || __i < __s) && (a & __j)) { \
printf(" %d", __i); \
} \
} \
} \
printf(" [0x%08x] %d", a, a); \
printf("\n"); \
__END_MACRO
#define bitdisp(a) __bitdisp((a), 0, 0, 0, 1)
int
main (int argc, const char *argv[])
{
if (argc < 3)
return 0;
uint32_t n = atoi (argv[1]); // Page size (unit KB)
uint32_t m = atoi (argv[2]); // PTE size (unit B)
printf ("/*\n");
printf ("Page size: %dKB\nPage table entry size: %dB\n", n, m);
uint32_t page_table_mapsize = n * n / m;
uint32_t page_table_page_entry = 2 * 1024 * m / (n * n);
printf ("%dMB / page table page.\n", page_table_mapsize);
printf ("%d page table page entry required. (total %dbyte)\n",
page_table_page_entry, page_table_page_entry * m);
printf ("page offset:\n");
uint32_t PAGE_SIZE = n * 1024;
uint32_t PTE_SIZE = m;
#define PAGE_OFFSET (PAGE_SIZE - 1)
// size of 1 page table page can map.
#define PTP_MAPSIZE (PAGE_SIZE / PTE_SIZE * PAGE_SIZE )
#define PTP_OFFSET ((PTP_MAPSIZE - 1) & ~PAGE_OFFSET)
#define PTP_INDEX (~(PTP_MAPSIZE - 1) & ~0x80000000)
bitdisp (PAGE_OFFSET);
uint32_t ptp_offset_shift = ffs(PTP_OFFSET) - 1;
printf ("page table page offset. shift=%d mask=0x%x\n", ptp_offset_shift,
PTP_OFFSET >> ptp_offset_shift);
bitdisp (PTP_OFFSET);
uint32_t ptp_shift = ffs(PTP_INDEX) - 1;
printf ("page table page index. shift=%d, mask=0x%x\n", ptp_shift,
PTP_INDEX >> ptp_shift);
bitdisp (PTP_INDEX);
printf ("*/\n");
printf ("#define\tPAGE_SIZE\t\t0x%x\n", PAGE_SIZE);
printf ("#define\tPTE_SIZE\t\t%d\n", PTE_SIZE);
printf ("#define\tPTP_OFFSET\t\t0x%x\n", PTP_OFFSET);
printf ("#define\tPTP_OFFSET_SHIFT\t%d\n", ptp_offset_shift);
printf ("#define\tPTP_OFFSET_MASK\t\t0x%x\n", PTP_OFFSET >> ptp_offset_shift);
printf ("#define\tPTP_INDEX\t\t0x%x\n", PTP_INDEX);
printf ("#define\tPTP_INDEX_SHIFT\t\t%d\n", ptp_shift);
printf ("#define\tPTP_INDEX_MASK\t\t0x%x\n", PTP_INDEX >> ptp_shift);
printf ("#define\tPTP_ENTRY\t\t%d\n", page_table_page_entry);
return 0;
}
