Blame view

common/bootstage.c 11.6 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
3a608ca01   Simon Glass   bootstage: Implem...
2
3
  /*
   * Copyright (c) 2011, Google Inc. All rights reserved.
3a608ca01   Simon Glass   bootstage: Implem...
4
5
6
7
8
9
   */
  
  
  /*
   * This module records the progress of boot and arbitrary commands, and
   * permits accurate timestamping of each.
3a608ca01   Simon Glass   bootstage: Implem...
10
11
12
   */
  
  #include <common.h>
b08c8c487   Masahiro Yamada   libfdt: move head...
13
  #include <linux/libfdt.h>
fb7db41cd   Simon Glass   bootstage: Allow ...
14
15
  #include <malloc.h>
  #include <linux/compiler.h>
3a608ca01   Simon Glass   bootstage: Implem...
16
17
  
  DECLARE_GLOBAL_DATA_PTR;
03ecac314   Simon Glass   bootstage: Use re...
18
  enum {
d69bb0ecb   Simon Glass   bootstage: Provid...
19
  	RECORD_COUNT = CONFIG_VAL(BOOTSTAGE_RECORD_COUNT),
03ecac314   Simon Glass   bootstage: Use re...
20
  };
3a608ca01   Simon Glass   bootstage: Implem...
21
22
  struct bootstage_record {
  	ulong time_us;
094e06a52   Simon Glass   bootstage: Export...
23
  	uint32_t start_us;
3a608ca01   Simon Glass   bootstage: Implem...
24
25
26
27
  	const char *name;
  	int flags;		/* see enum bootstage_flags */
  	enum bootstage_id id;
  };
b383d6c05   Simon Glass   bootstage: Conver...
28
  struct bootstage_data {
03ecac314   Simon Glass   bootstage: Use re...
29
  	uint rec_count;
b383d6c05   Simon Glass   bootstage: Conver...
30
  	uint next_id;
03ecac314   Simon Glass   bootstage: Use re...
31
  	struct bootstage_record record[RECORD_COUNT];
b383d6c05   Simon Glass   bootstage: Conver...
32
  };
3a608ca01   Simon Glass   bootstage: Implem...
33

fcf509b80   Simon Glass   bootstage: Add fe...
34
35
36
  enum {
  	BOOTSTAGE_VERSION	= 0,
  	BOOTSTAGE_MAGIC		= 0xb00757a3,
b8bcaa3ad   Simon Glass   Add function to p...
37
  	BOOTSTAGE_DIGITS	= 9,
fcf509b80   Simon Glass   bootstage: Add fe...
38
39
40
41
42
43
44
45
  };
  
  struct bootstage_hdr {
  	uint32_t version;	/* BOOTSTAGE_VERSION */
  	uint32_t count;		/* Number of records */
  	uint32_t size;		/* Total data size (non-zero if valid) */
  	uint32_t magic;		/* Unused */
  };
