Skip to content

Commit 1a8dd51

Browse files
committed
2MB-align the heap to avoid initial pagetable split
1 parent a50514a commit 1a8dd51

File tree

3 files changed

+76
-26
lines changed

3 files changed

+76
-26
lines changed

lib/tinykvm/machine_elf.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
166166
this->m_stack_address = this->m_heap_address + STACK_SIZE;
167167
this->m_brk_address = this->m_stack_address;
168168
this->m_brk_end_address = this->m_stack_address + BRK_MAX;
169+
this->m_brk_end_address = (this->m_brk_end_address + 0x1FFFFF) & ~0x1FFFFF; // 2MB align
169170
this->m_heap_address = this->m_brk_end_address;
170171

171172
/* Make sure mmap starts at a sane offset */
@@ -182,6 +183,7 @@ void Machine::elf_loader(std::string_view binary, const MachineOptions& options)
182183
(void*) m_brk_end_address);
183184
printf("* Stack is at %p -> %p\n", (void*) (m_stack_address - STACK_SIZE),
184185
(void*) (m_stack_address));
186+
printf("* Heap starts at %p\n", (void*) m_heap_address);
185187
this->fds().set_verbose(options.verbose_loader);
186188
}
187189
}

tests/unit/elf.cpp

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,95 @@
11
#include <catch2/catch_test_macros.hpp>
22

33
#include <tinykvm/machine.hpp>
4+
#include <tinykvm/rsp_client.hpp>
45
extern std::vector<uint8_t> load_file(const std::string& filename);
56
static const uint64_t MAX_MEMORY = 8ul << 20; /* 8MB */
67
static const std::vector<std::string> env{
7-
"LC_TYPE=C", "LC_ALL=C", "USER=root"};
8+
"LC_TYPE=C", "LC_ALL=C", "USER=root"};
9+
static const std::vector<uint8_t> ld_linux_x86_64_so
10+
= load_file("/lib64/ld-linux-x86-64.so.2");
811

912
TEST_CASE("Initialize KVM", "[Initialize]")
1013
{
11-
// Create KVM file descriptors etc.
12-
tinykvm::Machine::init();
14+
tinykvm::Machine::init();
1315
}
1416

15-
TEST_CASE("Verify Rust ELF", "[ELF]")
17+
TEST_CASE("Verify dynamic Rust ELF", "[ELF]")
1618
{
17-
const auto binary = load_file("../unit/elf/rust.elf");
19+
std::string guest_filename
20+
= std::string(get_current_dir_name()) + "/../unit/elf/rust.elf";
21+
// Make filename absolute
22+
char abs_path[PATH_MAX];
23+
realpath(guest_filename.c_str(), abs_path);
24+
guest_filename = abs_path;
1825

19-
tinykvm::Machine machine { binary, { .max_mem = MAX_MEMORY } };
26+
tinykvm::Machine machine { ld_linux_x86_64_so, {
27+
.max_mem = MAX_MEMORY,
28+
.verbose_loader = true,
29+
.executable_heap = true,
30+
.mmap_backed_files = true
31+
} };
32+
// Allow opening all files (for dynamic linker)
33+
machine.fds().set_open_readable_callback(
34+
[&] (std::string& path) -> bool {
35+
return true;
36+
});
37+
// Load the dynamic linker instead of the program
38+
std::vector<std::string> args;
39+
args.push_back("/lib64/ld-linux-x86-64.so.2");
40+
args.push_back(guest_filename);
2041
// We need to create a Linux environment for runtimes to work well
21-
machine.setup_linux({"verify"}, env);
42+
machine.setup_linux_system_calls();
43+
machine.setup_linux(args, env);
2244

23-
// Run for at most 4 seconds before giving up
24-
machine.run(4.0f);
45+
try {
46+
// Run for at most 4 seconds before giving up
47+
machine.run(4.0f);
48+
} catch (const std::exception& ex) {
49+
printf("Exception: %s\n", ex.what());
50+
if (getenv("GDB") != nullptr)
51+
{
52+
tinykvm::RSP server(guest_filename, machine, 2159);
53+
printf("Waiting 60s for remote GDB on port 2159...\n");
54+
auto client = server.accept(60);
55+
if (client) {
56+
printf("Now debugging rust.elf\n");
57+
while(client->process_one());
58+
}
59+
}
60+
}
2561

2662
REQUIRE(machine.return_value() == 231);
2763
}
2864

29-
TEST_CASE("Verify Rust ELF (himem)", "[ELF]")
65+
TEST_CASE("Verify dynamic Rust ELF (himem)", "[ELF]")
3066
{
31-
const auto binary = load_file("../unit/elf/rust.elf");
32-
33-
const uint64_t HIMEM = 128ULL << 30; /* 128GB */
34-
tinykvm::Machine machine{binary, {
35-
.max_mem = MAX_MEMORY,
36-
.dylink_address_hint = HIMEM + 0x200000,
37-
.vmem_base_address = HIMEM
38-
}};
39-
// We need to create a Linux environment for runtimes to work well
40-
machine.setup_linux({"verify"}, env);
41-
REQUIRE(machine.entry_address() > HIMEM);
42-
43-
// Run for at most 4 seconds before giving up
44-
machine.run(4.0f);
45-
46-
REQUIRE(machine.return_value() == 231);
67+
const uint64_t HIMEM = 128ULL << 30; /* 128GB */
68+
tinykvm::Machine machine{ld_linux_x86_64_so, {
69+
.max_mem = MAX_MEMORY,
70+
.dylink_address_hint = HIMEM + 0x200000,
71+
.vmem_base_address = HIMEM,
72+
.master_direct_memory_writes = true,
73+
.executable_heap = true,
74+
.mmap_backed_files = true
75+
}};
76+
// Use constrained working memory
77+
machine.prepare_copy_on_write(MAX_MEMORY);
78+
// Allow opening all files (for dynamic linker)
79+
machine.fds().set_open_readable_callback(
80+
[&] (std::string& path) -> bool {
81+
return true;
82+
});
83+
// Load the dynamic linker instead of the program
84+
std::vector<std::string> args;
85+
args.push_back("/lib64/ld-linux-x86-64.so.2");
86+
args.push_back(std::string(get_current_dir_name()) + "/../unit/elf/rust.elf");
87+
// We need to create a Linux environment for runtimes to work well
88+
machine.setup_linux(args, env);
89+
REQUIRE(machine.entry_address() > HIMEM);
90+
91+
// Run for at most 4 seconds before giving up
92+
machine.run(4.0f);
93+
94+
REQUIRE(machine.return_value() == 231);
4795
}

tests/unit/elf/rust.elf

-874 KB
Binary file not shown.

0 commit comments

Comments
 (0)