Blame view

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

fcf509b80   Simon Glass   bootstage: Add fe...
35
36
37
  enum {
  	BOOTSTAGE_VERSION	= 0,
  	BOOTSTAGE_MAGIC		= 0xb00757a3,
b8bcaa3ad   Simon Glass   Add function to p...
38
  	BOOTSTAGE_DIGITS	= 9,
fcf509b80   Simon Glass   bootstage: Add fe...
39
40
41
42
43
44
45
46
  };
  
  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...
47
48
  int bootstage_relocate(void)
  {
b383d6c05   Simon Glass   bootstage: Conver...
49
  	struct bootstage_data *data = gd->bootstage;
150678a58   Doug Anderson   bootstage: Copy b...
50
51
52
53
54
55
  	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...
56
57
58
59
  	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...
60
61
62
  
  	return 0;
  }
03ecac314   Simon Glass   bootstage: Use re...
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
91
  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...
92
  ulong bootstage_add_record(enum bootstage_id id, const char *name,
094e06a52   Simon Glass   bootstage: Export...
93
  			   int flags, ulong mark)
3a608ca01   Simon Glass   bootstage: Implem...
94
  {
b383d6c05   Simon Glass   bootstage: Conver...
95
  	struct bootstage_data *data = gd->bootstage;
3a608ca01   Simon Glass   bootstage: Implem...
96
  	struct bootstage_record *rec;
3a608ca01   Simon Glass   bootstage: Implem...
97
98
  
  	if (flags & BOOTSTAGEF_ALLOC)
b383d6c05   Simon Glass   bootstage: Conver...
99
  		id = data->next_id++;
3a608ca01   Simon Glass   bootstage: Implem...
100

03ecac314   Simon Glass   bootstage: Use re...
101
102
103
104
105
106
107
108
  	/* 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...
109
110
111
112
  	}
  
  	/* Tell the board about this progress */
  	show_boot_progress(flags & BOOTSTAGEF_ERROR ? -id : id);
cbcd6970a   Simon Glass   bootstage: Fix up...
113

3a608ca01   Simon Glass   bootstage: Implem...
114
115
116
117
118
119
  	return mark;
  }
  
  
  ulong bootstage_mark(enum bootstage_id id)
  {
094e06a52   Simon Glass   bootstage: Export...
120
  	return bootstage_add_record(id, NULL, 0, timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
121
122
123
124
  }
  
  ulong bootstage_error(enum bootstage_id id)
  {
094e06a52   Simon Glass   bootstage: Export...
125
126
  	return bootstage_add_record(id, NULL, BOOTSTAGEF_ERROR,
  				    timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
127
128
129
130
131
132
133
134
  }
  
  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...
135

094e06a52   Simon Glass   bootstage: Export...
136
  	return bootstage_add_record(id, name, flags, timer_get_boot_us());
3a608ca01   Simon Glass   bootstage: Implem...
137
  }
fb7db41cd   Simon Glass   bootstage: Allow ...
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
163
  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...
164
165
  uint32_t bootstage_start(enum bootstage_id id, const char *name)
  {
b383d6c05   Simon Glass   bootstage: Conver...
166
  	struct bootstage_data *data = gd->bootstage;
03ecac314   Simon Glass   bootstage: Use re...
167
168
  	struct bootstage_record *rec = ensure_id(data, id);
  	ulong start_us = timer_get_boot_us();
0e9967735   Simon Glass   bootstage: Add ti...
169

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

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

0e9967735   Simon Glass   bootstage: Add ti...
188
189
  	return duration;
  }
94fd1316b   Simon Glass   bootstage: Store ...
190
191
192
193
194
195
196
197
198
  /**
   * 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...
199
  				   const struct bootstage_record *rec)
94fd1316b   Simon Glass   bootstage: Store ...
200
201
202
203
204
205
206
207
208
209
  {
  	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...
210
  static uint32_t print_time_record(struct bootstage_record *rec, uint32_t prev)
3a608ca01   Simon Glass   bootstage: Implem...
211
  {
94fd1316b   Simon Glass   bootstage: Store ...
212
  	char buf[20];
0e9967735   Simon Glass   bootstage: Add ti...
213
214
  	if (prev == -1U) {
  		printf("%11s", "");
b8bcaa3ad   Simon Glass   Add function to p...
215
  		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
0e9967735   Simon Glass   bootstage: Add ti...
216
  	} else {
b8bcaa3ad   Simon Glass   Add function to p...
217
218
  		print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS);
  		print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS);
0e9967735   Simon Glass   bootstage: Add ti...
219
  	}
94fd1316b   Simon Glass   bootstage: Store ...
220
221
  	printf("  %s
  ", get_record_name(buf, sizeof(buf), rec));
3a608ca01   Simon Glass   bootstage: Implem...
222
223
224
225
226
227
228
229
230
  	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 ...
231
232
233
234
235
236
237
238
239
  #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...
240
  	struct bootstage_data *data = gd->bootstage;
94fd1316b   Simon Glass   bootstage: Store ...
241
242
  	int bootstage;
  	char buf[20];
03ecac314   Simon Glass   bootstage: Use re...
243
  	int recnum;
94fd1316b   Simon Glass   bootstage: Store ...
244
245
246
247
248
249
250
251
252
253
254
  	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...
255
  		return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
256
257
258
259
260
  
  	/*
  	 * 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...
261
262
  	for (recnum = data->rec_count - 1, i = 0; recnum >= 0; recnum--, i++) {
  		struct bootstage_record *rec = &data->record[recnum];
94fd1316b   Simon Glass   bootstage: Store ...
263
  		int node;
03ecac314   Simon Glass   bootstage: Use re...
264
  		if (rec->id != BOOTSTAGE_ID_AWAKE && rec->time_us == 0)
94fd1316b   Simon Glass   bootstage: Store ...
265
266
267
268
269
270
271
272
  			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...
273
  				       get_record_name(buf, sizeof(buf), rec)))
e003310a7   Simon Glass   bootstage: Tidy u...
274
  			return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
275
276
277
278
279
  
  		/* 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...
280
  			return -EINVAL;
94fd1316b   Simon Glass   bootstage: Store ...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  	}
  
  	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...
295
296
  void bootstage_report(void)
  {
b383d6c05   Simon Glass   bootstage: Conver...
297
298
  	struct bootstage_data *data = gd->bootstage;
  	struct bootstage_record *rec = data->record;
3a608ca01   Simon Glass   bootstage: Implem...
299
  	uint32_t prev;
03ecac314   Simon Glass   bootstage: Use re...
300
  	int i;
3a608ca01   Simon Glass   bootstage: Implem...
301

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

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

fcf509b80   Simon Glass   bootstage: Add fe...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  /**
   * 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...
356
  	const struct bootstage_data *data = gd->bootstage;
fcf509b80   Simon Glass   bootstage: Add fe...
357
  	struct bootstage_hdr *hdr = (struct bootstage_hdr *)base;
9d2542d06   Simon Glass   bootstage: Adjust...
358
  	const struct bootstage_record *rec;
fcf509b80   Simon Glass   bootstage: Add fe...
359
360
361
  	char buf[20];
  	char *ptr = base, *end = ptr + size;
  	uint32_t count;
03ecac314   Simon Glass   bootstage: Use re...
362
  	int i;
fcf509b80   Simon Glass   bootstage: Add fe...
363
364
365
366
  
  	if (hdr + 1 > (struct bootstage_hdr *)end) {
  		debug("%s: Not enough space for bootstage hdr
  ", __func__);
e003310a7   Simon Glass   bootstage: Tidy u...
367
  		return -ENOSPC;
fcf509b80   Simon Glass   bootstage: Add fe...
368
369
370
371
372
373
  	}
  
  	/* 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...
374
375
376
  	for (rec = data->record, i = count = 0; i < data->rec_count;
  	     i++, rec++) {
  		if (rec->id != 0)
fcf509b80   Simon Glass   bootstage: Add fe...
377
378
379
380
381
382
383
384
  			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...
385
  	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
c91001f60   Simon Glass   bootstage: Show r...
386
  		append_data(&ptr, end, rec, sizeof(*rec));
fcf509b80   Simon Glass   bootstage: Add fe...
387
388
389
  	}
  
  	/* Write the name strings */
03ecac314   Simon Glass   bootstage: Use re...
390
  	for (rec = data->record, i = 0; i < data->rec_count; i++, rec++) {
c91001f60   Simon Glass   bootstage: Show r...
391
  		const char *name;
fcf509b80   Simon Glass   bootstage: Add fe...
392

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

25e7dc6a6   Simon Glass   bootstage: Suppor...
488
489
490
491
  int bootstage_get_size(void)
  {
  	return sizeof(struct bootstage_data);
  }
b383d6c05   Simon Glass   bootstage: Conver...
492
493
494
495
496
497
498
499
500
501
  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...
502
503
  	if (first) {
  		data->next_id = BOOTSTAGE_ID_USER;
b383d6c05   Simon Glass   bootstage: Conver...
504
  		bootstage_add_record(BOOTSTAGE_ID_AWAKE, "reset", 0, 0);
03ecac314   Simon Glass   bootstage: Use re...
505
  	}
b383d6c05   Simon Glass   bootstage: Conver...
506
507
508
  
  	return 0;
  }