1/*
2 * POWER Data Stream Control Register (DSCR) fork exec test
3 *
4 * This testcase modifies the DSCR using mtspr, forks & execs and
5 * verifies that the child is using the changed DSCR using mfspr.
6 *
7 * When using the privilege state SPR, the instructions such as
8 * mfspr or mtspr are priviledged and the kernel emulates them
9 * for us. Instructions using problem state SPR can be exuecuted
10 * directly without any emulation if the HW supports them. Else
11 * they also get emulated by the kernel.
12 *
13 * Copyright 2012, Anton Blanchard, IBM Corporation.
14 * Copyright 2015, Anshuman Khandual, IBM Corporation.
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License version 2 as published
18 * by the Free Software Foundation.
19 */
20#include "dscr.h"
21
22static char prog[LEN_MAX];
23
24static void do_exec(unsigned long parent_dscr)
25{
26	unsigned long cur_dscr, cur_dscr_usr;
27
28	cur_dscr = get_dscr();
29	cur_dscr_usr = get_dscr_usr();
30
31	if (cur_dscr != parent_dscr) {
32		fprintf(stderr, "Parent DSCR %ld was not inherited "
33				"over exec (kernel value)\n", parent_dscr);
34		exit(1);
35	}
36
37	if (cur_dscr_usr != parent_dscr) {
38		fprintf(stderr, "Parent DSCR %ld was not inherited "
39				"over exec (user value)\n", parent_dscr);
40		exit(1);
41	}
42	exit(0);
43}
44
45int dscr_inherit_exec(void)
46{
47	unsigned long i, dscr = 0;
48	pid_t pid;
49
50	for (i = 0; i < COUNT; i++) {
51		dscr++;
52		if (dscr > DSCR_MAX)
53			dscr = 0;
54
55		if (dscr == get_default_dscr())
56			continue;
57
58		if (i % 2 == 0)
59			set_dscr_usr(dscr);
60		else
61			set_dscr(dscr);
62
63		/*
64		 * XXX: Force a context switch out so that DSCR
65		 * current value is copied into the thread struct
66		 * which is required for the child to inherit the
67		 * changed value.
68		 */
69		sleep(1);
70
71		pid = fork();
72		if (pid == -1) {
73			perror("fork() failed");
74			exit(1);
75		} else if (pid) {
76			int status;
77
78			if (waitpid(pid, &status, 0) == -1) {
79				perror("waitpid() failed");
80				exit(1);
81			}
82
83			if (!WIFEXITED(status)) {
84				fprintf(stderr, "Child didn't exit cleanly\n");
85				exit(1);
86			}
87
88			if (WEXITSTATUS(status) != 0) {
89				fprintf(stderr, "Child didn't exit cleanly\n");
90				return 1;
91			}
92		} else {
93			char dscr_str[16];
94
95			sprintf(dscr_str, "%ld", dscr);
96			execlp(prog, prog, "exec", dscr_str, NULL);
97			exit(1);
98		}
99	}
100	return 0;
101}
102
103int main(int argc, char *argv[])
104{
105	if (argc == 3 && !strcmp(argv[1], "exec")) {
106		unsigned long parent_dscr;
107
108		parent_dscr = atoi(argv[2]);
109		do_exec(parent_dscr);
110	} else if (argc != 1) {
111		fprintf(stderr, "Usage: %s\n", argv[0]);
112		exit(1);
113	}
114
115	strncpy(prog, argv[0], strlen(argv[0]));
116	return test_harness(dscr_inherit_exec, "dscr_inherit_exec_test");
117}
118