159 lines
6.3 KiB
C
159 lines
6.3 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ This program is free software; you can redistribute it and/or modify │
|
|
│ it under the terms of the GNU General Public License as published by │
|
|
│ the Free Software Foundation; version 2 of the License. │
|
|
│ │
|
|
│ This program is distributed in the hope that it will be useful, but │
|
|
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
|
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
|
│ General Public License for more details. │
|
|
│ │
|
|
│ You should have received a copy of the GNU General Public License │
|
|
│ along with this program; if not, write to the Free Software │
|
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
|
│ 02110-1301 USA │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/log/check.h"
|
|
#include "libc/macros.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/testlib/ezbench.h"
|
|
#include "libc/testlib/testlib.h"
|
|
#include "tool/build/lib/memory.h"
|
|
#include "tool/build/lib/pml4t.h"
|
|
|
|
struct Unmapped {
|
|
size_t i;
|
|
struct UnmappedEntry {
|
|
void *addr;
|
|
size_t size;
|
|
} p[8];
|
|
};
|
|
|
|
struct Unmapped unmapped;
|
|
uint64_t *pt2, *pt3, *pt4;
|
|
pml4t_t cr3;
|
|
|
|
void *NewPage(void) {
|
|
void *p;
|
|
p = tmemalign(4096, 4096);
|
|
CHECK_ALIGNED(4096, p);
|
|
memset(p, 0, 4096);
|
|
return p;
|
|
}
|
|
|
|
void FreePage(void *p) {
|
|
tfree(p);
|
|
}
|
|
|
|
int FakeMunmap(void *addr, size_t size) {
|
|
return 0;
|
|
}
|
|
|
|
int MockMunmap(void *addr, size_t size) {
|
|
CHECK_LT(unmapped.i, ARRAYLEN(unmapped.p));
|
|
unmapped.p[unmapped.i].addr = addr;
|
|
unmapped.p[unmapped.i].size = size;
|
|
unmapped.i++;
|
|
return 0;
|
|
}
|
|
|
|
void SetUp(void) {
|
|
memset(cr3, 0, sizeof(cr3));
|
|
}
|
|
|
|
void TearDown(void) {
|
|
unmapped.i = 0;
|
|
FreePml4t(cr3, -0x800000000000, 0x800000000000, FreePage, FakeMunmap);
|
|
}
|
|
|
|
TEST(pml4t, testHighestAddress) {
|
|
ASSERT_NE(-1,
|
|
RegisterPml4t(cr3, 0x7fffffffe000, 0x3133700000, 0x2000, NewPage));
|
|
ASSERT_TRUE(IsValidPage(cr3[255]));
|
|
pt2 = UnmaskPageAddr(cr3[255]);
|
|
ASSERT_TRUE(IsValidPage(pt2[511]));
|
|
pt3 = UnmaskPageAddr(pt2[511]);
|
|
ASSERT_TRUE(IsValidPage(pt3[511]));
|
|
pt4 = UnmaskPageAddr(pt3[511]);
|
|
ASSERT_TRUE(IsValidPage(pt4[510]));
|
|
ASSERT_TRUE(IsValidPage(pt4[511]));
|
|
EXPECT_EQ(0x3133700000, UnmaskPageAddr(pt4[510]));
|
|
EXPECT_EQ(0x3133701000, UnmaskPageAddr(pt4[511]));
|
|
}
|
|
|
|
TEST(pml4t, testLowestAddress) {
|
|
ASSERT_NE(-1,
|
|
RegisterPml4t(cr3, -0x800000000000, 0x31337000, 0x2000, NewPage));
|
|
ASSERT_TRUE(IsValidPage(cr3[256]));
|
|
pt2 = UnmaskPageAddr(cr3[256]);
|
|
ASSERT_TRUE(IsValidPage(pt2[0]));
|
|
pt3 = UnmaskPageAddr(pt2[0]);
|
|
ASSERT_TRUE(IsValidPage(pt3[0]));
|
|
pt4 = UnmaskPageAddr(pt3[0]);
|
|
ASSERT_TRUE(IsValidPage(pt4[0]));
|
|
ASSERT_TRUE(IsValidPage(pt4[1]));
|
|
}
|
|
|
|
TEST(pml4t, testOverlapsExistingRegistration_overwritesRegistration) {
|
|
ASSERT_NE(-1,
|
|
RegisterPml4t(cr3, 0x7fffffffe000, 0x31337000, 0x1000, NewPage));
|
|
ASSERT_TRUE(IsValidPage(cr3[255]));
|
|
pt2 = UnmaskPageAddr(cr3[255]);
|
|
ASSERT_TRUE(IsValidPage(pt2[511]));
|
|
pt3 = UnmaskPageAddr(pt2[511]);
|
|
ASSERT_TRUE(IsValidPage(pt3[511]));
|
|
pt4 = UnmaskPageAddr(pt3[511]);
|
|
EXPECT_TRUE(IsValidPage(pt4[510]));
|
|
EXPECT_EQ(0x31337000, UnmaskPageAddr(pt4[510]));
|
|
ASSERT_NE(-1, RegisterPml4t(cr3, 0x7fffffffe000, 0x31337000 + 0x1000, 0x1000,
|
|
NewPage));
|
|
EXPECT_TRUE(IsValidPage(pt4[510]));
|
|
EXPECT_EQ(0x31337000 + 0x1000, UnmaskPageAddr(pt4[510]));
|
|
}
|
|
|
|
TEST(pml4t, testFindPml4t_holeTooSmall_skipsOver) {
|
|
ASSERT_NE(-1, RegisterPml4t(cr3, 0x700000000, 0, 0x1000, NewPage));
|
|
ASSERT_NE(-1, RegisterPml4t(cr3, 0x700005000, 0, 0x1000, NewPage));
|
|
ASSERT_EQ(0x700001000, FindPml4t(cr3, 0x700000000, 0x01000));
|
|
ASSERT_EQ(0x700006000, FindPml4t(cr3, 0x700000000, 0x10000));
|
|
}
|
|
|
|
TEST(pml4t, testFindPml4t_bigAllocation) {
|
|
ASSERT_EQ(0x00200000, FindPml4t(cr3, 0x00200000, 0x00400000));
|
|
ASSERT_EQ(0x00201000, FindPml4t(cr3, 0x00201000, 0x00400000));
|
|
ASSERT_EQ(0xff200000, FindPml4t(cr3, 0xff200000, 0x00400000));
|
|
ASSERT_EQ(0xff201000, FindPml4t(cr3, 0xff201000, 0x00400000));
|
|
}
|
|
|
|
TEST(pml4t, testFreePmlt) {
|
|
ASSERT_NE(-1, RegisterPml4t(cr3, 0x000005000, 0x123000, 0x2000, NewPage));
|
|
ASSERT_NE(-1, RegisterPml4t(cr3, 0x000000000, 0x321000, 0x1000, NewPage));
|
|
ASSERT_NE(-1, FreePml4t(cr3, -0x800000000000, 0x800000000000, FreePage,
|
|
MockMunmap));
|
|
ASSERT_EQ(2, unmapped.i);
|
|
EXPECT_EQ(0x321000, unmapped.p[0].addr);
|
|
EXPECT_EQ(0x1000, unmapped.p[0].size);
|
|
EXPECT_EQ(0x123000, unmapped.p[1].addr);
|
|
EXPECT_EQ(0x2000, unmapped.p[1].size);
|
|
}
|
|
|
|
BENCH(pml4t, bench) {
|
|
EZBENCH2("RegisterPml4t 1mb fresh",
|
|
FreePml4t(cr3, -0x800000000000, 0x800000000000, free, FakeMunmap),
|
|
RegisterPml4t(cr3, 0x00100000, 0x31337000, 0x00100000, MallocPage));
|
|
EZBENCH2("RegisterPml4t 1gb fresh",
|
|
FreePml4t(cr3, -0x800000000000, 0x800000000000, free, FakeMunmap),
|
|
RegisterPml4t(cr3, 0x40000000, 0x31337000, 0x40000000, MallocPage));
|
|
EZBENCH2("RegisterPml4t 1mb overwrite", donothing,
|
|
RegisterPml4t(cr3, 0x00100000, 0x31337000, 0x00100000, MallocPage));
|
|
EZBENCH2("RegisterPml4t 1gb overwrite", donothing,
|
|
RegisterPml4t(cr3, 0x40000000, 0x31337000, 0x40000000, MallocPage));
|
|
FreePml4t(cr3, -0x800000000000, 0x800000000000, free, FakeMunmap);
|
|
}
|