Skip to content

Commit aac5072

Browse files
committed
Add unit test for remote resume
1 parent a8b65f4 commit aac5072

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

tests/unit/remote.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,126 @@ extern int test_many_calls()
320320
fork2.vmcall("test_many_calls");
321321
REQUIRE(fork2.return_value() == 42000);
322322
}
323+
324+
TEST_CASE("Remote resume", "[Remote]")
325+
{
326+
const auto storage_binary = build_and_load(R"M(
327+
extern long write(int, const void*, unsigned long);
328+
#include <stdio.h>
329+
#include <string.h>
330+
__asm__(".global storage_wait_paused\n"
331+
".type storage_wait_paused, @function\n"
332+
"storage_wait_paused:\n"
333+
".cfi_startproc\n"
334+
" mov $0x10002, %eax\n"
335+
" out %eax, $0\n"
336+
" wrfsbase %rdi\n"
337+
" ret\n"
338+
".cfi_endproc\n");
339+
extern size_t storage_wait_paused(void** ptr);
340+
341+
int main() {
342+
while (1) {
343+
void* p = NULL;
344+
size_t len = storage_wait_paused(&p);
345+
strcpy((char*)p, "Data from storage");
346+
}
347+
return 1234;
348+
}
349+
)M", "-Wl,-Ttext-segment=0x40400000");
350+
351+
// Extract storage remote symbols
352+
const std::string command = "objcopy -w --extract-symbol --strip-symbol=!remote* --strip-symbol=* " + storage_binary.first + " storage.syms";
353+
FILE* f = popen(command.c_str(), "r");
354+
if (f == nullptr) {
355+
throw std::runtime_error("Unable to extract remote symbols");
356+
}
357+
pclose(f);
358+
359+
const auto main_binary = build_and_load(R"M(
360+
#include <stdio.h>
361+
#include <string.h>
362+
__asm__(".global remote_resume\n"
363+
".type remote_resume, @function\n"
364+
"remote_resume:\n"
365+
" mov $0x10001, %eax\n"
366+
" out %eax, $0\n"
367+
" ret\n");
368+
extern long remote_resume(void* data, size_t len);
369+
long test_remote() {
370+
for (int i = 0; i < 100; i++) {
371+
char buffer[8192];
372+
remote_resume(buffer, sizeof(buffer));
373+
if (strcmp(buffer, "Data from storage") == 0) {
374+
continue;
375+
}
376+
return 1;
377+
}
378+
return 2345;
379+
}
380+
int main() {
381+
return test_remote();
382+
}
383+
)M",
384+
"-Wl,--just-symbols=storage.syms");
385+
386+
static bool is_waiting = false;
387+
tinykvm::Machine::install_unhandled_syscall_handler(
388+
[] (tinykvm::vCPU& cpu, unsigned syscall_number) {
389+
switch (syscall_number) {
390+
case 0x10001: { // remote_resume
391+
// Remember buffer address and length values
392+
const uint64_t src = cpu.registers().rdi;
393+
const uint64_t len = cpu.registers().rsi;
394+
395+
cpu.machine().ipre_remote_resume_now(false,
396+
[src, len] (tinykvm::Machine& m) {
397+
m.copy_to_guest(m.registers().rdi, &src, sizeof(src));
398+
m.registers().rax = len;
399+
});
400+
return;
401+
}
402+
case 0x10002: // wait_for_storage_task_paused
403+
cpu.stop();
404+
is_waiting = true;
405+
return;
406+
}
407+
throw std::runtime_error("Unhandled syscall in remote resume test: " + std::to_string(syscall_number));
408+
});
409+
tinykvm::Machine storage { storage_binary.second, {
410+
.max_mem = 16ULL << 20, // MB
411+
.vmem_base_address = 1ULL << 30, // 1GB
412+
} };
413+
storage.setup_linux({"storage"}, env);
414+
storage.run(4.0f);
415+
storage.registers().rip += 2; // Skip OUT instruction
416+
REQUIRE(is_waiting);
417+
418+
tinykvm::Machine machine { main_binary.second, {
419+
.max_mem = MAX_MEMORY
420+
} };
421+
machine.setup_linux({"main"}, env);
422+
423+
machine.remote_connect(storage);
424+
REQUIRE(machine.has_remote());
425+
426+
machine.run(4.0f);
427+
REQUIRE(machine.return_value() == 2345);
428+
REQUIRE(!machine.is_remote_connected());
429+
REQUIRE(machine.remote_connection_count() == 100);
430+
431+
// Create a fork
432+
machine.prepare_copy_on_write();
433+
tinykvm::Machine fork(machine, {
434+
.max_mem = MAX_MEMORY,
435+
.max_cow_mem = MAX_COWMEM,
436+
.split_hugepages = true
437+
});
438+
REQUIRE(fork.has_remote());
439+
440+
// Test remote resume
441+
fork.vmcall("test_remote");
442+
REQUIRE(fork.return_value() == 2345);
443+
REQUIRE(!fork.is_remote_connected());
444+
REQUIRE(fork.remote_connection_count() == 100);
445+
}

0 commit comments

Comments
 (0)