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