xref: /linux/tools/testing/selftests/kexec/test_kexec_jump.c (revision 785cdec46e9227f9433884ed3b436471e944007c)
1*7615b94bSDavid Woodhouse #include <unistd.h>
2*7615b94bSDavid Woodhouse #include <errno.h>
3*7615b94bSDavid Woodhouse #include <stdio.h>
4*7615b94bSDavid Woodhouse #include <stdlib.h>
5*7615b94bSDavid Woodhouse #include <linux/kexec.h>
6*7615b94bSDavid Woodhouse #include <linux/reboot.h>
7*7615b94bSDavid Woodhouse #include <sys/reboot.h>
8*7615b94bSDavid Woodhouse #include <sys/syscall.h>
9*7615b94bSDavid Woodhouse 
10*7615b94bSDavid Woodhouse asm(
11*7615b94bSDavid Woodhouse     "  .code64\n"
12*7615b94bSDavid Woodhouse     "  .data\n"
13*7615b94bSDavid Woodhouse     "purgatory_start:\n"
14*7615b94bSDavid Woodhouse 
15*7615b94bSDavid Woodhouse     // Trigger kexec debug exception handling
16*7615b94bSDavid Woodhouse     "  int3\n"
17*7615b94bSDavid Woodhouse 
18*7615b94bSDavid Woodhouse     // Set load address for next time
19*7615b94bSDavid Woodhouse     "  leaq purgatory_start_b(%rip), %r11\n"
20*7615b94bSDavid Woodhouse     "  movq %r11, 8(%rsp)\n"
21*7615b94bSDavid Woodhouse 
22*7615b94bSDavid Woodhouse     // Back to Linux
23*7615b94bSDavid Woodhouse     "  ret\n"
24*7615b94bSDavid Woodhouse 
25*7615b94bSDavid Woodhouse     // Same again
26*7615b94bSDavid Woodhouse     "purgatory_start_b:\n"
27*7615b94bSDavid Woodhouse 
28*7615b94bSDavid Woodhouse     // Trigger kexec debug exception handling
29*7615b94bSDavid Woodhouse     "  int3\n"
30*7615b94bSDavid Woodhouse 
31*7615b94bSDavid Woodhouse     // Set load address for next time
32*7615b94bSDavid Woodhouse     "  leaq purgatory_start(%rip), %r11\n"
33*7615b94bSDavid Woodhouse     "  movq %r11, 8(%rsp)\n"
34*7615b94bSDavid Woodhouse 
35*7615b94bSDavid Woodhouse     // Back to Linux
36*7615b94bSDavid Woodhouse     "  ret\n"
37*7615b94bSDavid Woodhouse 
38*7615b94bSDavid Woodhouse     "purgatory_end:\n"
39*7615b94bSDavid Woodhouse     ".previous"
40*7615b94bSDavid Woodhouse );
41*7615b94bSDavid Woodhouse extern char purgatory_start[], purgatory_end[];
42*7615b94bSDavid Woodhouse 
43*7615b94bSDavid Woodhouse int main (void)
44*7615b94bSDavid Woodhouse {
45*7615b94bSDavid Woodhouse         struct kexec_segment segment = {};
46*7615b94bSDavid Woodhouse 	int ret;
47*7615b94bSDavid Woodhouse 
48*7615b94bSDavid Woodhouse 	segment.buf = purgatory_start;
49*7615b94bSDavid Woodhouse 	segment.bufsz = purgatory_end - purgatory_start;
50*7615b94bSDavid Woodhouse 	segment.mem = (void *)0x400000;
51*7615b94bSDavid Woodhouse 	segment.memsz = 0x1000;
52*7615b94bSDavid Woodhouse 	ret = syscall(__NR_kexec_load, 0x400000, 1, &segment, KEXEC_PRESERVE_CONTEXT);
53*7615b94bSDavid Woodhouse 	if (ret) {
54*7615b94bSDavid Woodhouse 		perror("kexec_load");
55*7615b94bSDavid Woodhouse 		exit(1);
56*7615b94bSDavid Woodhouse 	}
57*7615b94bSDavid Woodhouse 
58*7615b94bSDavid Woodhouse 	ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC);
59*7615b94bSDavid Woodhouse 	if (ret) {
60*7615b94bSDavid Woodhouse 		perror("kexec reboot");
61*7615b94bSDavid Woodhouse 		exit(1);
62*7615b94bSDavid Woodhouse 	}
63*7615b94bSDavid Woodhouse 
64*7615b94bSDavid Woodhouse 	ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC);
65*7615b94bSDavid Woodhouse 	if (ret) {
66*7615b94bSDavid Woodhouse 		perror("kexec reboot");
67*7615b94bSDavid Woodhouse 		exit(1);
68*7615b94bSDavid Woodhouse 	}
69*7615b94bSDavid Woodhouse 	printf("Success\n");
70*7615b94bSDavid Woodhouse 	return 0;
71*7615b94bSDavid Woodhouse }
72*7615b94bSDavid Woodhouse 
73