1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Tests for bootm routines
4  *
5  * Copyright 2020 Google LLC
6  */
7 
8 #include <bootm.h>
9 #include <env.h>
10 #include <asm/global_data.h>
11 #include <test/test.h>
12 #include <test/ut.h>
13 
14 DECLARE_GLOBAL_DATA_PTR;
15 
16 #define BOOTM_TEST(_name, _flags)	UNIT_TEST(_name, _flags, bootm)
17 
18 enum {
19 	BUF_SIZE	= 1024,
20 };
21 
22 #define CONSOLE_STR	"console=/dev/ttyS0"
23 
24 /* Test cmdline processing where nothing happens */
bootm_test_nop(struct unit_test_state * uts)25 static int bootm_test_nop(struct unit_test_state *uts)
26 {
27 	char buf[BUF_SIZE];
28 
29 	/* This tests relies on GD_FLG_SILENT not being set */
30 	gd->flags &= ~GD_FLG_SILENT;
31 	env_set("silent_linux", NULL);
32 
33 	*buf = '\0';
34 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_ALL));
35 	ut_asserteq_str("", buf);
36 
37 	strcpy(buf, "test");
38 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_ALL));
39 	ut_asserteq_str("test", buf);
40 
41 	return 0;
42 }
43 BOOTM_TEST(bootm_test_nop, 0);
44 
45 /* Test cmdline processing when out of space */
bootm_test_nospace(struct unit_test_state * uts)46 static int bootm_test_nospace(struct unit_test_state *uts)
47 {
48 	char buf[BUF_SIZE];
49 
50 	/* This tests relies on GD_FLG_SILENT not being set */
51 	gd->flags &= ~GD_FLG_SILENT;
52 
53 	/* Zero buffer size */
54 	*buf = '\0';
55 	ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 0, BOOTM_CL_ALL));
56 
57 	/* Buffer string not terminated */
58 	memset(buf, 'a', BUF_SIZE);
59 	ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_ALL));
60 
61 	/* Not enough space to copy string */
62 	memset(buf, '\0', BUF_SIZE);
63 	memset(buf, 'a', BUF_SIZE / 2);
64 	ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_ALL));
65 
66 	/* Just enough space */
67 	memset(buf, '\0', BUF_SIZE);
68 	memset(buf, 'a', BUF_SIZE / 2 - 1);
69 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_ALL));
70 
71 	return 0;
72 }
73 BOOTM_TEST(bootm_test_nospace, 0);
74 
75 /* Test silent processing */
bootm_test_silent(struct unit_test_state * uts)76 static int bootm_test_silent(struct unit_test_state *uts)
77 {
78 	char buf[BUF_SIZE];
79 
80 	/* This tests relies on GD_FLG_SILENT not being set */
81 	gd->flags &= ~GD_FLG_SILENT;
82 
83 	/* 'silent_linux' not set should do nothing */
84 	env_set("silent_linux", NULL);
85 	strcpy(buf, CONSOLE_STR);
86 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
87 	ut_asserteq_str(CONSOLE_STR, buf);
88 
89 	ut_assertok(env_set("silent_linux", "no"));
90 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
91 	ut_asserteq_str(CONSOLE_STR, buf);
92 
93 	ut_assertok(env_set("silent_linux", "yes"));
94 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
95 	ut_asserteq_str("console=ttynull", buf);
96 
97 	/* Empty buffer should still add the string */
98 	*buf = '\0';
99 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
100 	ut_asserteq_str("console=ttynull", buf);
101 
102 	/* Check nothing happens when do_silent is false */
103 	*buf = '\0';
104 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, 0));
105 	ut_asserteq_str("", buf);
106 
107 	/* Not enough space */
108 	*buf = '\0';
109 	ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 15, BOOTM_CL_SILENT));
110 
111 	/* Just enough space */
112 	*buf = '\0';
113 	ut_assertok(bootm_process_cmdline(buf, 16, BOOTM_CL_SILENT));
114 
115 	/* add at end */
116 	strcpy(buf, "something");
117 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
118 	ut_asserteq_str("something console=ttynull", buf);
119 
120 	/* change at start */
121 	strcpy(buf, CONSOLE_STR " something");
122 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SILENT));
123 	ut_asserteq_str("console=ttynull something", buf);
124 
125 	return 0;
126 }
127 BOOTM_TEST(bootm_test_silent, 0);
128 
129 /* Test substitution processing */
bootm_test_subst(struct unit_test_state * uts)130 static int bootm_test_subst(struct unit_test_state *uts)
131 {
132 	char buf[BUF_SIZE];
133 
134 	/* try with an unset variable */
135 	ut_assertok(env_set("var", NULL));
136 	strcpy(buf, "some${var}thing");
137 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
138 	ut_asserteq_str("something", buf);
139 
140 	/* Replace with shorter string */
141 	ut_assertok(env_set("var", "bb"));
142 	strcpy(buf, "some${var}thing");
143 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
144 	ut_asserteq_str("somebbthing", buf);
145 
146 	/* Replace with same-length string */
147 	ut_assertok(env_set("var", "abc"));
148 	strcpy(buf, "some${var}thing");
149 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
150 	ut_asserteq_str("someabcthing", buf);
151 
152 	/* Replace with longer string */
153 	ut_assertok(env_set("var", "abcde"));
154 	strcpy(buf, "some${var}thing");
155 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
156 	ut_asserteq_str("someabcdething", buf);
157 
158 	/* Check it is case sensitive */
159 	ut_assertok(env_set("VAR", NULL));
160 	strcpy(buf, "some${VAR}thing");
161 	ut_assertok(bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
162 	ut_asserteq_str("something", buf);
163 
164 	/* Check too long - need 12 bytes for each string */
165 	strcpy(buf, "some${var}thing");
166 	ut_asserteq(-ENOSPC,
167 		    bootm_process_cmdline(buf, 12 * 2 - 1, BOOTM_CL_SUBST));
168 
169 	/* Check just enough space */
170 	strcpy(buf, "some${var}thing");
171 	ut_assertok(bootm_process_cmdline(buf, 16 * 2, BOOTM_CL_SUBST));
172 	ut_asserteq_str("someabcdething", buf);
173 
174 	/*
175 	 * Check the substition string being too long. This results in a string
176 	 * of 12 (13 bytes). We need enough space for that plus the original
177 	 * "a${var}c" string of 9 bytes. So 12 + 9 = 21 bytes.
178 	 */
179 	ut_assertok(env_set("var", "1234567890"));
180 	strcpy(buf, "a${var}c");
181 	ut_asserteq(-ENOSPC, bootm_process_cmdline(buf, 21, BOOTM_CL_SUBST));
182 
183 	strcpy(buf, "a${var}c");
184 	ut_asserteq(0, bootm_process_cmdline(buf, 22, BOOTM_CL_SUBST));
185 
186 	/* Check multiple substitutions */
187 	ut_assertok(env_set("bvar", NULL));
188 	ut_assertok(env_set("var", "abc"));
189 	strcpy(buf, "some${var}thing${bvar}else");
190 	ut_asserteq(0, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
191 	ut_asserteq_str("someabcthingelse", buf);
192 
193 	/* Check multiple substitutions */
194 	ut_assertok(env_set("bvar", "123"));
195 	strcpy(buf, "some${var}thing${bvar}else");
196 	ut_asserteq(0, bootm_process_cmdline(buf, BUF_SIZE, BOOTM_CL_SUBST));
197 	ut_asserteq_str("someabcthing123else", buf);
198 
199 	return 0;
200 }
201 BOOTM_TEST(bootm_test_subst, 0);
202 
203 /* Test silent processing in the bootargs variable */
bootm_test_silent_var(struct unit_test_state * uts)204 static int bootm_test_silent_var(struct unit_test_state *uts)
205 {
206 	ut_assertok(env_set("var", NULL));
207 	env_set("bootargs", NULL);
208 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SUBST));
209 	ut_assertnull(env_get("bootargs"));
210 
211 	ut_assertok(env_set("bootargs", "some${var}thing"));
212 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SUBST));
213 	ut_asserteq_str("something", env_get("bootargs"));
214 
215 	return 0;
216 }
217 BOOTM_TEST(bootm_test_silent_var, 0);
218 
219 /* Test substitution processing in the bootargs variable */
bootm_test_subst_var(struct unit_test_state * uts)220 static int bootm_test_subst_var(struct unit_test_state *uts)
221 {
222 	ut_assertok(env_set("silent_linux", "yes"));
223 	ut_assertok(env_set("bootargs", NULL));
224 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT));
225 	ut_asserteq_str("console=ttynull", env_get("bootargs"));
226 
227 	ut_assertok(env_set("var", "abc"));
228 	ut_assertok(env_set("bootargs", "some${var}thing"));
229 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_SILENT));
230 	ut_asserteq_str("some${var}thing console=ttynull", env_get("bootargs"));
231 
232 	return 0;
233 }
234 BOOTM_TEST(bootm_test_subst_var, 0);
235 
236 /* Test substitution and silent console processing in the bootargs variable */
bootm_test_subst_both(struct unit_test_state * uts)237 static int bootm_test_subst_both(struct unit_test_state *uts)
238 {
239 	ut_assertok(env_set("silent_linux", "yes"));
240 	env_set("bootargs", NULL);
241 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL));
242 	ut_asserteq_str("console=ttynull", env_get("bootargs"));
243 
244 	ut_assertok(env_set("bootargs", "some${var}thing " CONSOLE_STR));
245 	ut_assertok(env_set("var", "1234567890"));
246 	ut_assertok(bootm_process_cmdline_env(BOOTM_CL_ALL));
247 	ut_asserteq_str("some1234567890thing console=ttynull", env_get("bootargs"));
248 
249 	return 0;
250 }
251 BOOTM_TEST(bootm_test_subst_both, 0);
252