Commit fcf509b80760156fe146aeb11510ffb0278b7b74

Authored by Simon Glass
Committed by Anatolij Gustschin
1 parent 94fd1316b7

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

... ... @@ -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 +}
... ... @@ -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