1 // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 /*
3  * NVRAM Format as specified in PAPR
4  *
5  * Copyright 2013-2019 IBM Corp.
6  */
7 
8 #include <skiboot.h>
9 #include <nvram.h>
10 
11 struct chrp_nvram_hdr {
12 	uint8_t		sig;
13 	uint8_t		cksum;
14 	be16		len;
15 	char		name[12];
16 };
17 
18 static struct chrp_nvram_hdr *skiboot_part_hdr;
19 
20 #define NVRAM_SIG_FW_PRIV	0x51
21 #define NVRAM_SIG_SYSTEM	0x70
22 #define NVRAM_SIG_FREE		0x7f
23 
24 #define NVRAM_NAME_COMMON	"common"
25 #define NVRAM_NAME_FW_PRIV	"ibm,skiboot"
26 #define NVRAM_NAME_FREE		"wwwwwwwwwwww"
27 
28 /* 64k should be enough, famous last words... */
29 #define NVRAM_SIZE_COMMON	0x10000
30 
31 /* 4k should be enough, famous last words... */
32 #define NVRAM_SIZE_FW_PRIV	0x1000
33 
chrp_nv_cksum(struct chrp_nvram_hdr * hdr)34 static uint8_t chrp_nv_cksum(struct chrp_nvram_hdr *hdr)
35 {
36 	struct chrp_nvram_hdr h_copy = *hdr;
37 	uint8_t b_data, i_sum, c_sum;
38 	uint8_t *p = (uint8_t *)&h_copy;
39 	unsigned int nbytes = sizeof(h_copy);
40 
41 	h_copy.cksum = 0;
42 	for (c_sum = 0; nbytes; nbytes--) {
43 		b_data = *(p++);
44 		i_sum = c_sum + b_data;
45 		if (i_sum < c_sum)
46 			i_sum++;
47 		c_sum = i_sum;
48 	}
49 	return c_sum;
50 }
51 
nvram_format(void * nvram_image,uint32_t nvram_size)52 int nvram_format(void *nvram_image, uint32_t nvram_size)
53 {
54 	struct chrp_nvram_hdr *h;
55 	unsigned int offset = 0;
56 
57 	prerror("NVRAM: Re-initializing (size: 0x%08x)\n", nvram_size);
58 	memset(nvram_image, 0, nvram_size);
59 
60 	/* Create private partition */
61 	if (nvram_size - offset < NVRAM_SIZE_FW_PRIV)
62 		return -1;
63 	h = nvram_image + offset;
64 	h->sig = NVRAM_SIG_FW_PRIV;
65 	h->len = cpu_to_be16(NVRAM_SIZE_FW_PRIV >> 4);
66 	strcpy(h->name, NVRAM_NAME_FW_PRIV);
67 	h->cksum = chrp_nv_cksum(h);
68 	prlog(PR_DEBUG, "NVRAM: Created '%s' partition at 0x%08x"
69 	      " for size 0x%08x with cksum 0x%02x\n",
70 	      NVRAM_NAME_FW_PRIV, offset,
71 	      be16_to_cpu(h->len), h->cksum);
72 	offset += NVRAM_SIZE_FW_PRIV;
73 
74 	/* Create common partition */
75 	if (nvram_size - offset < NVRAM_SIZE_COMMON)
76 		return -1;
77 	h = nvram_image + offset;
78 	h->sig = NVRAM_SIG_SYSTEM;
79 	h->len = cpu_to_be16(NVRAM_SIZE_COMMON >> 4);
80 	strcpy(h->name, NVRAM_NAME_COMMON);
81 	h->cksum = chrp_nv_cksum(h);
82 	prlog(PR_DEBUG, "NVRAM: Created '%s' partition at 0x%08x"
83 	      " for size 0x%08x with cksum 0x%02x\n",
84 	      NVRAM_NAME_COMMON, offset,
85 	      be16_to_cpu(h->len), h->cksum);
86 	offset += NVRAM_SIZE_COMMON;
87 
88 	/* Create free space partition */
89 	if (nvram_size - offset < sizeof(struct chrp_nvram_hdr))
90 		return -1;
91 	h = nvram_image + offset;
92 	h->sig = NVRAM_SIG_FREE;
93 	h->len = cpu_to_be16((nvram_size - offset) >> 4);
94 	/* We have the full 12 bytes here */
95 	memcpy(h->name, NVRAM_NAME_FREE, 12);
96 	h->cksum = chrp_nv_cksum(h);
97 	prlog(PR_DEBUG, "NVRAM: Created '%s' partition at 0x%08x"
98 	      " for size 0x%08x with cksum 0x%02x\n",
99 	      NVRAM_NAME_FREE, offset, be16_to_cpu(h->len), h->cksum);
100 	return 0;
101 }
102 
103 /*
104  * Check that the nvram partition layout is sane and that it
105  * contains our required partitions. If not, we re-format the
106  * lot of it
107  */
nvram_check(void * nvram_image,const uint32_t nvram_size)108 int nvram_check(void *nvram_image, const uint32_t nvram_size)
109 {
110 	unsigned int offset = 0;
111 	bool found_common = false;
112 
113 	skiboot_part_hdr = NULL;
114 
115 	while (offset + sizeof(struct chrp_nvram_hdr) < nvram_size) {
116 		struct chrp_nvram_hdr *h = nvram_image + offset;
117 
118 		if (chrp_nv_cksum(h) != h->cksum) {
119 			prerror("NVRAM: Partition at offset 0x%x"
120 				" has bad checksum: 0x%02x vs 0x%02x\n",
121 				offset, h->cksum, chrp_nv_cksum(h));
122 			goto failed;
123 		}
124 		if (be16_to_cpu(h->len) < 1) {
125 			prerror("NVRAM: Partition at offset 0x%x"
126 				" has incorrect 0 length\n", offset);
127 			goto failed;
128 		}
129 
130 		if (h->sig == NVRAM_SIG_SYSTEM &&
131 		    strcmp(h->name, NVRAM_NAME_COMMON) == 0)
132 			found_common = true;
133 
134 		if (h->sig == NVRAM_SIG_FW_PRIV &&
135 		    strcmp(h->name, NVRAM_NAME_FW_PRIV) == 0)
136 			skiboot_part_hdr = h;
137 
138 		offset += be16_to_cpu(h->len) << 4;
139 		if (offset > nvram_size) {
140 			prerror("NVRAM: Partition at offset 0x%x"
141 				" extends beyond end of nvram !\n", offset);
142 			goto failed;
143 		}
144 	}
145 	if (!found_common) {
146 		prlog_once(PR_ERR, "NVRAM: Common partition not found !\n");
147 		goto failed;
148 	}
149 
150 	if (!skiboot_part_hdr) {
151 		prlog_once(PR_ERR, "NVRAM: Skiboot private partition not found !\n");
152 		goto failed;
153 	} else {
154 		/*
155 		 * The OF NVRAM format requires config strings to be NUL
156 		 * terminated and unused memory to be set to zero. Well behaved
157 		 * software should ensure this is done for us, but we should
158 		 * always check.
159 		 */
160 		const char *last_byte = (const char *) skiboot_part_hdr +
161 			be16_to_cpu(skiboot_part_hdr->len) * 16 - 1;
162 
163 		if (*last_byte != 0) {
164 			prerror("NVRAM: Skiboot private partition is not NUL terminated");
165 			goto failed;
166 		}
167 	}
168 
169 	prlog(PR_INFO, "NVRAM: Layout appears sane\n");
170 	assert(skiboot_part_hdr);
171 	return 0;
172  failed:
173 	return -1;
174 }
175 
find_next_key(const char * start,const char * end)176 static const char *find_next_key(const char *start, const char *end)
177 {
178 	/*
179 	 * Unused parts of the partition are set to NUL. If we hit two
180 	 * NULs in a row then we assume that we have hit the end of the
181 	 * partition.
182 	 */
183 	if (*start == 0)
184 		return NULL;
185 
186 	while (start < end) {
187 		if (*start == 0)
188 			return start + 1;
189 
190 		start++;
191 	}
192 
193 	return NULL;
194 }
195 
nvram_dangerous(const char * key)196 static void nvram_dangerous(const char *key)
197 {
198 	prlog(PR_ERR, " ___________________________________________________________\n");
199 	prlog(PR_ERR, "<  Dangerous NVRAM option: %s\n", key);
200 	prlog(PR_ERR, " -----------------------------------------------------------\n");
201 	prlog(PR_ERR, "                  \\                         \n");
202 	prlog(PR_ERR, "                   \\   WW                   \n");
203 	prlog(PR_ERR, "                      <^ \\___/|             \n");
204 	prlog(PR_ERR, "                       \\      /             \n");
205 	prlog(PR_ERR, "                        \\_  _/              \n");
206 	prlog(PR_ERR, "                          }{                 \n");
207 }
208 
209 
210 /*
211  * nvram_query_safe/dangerous() - Searches skiboot NVRAM partition
212  * for a key=value pair.
213  *
214  * Dangerous means it should only be used for testing as it may
215  * mask issues. Safe is ok for long term use.
216  *
217  * Returns a pointer to a NUL terminated string that contains the value
218  * associated with the given key.
219  */
__nvram_query(const char * key,bool dangerous)220 static const char *__nvram_query(const char *key, bool dangerous)
221 {
222 	const char *part_end, *start;
223 	int key_len = strlen(key);
224 
225 	assert(key);
226 
227 	if (!nvram_has_loaded()) {
228 		prlog(PR_DEBUG,
229 			"NVRAM: Query for '%s' must wait for NVRAM to load\n",
230 			key);
231 		if (!nvram_wait_for_load()) {
232 			prlog(PR_CRIT, "NVRAM: Failed to load\n");
233 			return NULL;
234 		}
235 	}
236 
237 	/*
238 	 * The running OS can modify the NVRAM as it pleases so we need to be
239 	 * a little paranoid and check that it's ok before we try parse it.
240 	 *
241 	 * NB: nvram_validate() can update skiboot_part_hdr
242 	 */
243 	if (!nvram_validate())
244 		return NULL;
245 
246 	assert(skiboot_part_hdr);
247 
248 	part_end = (const char *) skiboot_part_hdr
249 		+ be16_to_cpu(skiboot_part_hdr->len) * 16 - 1;
250 
251 	start = (const char *) skiboot_part_hdr
252 		+ sizeof(*skiboot_part_hdr);
253 
254 	if (!key_len) {
255 		prlog(PR_WARNING, "NVRAM: search key is empty!\n");
256 		return NULL;
257 	}
258 
259 	if (key_len > 32)
260 		prlog(PR_WARNING, "NVRAM: search key '%s' is longer than 32 chars\n", key);
261 
262 	while (start) {
263 		int remaining = part_end - start;
264 
265 		prlog(PR_TRACE, "NVRAM: '%s' (%lu)\n",
266 			start, strlen(start));
267 
268 		if (key_len + 1 > remaining)
269 			return NULL;
270 
271 		if (!strncmp(key, start, key_len) && start[key_len] == '=') {
272 			const char *value = &start[key_len + 1];
273 
274 			prlog(PR_DEBUG, "NVRAM: Searched for '%s' found '%s'\n",
275 				key, value);
276 
277 			if (dangerous)
278 				nvram_dangerous(start);
279 			return value;
280 		}
281 
282 		start = find_next_key(start, part_end);
283 	}
284 
285 	prlog(PR_DEBUG, "NVRAM: '%s' not found\n", key);
286 
287 	return NULL;
288 }
289 
nvram_query_safe(const char * key)290 const char *nvram_query_safe(const char *key)
291 {
292 	return __nvram_query(key, false);
293 }
294 
nvram_query_dangerous(const char * key)295 const char *nvram_query_dangerous(const char *key)
296 {
297 	return __nvram_query(key, true);
298 }
299 
300 /*
301  * nvram_query_eq_safe/dangerous() - Check if the given 'key' exists
302  * and is set to 'value'.
303  *
304  * Dangerous means it should only be used for testing as it may
305  * mask issues. Safe is ok for long term use.
306  *
307  * Note: Its an error to check for non-existence of a key
308  * by passing 'value == NULL' as a key's value can never be
309  * NULL in nvram.
310  */
__nvram_query_eq(const char * key,const char * value,bool dangerous)311 static bool __nvram_query_eq(const char *key, const char *value, bool dangerous)
312 {
313 	const char *s = __nvram_query(key, dangerous);
314 
315 	if (!s)
316 		return false;
317 
318 	assert(value != NULL);
319 	return !strcmp(s, value);
320 }
321 
nvram_query_eq_safe(const char * key,const char * value)322 bool nvram_query_eq_safe(const char *key, const char *value)
323 {
324 	return __nvram_query_eq(key, value, false);
325 }
326 
nvram_query_eq_dangerous(const char * key,const char * value)327 bool nvram_query_eq_dangerous(const char *key, const char *value)
328 {
329 	return __nvram_query_eq(key, value, true);
330 }
331 
332