150678a58   Doug Anderson   bootstage: Copy b...
46
47
  int bootstage_relocate(void)
  {
b383d6c05   Simon Glass   bootstage: Conver...
48
  	struct bootstage_data *data = gd->bootstage;
150678a58   Doug Anderson   bootstage: Copy b...
49
50
51
52
53
54
  	int i;
  
  	/*
  	 * Duplicate all strings.  They may point to an old location in the
  	 * program .text section that can eventually get trashed.
  	 */
03ecac314   Simon Glass   bootstage: Use re...
55
56
57
58
  	debug("Relocating %d records
  ", data->rec_count);
  	for (i = 0; i < data->rec_count; i++)
  		data->record[i].name = strdup(data->record[i].name);
150678a58   Doug Anderson   bootstage: Copy b...
59
60
61
  
  	return 0;
  }
03ecac314   Simon Glass   bootstage: Use re...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  struct bootstage_record *find_id(struct bootstage_data *data,
  				 enum bootstage_id id)
  {
  	struct bootstage_record *rec;
  	struct bootstage_record *end;
  
  	for (rec = data->record, end = rec + data->rec_count; rec < end;
  	     rec++) {
  		if (rec->id == id)
  			return rec;
  	}
  
  	return NULL;
  }
  
  struct bootstage_record *ensure_id(struct bootstage_data *data,
  				   enum bootstage_id id)
  {
  	struct bootstage_record *rec;
  
  	rec = find_id(data, id);
  	if (!rec && data->rec_count < RECORD_COUNT) {
  		rec = &data->record[data->rec_count++];
  		rec->id = id;
  		return rec;
  	}
  
  	return rec;
  }
3a608ca01   Simon Glass   bootstage: Implem...
91
  ulong bootstage_add_record(enum bootstage_id id, const char *name,
094e06a52   Simon Glass   bootstage: Export...
92
  			   int flags, ulong mark)
3a608ca01   Simon Glass   bootstage: Implem...
93
  {
b383d6c05   Simon Glass   bootstage: Conver...
94
  	struct bootstage_data *data = gd->bootstage;
3a608ca01   Simon Glass   bootstage: Implem...
95
  	struct bootstage_record *rec;
3a608ca01   Simon Glass   bootstage: Implem...
96
97
  
  	if (flags & BOOTSTAGEF_ALLOC)
b383d6c05   Simon Glass   bootstage: Conver...
98
  		id = data->next_id++;
3a608ca01   Simon Glass   bootstage: Implem...
99

03ecac314   Simon Glass   bootstage: Use re...
100
101
102
103
104
105
106
107
  	/* Only record the first event for each */
  	rec = find_id(data, id);
  	if (!rec && data->rec_count < RECORD_COUNT) {
  		rec = &data->record[data->rec_count++];
  		rec->time_us = mark;
  		rec->name = name;
  		rec->flags = flags;
  		rec->id = id;
3a608ca01   Simon Glass   bootstage: Implem...
108
109
110
111
  	}
  
  	/* Tell the board about this progress */
  	show_boot_progress(flags & BOOTSTAGEF_ERROR ? -id : id);
cbcd6970a   Simon Glass   bootstage: Fix up...
112

3a608ca01   Simon Glass   bootstage: Implem...
113
114
115
116
117
118
  	return mark;
  }
  
  
  ulong bootstage_mark(enum bootstage_id id)
  {
094e06a52   Simon Glass   bootstage: Export...
119
  	return bootstage_add_record(id, NULL, 0, timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
120
121
122
123
  }
  
  ulong bootstage_error(enum bootstage_id id)
  {
094e06a52   Simon Glass   bootstage: Export...
124
125
  	return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR,
  				    timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
126
127
128
129
130
131
132
133
  }
  
  ulong bootstage_mark_name(enum bootstage_id id, const char *name)
  {
  	int flags = 0;
  
  	if (id == BOOTSTAGE_ID_ALLOC)
  		flags = BOOTSTAGEF_ALLOC;
cbcd6970a   Simon Glass   bootstage: Fix up...
134

094e06a52   Simon Glass   bootstage: Export...
135
  	return bootstage_add_record(id, name, flags, timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
136
  }
fb7db41cd   Simon Glass   bootstage: Allow ...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  ulong bootstage_mark_code(const char *file, const char *func, int linenum)
  {
  	char *str, *p;
  	__maybe_unused char *end;
  	int len = 0;
  
  	/* First work out the length we need to allocate */
  	if (linenum != -1)
  		len = 11;
  	if (func)
  		len += strlen(func);
  	if (file)
  		len += strlen(file);
  
  	str = malloc(len + 1);
  	p = str;
  	end = p + len;
  	if (file)
  		p += snprintf(p, end - p, "%s,", file);
  	if (linenum != -1)
  		p += snprintf(p, end - p, "%d", linenum);
  	if (func)
  		p += snprintf(p, end - p, ": %s", func);
  
  	return bootstage_mark_name(BOOTSTAGE_ID_ALLOC, str);
  }
0e9967735   Simon Glass   bootstage: Add ti...
163
164
  uint32_t bootstage_start(enum bootstage_id id, const char *name)
  {
b383d6c05   Simon Glass   bootstage: Conver...
165
  	struct bootstage_data *data = gd->bootstage;
03ecac314   Simon Glass   bootstage: Use re...
166
167
  	struct bootstage_record *rec = ensure_id(data, id);
  	ulong start_us = timer_get_boot_us();
0e9967735   Simon Glass   bootstage: Add ti...
168

03ecac314   Simon Glass   bootstage: Use re...
169
170
171
172
  	if (rec) {
  		rec->start_us = start_us;
  		rec->name = name;
  	}
cbcd6970a   Simon Glass   bootstage: Fix up...
173

03ecac314   Simon Glass   bootstage: Use re...
174
  	return start_us;
0e9967735   Simon Glass   bootstage: Add ti...
175
176
177
178
  }
  
  uint32_t bootstage_accum(enum bootstage_id id)
  {
b383d6c05   Simon Glass   bootstage: Conver...
179
  	struct bootstage_data *data = gd->bootstage;
03ecac314   Simon Glass   bootstage: Use re...
180
  	struct bootstage_record *rec = ensure_id(data, id);
0e9967735   Simon Glass   bootstage: Add ti...
181
  	uint32_t duration;
03ecac314   Simon Glass   bootstage: Use re...
182
183
  	if (!rec)
  		return 0;
0e9967735   Simon Glass   bootstage: Add ti...
184
185
  	duration = (uint32_t)timer_get_boot_us() - rec->start_us;
  	rec->time_us += duration;
cbcd6970a   Simon Glass   bootstage: Fix up...
186

0e9967735   Simon Glass   bootstage: Add ti...
187
188
  	return duration;
  }
94fd1316b   Simon Glass   bootstage: Store ...
189
190
191
192
193
194
195
196
197
  /**
   * Get a record name as a printable string
   *
   * @param buf	Buffer to put name if needed
   * @param len	Length of buffer
   * @param rec	Boot stage record to get the name from
   * @return pointer to name, either from the record or pointing to buf.
   */
  static const char *get_record_name(char *buf, int len,
9d2542d06   Simon Glass   bootstage: Adjust...
198
  				   const struct bootstage_record *rec)
94fd1316b   Simon Glass   bootstage: Store ...
199
200
201
202
203
204
205
206
207
208
  {
  	if (rec->name)
  		return rec->name;
  	else if (rec->id >= BOOTSTAGE_ID_USER)
  		snprintf(buf, len, "user_%d", rec->id - BOOTSTAGE_ID_USER);
  	else
  		snprintf(buf, len, "id=%d", rec->id);
  
  	return buf;
  }
b383d6c05   Simon Glass   bootstage: Conver...
209
  static uint32_t print_time_record(struct bootstage_record *rec, uint32_t prev)
3a608ca01   Simon Glass   bootstage: Implem...
210
  {
94fd1316b   Simon Glass   bootstage: Store ...
211
  	char buf[20];
0e9967735   Simon Glass   bootstage: Add ti...
212
213
  	if (prev == -1U) {
  		printf("%11s", "");
b8bcaa3ad   Simon Glass   Add function to p...
214
  		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
0e9967735   Simon Glass   bootstage: Add ti...
215
  	} else {
b8bcaa3ad   Simon Glass   Add function to p...
216
217
  		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
  		print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);
0e9967735   Simon Glass   bootstage: Add ti...
218
  	}
94fd1316b   Simon Glass   bootstage: Store ...
219
220
  	printf("  %s
  ", get_record_name(buf, sizeof(buf), rec));
3a608ca01   Simon Glass   bootstage: Implem...
221
222
223
224
225
226
227
228
229
  	return rec->time_us;
  }
  
  static int h_compare_record(const void *r1, const void *r2)
  {
  	const struct bootstage_record *rec1 = r1, *rec2 = r2;
  
  	return rec1->time_us > rec2->time_us ? 1 : -1;
  }
94fd1316b   Simon Glass   bootstage: Store ...
230
231
232
233
234
235
236
237
238
  #ifdef CONFIG_OF_LIBFDT
  /**
   * Add all bootstage timings to a device tree.
   *
   * @param blob	Device tree blob
   * @return 0 on success, != 0 on failure.
   */
  static int add_bootstages_devicetree(struct fdt_header *blob)
  {
b383d6c05   Simon Glass   bootstage: Conver...
239
  	struct bootstage_data *data = gd->bootstage;
94fd1316b   Simon Glass   bootstage: Store ...
240
241
  	int bootstage;
  	char buf[20];
03ecac314   Simon Glass   bootstage: Use re...
242
  	int recnum;
94fd1316b   Simon Glass   bootstage: Store ...
243
244
245
246
247
248
249
250
251
252
253
  	int i;
  
  	if (!blob)
  		return 0;
  
  	/*
  	 * Create the node for bootstage.
  	 * The address of flat device tree is set up by the command bootm.
  	 */
  	bootstage = fdt_add_subnode(blob, 0, "bootstage");
  	if (bootstage < 0)
e003310a7   Simon Glass   bootstage: Tidy u...
254
  		return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
255
256
257
258
259
  
  	/*
  	 * Insert the timings to the device tree in the reverse order so
  	 * that they can be printed in the Linux kernel in the right order.
  	 */
03ecac314   Simon Glass   bootstage: Use re...
260
261
  	for (recnum = data->rec_count - 1, i = 0; recnum >= 0; recnum--, i++) {
  		struct bootstage_record *rec = &data->record[recnum];
94fd1316b   Simon Glass   bootstage: Store ...
262
  		int node;
03ecac314   Simon Glass   bootstage: Use re...
263
  		if (rec->id != BOOTSTAGE_ID_AWAKE && rec->time_us == 0)
94fd1316b   Simon Glass   bootstage: Store ...
264
265
266
267
268
269
270
271
  			continue;
  
  		node = fdt_add_subnode(blob, bootstage, simple_itoa(i));
  		if (node < 0)
  			break;
  
  		/* add properties to the node. */
  		if (fdt_setprop_string(blob, node, "name",
03ecac314   Simon Glass   bootstage: Use re...
272
  				       get_record_name(buf, sizeof(buf), rec)))
e003310a7   Simon Glass   bootstage: Tidy u...
273
  			return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
274
275
276
277
278
  
  		/* Check if this is a 'mark' or 'accum' record */
  		if (fdt_setprop_cell(blob, node,
  				rec->start_us ? "accum" : "mark",
  				rec->time_us))
e003310a7   Simon Glass   bootstage: Tidy u...
279
  			return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  	}
  
  	return 0;
  }
  
  int bootstage_fdt_add_report(void)
  {
  	if (add_bootstages_devicetree(working_fdt))
  		puts("bootstage: Failed to add to device tree
  ");
  
  	return 0;
  }
  #endif
3a608ca01   Simon Glass   bootstage: Implem...
294
295
  void bootstage_report(void)
  {
b383d6c05   Simon Glass   bootstage: Conver...
296
297
  	struct bootstage_data *data = gd->bootstage;
  	struct bootstage_record *rec = data->record;
3a608ca01   Simon Glass   bootstage: Implem...
298
  	uint32_t prev;
03ecac314   Simon Glass   bootstage: Use re...
299
  	int i;
3a608ca01   Simon Glass   bootstage: Implem...
300

03ecac314   Simon Glass   bootstage: Use re...
301
302
303
  	printf("Timer summary in microseconds (%d records):
  ",
  	       data->rec_count);
3a608ca01   Simon Glass   bootstage: Implem...
304
305
  	printf("%11s%11s  %s
  ", "Mark", "Elapsed", "Stage");
b383d6c05   Simon Glass   bootstage: Conver...
306
  	prev = print_time_record(rec, 0);
3a608ca01   Simon Glass   bootstage: Implem...
307
308
  
  	/* Sort records by increasing time */
03ecac314   Simon Glass   bootstage: Use re...
309
  	qsort(data->record, data->rec_count, sizeof(*rec), h_compare_record);
3a608ca01   Simon Glass   bootstage: Implem...
310

03ecac314   Simon Glass   bootstage: Use re...
311
312
  	for (i = 1, rec++; i < data->rec_count; i++, rec++) {
  		if (rec->id && !rec->start_us)
b383d6c05   Simon Glass   bootstage: Conver...
313
  			prev = print_time_record(rec, prev);
3a608ca01   Simon Glass   bootstage: Implem...
314
  	}
03ecac314   Simon Glass   bootstage: Use re...
315
316
317
  	if (data->rec_count > RECORD_COUNT)
  		printf("Overflowed internal boot id table by %d entries
  "
d69bb0ecb   Simon Glass   bootstage: Provid...
318
319
  		       "Please increase CONFIG_(SPL_)BOOTSTAGE_RECORD_COUNT
  ",
03ecac314   Simon Glass   bootstage: Use re...
320
  		       data->rec_count - RECORD_COUNT);
0e9967735   Simon Glass   bootstage: Add ti...
321
322
323
324
  
  	puts("
  Accumulated time:
  ");
03ecac314   Simon Glass   bootstage: Use re...
325
  	for (i = 0, rec = data->record; i < data->rec_count; i++, rec++) {
0e9967735   Simon Glass   bootstage: Add ti...
326
  		if (rec->start_us)
b383d6c05   Simon Glass   bootstage: Conver...
327
  			prev = print_time_record(rec, -1);
0e9967735   Simon Glass   bootstage: Add ti...
328
  	}
3a608ca01   Simon Glass   bootstage: Implem...
329
  }
3786980dd   Simon Glass   Move bootstage ti...
330

fcf509b80   Simon Glass   bootstage: Add fe...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  /**
   * Append data to a memory buffer
   *
   * Write data to the buffer if there is space. Whether there is space or not,
   * the buffer pointer is incremented.
   *
   * @param ptrp	Pointer to buffer, updated by this function
   * @param end	Pointer to end of buffer
   * @param data	Data to write to buffer
   * @param size	Size of data
   */
  static void append_data(char **ptrp, char *end, const void *data, int size)
  {
  	char *ptr = *ptrp;
  
  	*ptrp += size;
  	if (*ptrp > end)
  		return;
  
  	memcpy(ptr, data, size);
  }
  
  int bootstage_stash(void *base, int size)
  {
9d2542d06   Simon Glass   bootstage: Adjust...
355
  	const struct bootstage_data *data = gd->bootstage;
fcf509b80   Simon Glass   bootstage: Add fe...
356
  	struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
9d2542d06   Simon Glass   bootstage: Adjust...
357
  	const struct bootstage_record *rec;
fcf509b80   Simon Glass   bootstage: Add fe...
358
359
360
  	char buf[20];
  	char *ptr = base, *end = ptr + size;
  	uint32_t count;
03ecac314   Simon Glass   bootstage: Use re...
361
  	int i;
fcf509b80   Simon Glass   bootstage: Add fe...
362
363
364
365
  
  	if (hdr + 1 > (struct bootstage_hdr *)end) {
  		debug("%s: Not enough space for bootstage hdr
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
366
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
367
368
369
370
371
372
  	}
  
  	/* Write an arbitrary version number */
  	hdr->version = BOOTSTAGE_VERSION;
  
  	/* Count the number of records, and write that value first */
03ecac314   Simon Glass   bootstage: Use re...
373
374
375
  	for (rec = data->record, i = count = 0; i < data->rec_count;
  	     i++, rec++) {
  		if (rec->id != 0)
fcf509b80   Simon Glass   bootstage: Add fe...
376
377
378
379
380
381
382
383
  			count++;
  	}
  	hdr->count = count;
  	hdr->size = 0;
  	hdr->magic = BOOTSTAGE_MAGIC;
  	ptr += sizeof(*hdr);
  
  	/* Write the records, silently stopping when we run out of space */
03ecac314   Simon Glass   bootstage: Use re...
384
  	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
c91001f60   Simon Glass   bootstage: Show r...
385
  		append_data(&ptr, end, rec, sizeof(*rec));
fcf509b80   Simon Glass   bootstage: Add fe...
386
387
388
  	}
  
  	/* Write the name strings */
03ecac314   Simon Glass   bootstage: Use re...
389
  	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
c91001f60   Simon Glass   bootstage: Show r...
390
  		const char *name;
fcf509b80   Simon Glass   bootstage: Add fe...
391

c91001f60   Simon Glass   bootstage: Show r...
392
393
  		name = get_record_name(buf, sizeof(buf), rec);
  		append_data(&ptr, end, name, strlen(name) + 1);
fcf509b80   Simon Glass   bootstage: Add fe...
394
395
396
397
398
399
  	}
  
  	/* Check for buffer overflow */
  	if (ptr > end) {
  		debug("%s: Not enough space for bootstage stash
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
400
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
401
402
403
404
  	}
  
  	/* Update total data size */
  	hdr->size = ptr - (char *)base;
ff00226e0   Simon Glass   bootstage: Use de...
405
406
  	debug("Stashed %d records
  ", hdr->count);
fcf509b80   Simon Glass   bootstage: Add fe...
407
408
409
  
  	return 0;
  }
9d2542d06   Simon Glass   bootstage: Adjust...
410
  int bootstage_unstash(const void *base, int size)
fcf509b80   Simon Glass   bootstage: Add fe...
411
  {
9d2542d06   Simon Glass   bootstage: Adjust...
412
  	const struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
b383d6c05   Simon Glass   bootstage: Conver...
413
  	struct bootstage_data *data = gd->bootstage;
9d2542d06   Simon Glass   bootstage: Adjust...
414
  	const char *ptr = base, *end = ptr + size;
fcf509b80   Simon Glass   bootstage: Add fe...
415
  	struct bootstage_record *rec;
fcf509b80   Simon Glass   bootstage: Add fe...
416
  	uint rec_size;
03ecac314   Simon Glass   bootstage: Use re...
417
  	int i;
fcf509b80   Simon Glass   bootstage: Add fe...
418
419
420
421
422
423
424
  
  	if (size == -1)
  		end = (char *)(~(uintptr_t)0);
  
  	if (hdr + 1 > (struct bootstage_hdr *)end) {
  		debug("%s: Not enough space for bootstage hdr
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
425
  		return -EPERM;
fcf509b80   Simon Glass   bootstage: Add fe...
426
427
428
429
430
  	}
  
  	if (hdr->magic != BOOTSTAGE_MAGIC) {
  		debug("%s: Invalid bootstage magic
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
431
  		return -ENOENT;
fcf509b80   Simon Glass   bootstage: Add fe...
432
433
434
435
436
  	}
  
  	if (ptr + hdr->size > end) {
  		debug("%s: Bootstage data runs past buffer end
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
437
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
438
439
440
  	}
  
  	if (hdr->count * sizeof(*rec) > hdr->size) {
5d3bd3454   Simon Glass   bootstage: Correc...
441
  		debug("%s: Bootstage has %d records needing %lu bytes, but "
fcf509b80   Simon Glass   bootstage: Add fe...
442
443
  			"only %d bytes is available
  ", __func__, hdr->count,
5d3bd3454   Simon Glass   bootstage: Correc...
444
  		      (ulong)hdr->count * sizeof(*rec), hdr->size);
e003310a7   Simon Glass   bootstage: Tidy u...
445
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
446
447
448
449
450
451
  	}
  
  	if (hdr->version != BOOTSTAGE_VERSION) {
  		debug("%s: Bootstage data version %#0x unrecognised
  ",
  		      __func__, hdr->version);
e003310a7   Simon Glass   bootstage: Tidy u...
452
  		return -EINVAL;
fcf509b80   Simon Glass   bootstage: Add fe...
453
  	}
03ecac314   Simon Glass   bootstage: Use re...
454
  	if (data->rec_count + hdr->count > RECORD_COUNT) {
fcf509b80   Simon Glass   bootstage: Add fe...
455
456
  		debug("%s: Bootstage has %d records, we have space for %d
  "
d69bb0ecb   Simon Glass   bootstage: Provid...
457
458
  			"Please increase CONFIG_(SPL_)BOOTSTAGE_RECORD_COUNT
  ",
03ecac314   Simon Glass   bootstage: Use re...
459
  		      __func__, hdr->count, RECORD_COUNT - data->rec_count);
e003310a7   Simon Glass   bootstage: Tidy u...
460
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
461
462
463
464
465
  	}
  
  	ptr += sizeof(*hdr);
  
  	/* Read the records */
b383d6c05   Simon Glass   bootstage: Conver...
466
  	rec_size = hdr->count * sizeof(*data->record);
03ecac314   Simon Glass   bootstage: Use re...
467
  	memcpy(data->record + data->rec_count, ptr, rec_size);
fcf509b80   Simon Glass   bootstage: Add fe...
468
469
470
  
  	/* Read the name strings */
  	ptr += rec_size;
03ecac314   Simon Glass   bootstage: Use re...
471
472
  	for (rec = data->record + data->next_id, i = 0; i < hdr->count;
  	     i++, rec++) {
fcf509b80   Simon Glass   bootstage: Add fe...
473
474
475
476
477
478
479
  		rec->name = ptr;
  
  		/* Assume no data corruption here */
  		ptr += strlen(ptr) + 1;
  	}
  
  	/* Mark the records as read */
03ecac314   Simon Glass   bootstage: Use re...
480
  	data->rec_count += hdr->count;
ff00226e0   Simon Glass   bootstage: Use de...
481
482
  	debug("Unstashed %d records
  ", hdr->count);
fcf509b80   Simon Glass   bootstage: Add fe...
483
484
485
  
  	return 0;
  }
b383d6c05   Simon Glass   bootstage: Conver...
486

25e7dc6a6   Simon Glass   bootstage: Suppor...
487
488
489
490
  int bootstage_get_size(void)
  {
  	return sizeof(struct bootstage_data);
  }
b383d6c05   Simon Glass   bootstage: Conver...
491
492
493
494
495
496
497
498
499
500
  int bootstage_init(bool first)
  {
  	struct bootstage_data *data;
  	int size = sizeof(struct bootstage_data);
  
  	gd->bootstage = (struct bootstage_data *)malloc(size);
  	if (!gd->bootstage)
  		return -ENOMEM;
  	data = gd->bootstage;
  	memset(data, '\0', size);
03ecac314   Simon Glass   bootstage: Use re...
501
502
  	if (first) {
  		data->next_id = BOOTSTAGE_ID_USER;
b383d6c05   Simon Glass   bootstage: Conver...
503
  		bootstage_add_record(BOOTSTAGE_ID_AWAKE, "reset", 0, 0);
03ecac314   Simon Glass   bootstage: Use re...
504
  	}
b383d6c05   Simon Glass   bootstage: Conver...
505
506
507
  
  	return 0;
  }