Commit fcf509b80760156fe146aeb11510ffb0278b7b74
Committed by
Anatolij Gustschin
1 parent
94fd1316b7
Exists in
master
and in
54 other branches
bootstage: Add feature to stash/unstash bootstage info
It is useful to be able to write the bootstage information to memory for use by a later utility, or the Linux kernel. Provide a function to do this as well as a function to read bootstage information back and incorporate it into the current table. This also makes it possible for U-Boot to chain to another U-Boot and pass on its bootstage information. Signed-off-by: Simon Glass <sjg@chromium.org>
Showing 2 changed files with 188 additions and 0 deletions Side-by-side Diff
common/bootstage.c
... | ... | @@ -44,6 +44,18 @@ |
44 | 44 | static struct bootstage_record record[BOOTSTAGE_ID_COUNT] = { {1} }; |
45 | 45 | static int next_id = BOOTSTAGE_ID_USER; |
46 | 46 | |
47 | +enum { | |
48 | + BOOTSTAGE_VERSION = 0, | |
49 | + BOOTSTAGE_MAGIC = 0xb00757a3, | |
50 | +}; | |
51 | + | |
52 | +struct bootstage_hdr { | |
53 | + uint32_t version; /* BOOTSTAGE_VERSION */ | |
54 | + uint32_t count; /* Number of records */ | |
55 | + uint32_t size; /* Total data size (non-zero if valid) */ | |
56 | + uint32_t magic; /* Unused */ | |
57 | +}; | |
58 | + | |
47 | 59 | ulong bootstage_add_record(enum bootstage_id id, const char *name, |
48 | 60 | int flags, ulong mark) |
49 | 61 | { |
... | ... | @@ -282,4 +294,151 @@ |
282 | 294 | |
283 | 295 | ulong timer_get_boot_us(void) |
284 | 296 | __attribute__((weak, alias("__timer_get_boot_us"))); |
297 | + | |
298 | +/** | |
299 | + * Append data to a memory buffer | |
300 | + * | |
301 | + * Write data to the buffer if there is space. Whether there is space or not, | |
302 | + * the buffer pointer is incremented. | |
303 | + * | |
304 | + * @param ptrp Pointer to buffer, updated by this function | |
305 | + * @param end Pointer to end of buffer | |
306 | + * @param data Data to write to buffer | |
307 | + * @param size Size of data | |
308 | + */ | |
309 | +static void append_data(char **ptrp, char *end, const void *data, int size) | |
310 | +{ | |
311 | + char *ptr = *ptrp; | |
312 | + | |
313 | + *ptrp += size; | |
314 | + if (*ptrp > end) | |
315 | + return; | |
316 | + | |
317 | + memcpy(ptr, data, size); | |
318 | +} | |
319 | + | |
320 | +int bootstage_stash(void *base, int size) | |
321 | +{ | |
322 | + struct bootstage_hdr *hdr = (struct bootstage_hdr *)base; | |
323 | + struct bootstage_record *rec; | |
324 | + char buf[20]; | |
325 | + char *ptr = base, *end = ptr + size; | |
326 | + uint32_t count; | |
327 | + int id; | |
328 | + | |
329 | + if (hdr + 1 > (struct bootstage_hdr *)end) { | |
330 | + debug("%s: Not enough space for bootstage hdr\n", __func__); | |
331 | + return -1; | |
332 | + } | |
333 | + | |
334 | + /* Write an arbitrary version number */ | |
335 | + hdr->version = BOOTSTAGE_VERSION; | |
336 | + | |
337 | + /* Count the number of records, and write that value first */ | |
338 | + for (rec = record, id = count = 0; id < BOOTSTAGE_ID_COUNT; | |
339 | + id++, rec++) { | |
340 | + if (rec->time_us != 0) | |
341 | + count++; | |
342 | + } | |
343 | + hdr->count = count; | |
344 | + hdr->size = 0; | |
345 | + hdr->magic = BOOTSTAGE_MAGIC; | |
346 | + ptr += sizeof(*hdr); | |
347 | + | |
348 | + /* Write the records, silently stopping when we run out of space */ | |
349 | + for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) { | |
350 | + if (rec->time_us != 0) | |
351 | + append_data(&ptr, end, rec, sizeof(*rec)); | |
352 | + } | |
353 | + | |
354 | + /* Write the name strings */ | |
355 | + for (rec = record, id = 0; id < BOOTSTAGE_ID_COUNT; id++, rec++) { | |
356 | + if (rec->time_us != 0) { | |
357 | + const char *name; | |
358 | + | |
359 | + name = get_record_name(buf, sizeof(buf), rec); | |
360 | + append_data(&ptr, end, name, strlen(name) + 1); | |
361 | + } | |
362 | + } | |
363 | + | |
364 | + /* Check for buffer overflow */ | |
365 | + if (ptr > end) { | |
366 | + debug("%s: Not enough space for bootstage stash\n", __func__); | |
367 | + return -1; | |
368 | + } | |
369 | + | |
370 | + /* Update total data size */ | |
371 | + hdr->size = ptr - (char *)base; | |
372 | + printf("Stashed %d records\n", hdr->count); | |
373 | + | |
374 | + return 0; | |
375 | +} | |
376 | + | |
377 | +int bootstage_unstash(void *base, int size) | |
378 | +{ | |
379 | + struct bootstage_hdr *hdr = (struct bootstage_hdr *)base; | |
380 | + struct bootstage_record *rec; | |
381 | + char *ptr = base, *end = ptr + size; | |
382 | + uint rec_size; | |
383 | + int id; | |
384 | + | |
385 | + if (size == -1) | |
386 | + end = (char *)(~(uintptr_t)0); | |
387 | + | |
388 | + if (hdr + 1 > (struct bootstage_hdr *)end) { | |
389 | + debug("%s: Not enough space for bootstage hdr\n", __func__); | |
390 | + return -1; | |
391 | + } | |
392 | + | |
393 | + if (hdr->magic != BOOTSTAGE_MAGIC) { | |
394 | + debug("%s: Invalid bootstage magic\n", __func__); | |
395 | + return -1; | |
396 | + } | |
397 | + | |
398 | + if (ptr + hdr->size > end) { | |
399 | + debug("%s: Bootstage data runs past buffer end\n", __func__); | |
400 | + return -1; | |
401 | + } | |
402 | + | |
403 | + if (hdr->count * sizeof(*rec) > hdr->size) { | |
404 | + debug("%s: Bootstage has %d records needing %d bytes, but " | |
405 | + "only %d bytes is available\n", __func__, hdr->count, | |
406 | + hdr->count * sizeof(*rec), hdr->size); | |
407 | + return -1; | |
408 | + } | |
409 | + | |
410 | + if (hdr->version != BOOTSTAGE_VERSION) { | |
411 | + debug("%s: Bootstage data version %#0x unrecognised\n", | |
412 | + __func__, hdr->version); | |
413 | + return -1; | |
414 | + } | |
415 | + | |
416 | + if (next_id + hdr->count > BOOTSTAGE_ID_COUNT) { | |
417 | + debug("%s: Bootstage has %d records, we have space for %d\n" | |
418 | + "- please increase CONFIG_BOOTSTAGE_USER_COUNT\n", | |
419 | + __func__, hdr->count, BOOTSTAGE_ID_COUNT - next_id); | |
420 | + return -1; | |
421 | + } | |
422 | + | |
423 | + ptr += sizeof(*hdr); | |
424 | + | |
425 | + /* Read the records */ | |
426 | + rec_size = hdr->count * sizeof(*record); | |
427 | + memcpy(record + next_id, ptr, rec_size); | |
428 | + | |
429 | + /* Read the name strings */ | |
430 | + ptr += rec_size; | |
431 | + for (rec = record + next_id, id = 0; id < hdr->count; id++, rec++) { | |
432 | + rec->name = ptr; | |
433 | + | |
434 | + /* Assume no data corruption here */ | |
435 | + ptr += strlen(ptr) + 1; | |
436 | + } | |
437 | + | |
438 | + /* Mark the records as read */ | |
439 | + next_id += hdr->count; | |
440 | + printf("Unstashed %d records\n", hdr->count); | |
441 | + | |
442 | + return 0; | |
443 | +} |
include/bootstage.h
... | ... | @@ -284,6 +284,27 @@ |
284 | 284 | */ |
285 | 285 | int bootstage_fdt_add_report(void); |
286 | 286 | |
287 | +/* | |
288 | + * Stash bootstage data into memory | |
289 | + * | |
290 | + * @param base Base address of memory buffer | |
291 | + * @param size Size of memory buffer | |
292 | + * @return 0 if stashed ok, -1 if out of space | |
293 | + */ | |
294 | +int bootstage_stash(void *base, int size); | |
295 | + | |
296 | +/** | |
297 | + * Read bootstage data from memory | |
298 | + * | |
299 | + * Bootstage data is read from memory and placed in the bootstage table | |
300 | + * in the user records. | |
301 | + * | |
302 | + * @param base Base address of memory buffer | |
303 | + * @param size Size of memory buffer (-1 if unknown) | |
304 | + * @return 0 if unstashed ok, -1 if bootstage info not found, or out of space | |
305 | + */ | |
306 | +int bootstage_unstash(void *base, int size); | |
307 | + | |
287 | 308 | #else |
288 | 309 | /* |
289 | 310 | * This is a dummy implementation which just calls show_boot_progress(), |
290 | 311 | |
... | ... | @@ -307,7 +328,15 @@ |
307 | 328 | return 0; |
308 | 329 | } |
309 | 330 | |
331 | +static inline int bootstage_stash(void *base, int size) | |
332 | +{ | |
333 | + return 0; /* Pretend to succeed */ | |
334 | +} | |
310 | 335 | |
336 | +static inline int bootstage_unstash(void *base, int size) | |
337 | +{ | |
338 | + return 0; /* Pretend to succeed */ | |
339 | +} | |
311 | 340 | #endif /* CONFIG_BOOTSTAGE */ |
312 | 341 | |
313 | 342 | #endif |