Home | History | Annotate | Download | only in include
      1 /* SPDX-License-Identifier: GPL-2.0+ */
      2 /*
      3  * This file implements recording of each stage of the boot process. It is
      4  * intended to implement timing of each stage, reporting this information
      5  * to the user and passing it to the OS for logging / further analysis.
      6  * Note that it requires timer_get_boot_us() to be defined by the board
      7  *
      8  * Copyright (c) 2011 The Chromium OS Authors.
      9  */
     10 
     11 #ifndef _BOOTSTAGE_H
     12 #define _BOOTSTAGE_H
     13 
     14 /* Flags for each bootstage record */
     15 enum bootstage_flags {
     16 	BOOTSTAGEF_ERROR	= 1 << 0,	/* Error record */
     17 	BOOTSTAGEF_ALLOC	= 1 << 1,	/* Allocate an id */
     18 };
     19 
     20 /* bootstate sub-IDs used for kernel and ramdisk ranges */
     21 enum {
     22 	BOOTSTAGE_SUB_FORMAT,
     23 	BOOTSTAGE_SUB_FORMAT_OK,
     24 	BOOTSTAGE_SUB_NO_UNIT_NAME,
     25 	BOOTSTAGE_SUB_UNIT_NAME,
     26 	BOOTSTAGE_SUB_SUBNODE,
     27 
     28 	BOOTSTAGE_SUB_CHECK,
     29 	BOOTSTAGE_SUB_HASH = 5,
     30 	BOOTSTAGE_SUB_CHECK_ARCH = 5,
     31 	BOOTSTAGE_SUB_CHECK_ALL,
     32 	BOOTSTAGE_SUB_GET_DATA,
     33 	BOOTSTAGE_SUB_CHECK_ALL_OK = 7,
     34 	BOOTSTAGE_SUB_GET_DATA_OK,
     35 	BOOTSTAGE_SUB_LOAD,
     36 };
     37 
     38 /*
     39  * A list of boot stages that we know about. Each of these indicates the
     40  * state that we are at, and the action that we are about to perform. For
     41  * errors, we issue an error for an item when it fails. Therefore the
     42  * normal sequence is:
     43  *
     44  * progress action1
     45  * progress action2
     46  * progress action3
     47  *
     48  * and an error condition where action 3 failed would be:
     49  *
     50  * progress action1
     51  * progress action2
     52  * progress action3
     53  * error on action3
     54  */
     55 enum bootstage_id {
     56 	BOOTSTAGE_ID_START = 0,
     57 	BOOTSTAGE_ID_CHECK_MAGIC,	/* Checking image magic */
     58 	BOOTSTAGE_ID_CHECK_HEADER,	/* Checking image header */
     59 	BOOTSTAGE_ID_CHECK_CHECKSUM,	/* Checking image checksum */
     60 	BOOTSTAGE_ID_CHECK_ARCH,	/* Checking architecture */
     61 
     62 	BOOTSTAGE_ID_CHECK_IMAGETYPE = 5,/* Checking image type */
     63 	BOOTSTAGE_ID_DECOMP_IMAGE,	/* Decompressing image */
     64 	BOOTSTAGE_ID_KERNEL_LOADED,	/* Kernel has been loaded */
     65 	BOOTSTAGE_ID_DECOMP_UNIMPL = 7,	/* Odd decompression algorithm */
     66 	BOOTSTAGE_ID_CHECK_BOOT_OS,	/* Calling OS-specific boot function */
     67 	BOOTSTAGE_ID_BOOT_OS_RETURNED,	/* Tried to boot OS, but it returned */
     68 	BOOTSTAGE_ID_CHECK_RAMDISK = 9,	/* Checking ram disk */
     69 
     70 	BOOTSTAGE_ID_RD_MAGIC,		/* Checking ram disk magic */
     71 	BOOTSTAGE_ID_RD_HDR_CHECKSUM,	/* Checking ram disk heder checksum */
     72 	BOOTSTAGE_ID_RD_CHECKSUM,	/* Checking ram disk checksum */
     73 	BOOTSTAGE_ID_COPY_RAMDISK = 12,	/* Copying ram disk into place */
     74 	BOOTSTAGE_ID_RAMDISK,		/* Checking for valid ramdisk */
     75 	BOOTSTAGE_ID_NO_RAMDISK,	/* No ram disk found (not an error) */
     76 
     77 	BOOTSTAGE_ID_RUN_OS	= 15,	/* Exiting U-Boot, entering OS */
     78 
     79 	BOOTSTAGE_ID_NEED_RESET = 30,
     80 	BOOTSTAGE_ID_POST_FAIL,		/* Post failure */
     81 	BOOTSTAGE_ID_POST_FAIL_R,	/* Post failure reported after reloc */
     82 
     83 	/*
     84 	 * This set is reported only by x86, and the meaning is different. In
     85 	 * this case we are reporting completion of a particular stage.
     86 	 * This should probably change in the x86 code (which doesn't report
     87 	 * errors in any case), but discussion this can perhaps wait until we
     88 	 * have a generic board implementation.
     89 	 */
     90 	BOOTSTAGE_ID_BOARD_INIT_R,	/* We have relocated */
     91 	BOOTSTAGE_ID_BOARD_GLOBAL_DATA,	/* Global data is set up */
     92 
     93 	BOOTSTAGE_ID_BOARD_INIT_SEQ,	/* We completed the init sequence */
     94 	BOOTSTAGE_ID_BOARD_FLASH,	/* We have configured flash banks */
     95 	BOOTSTAGE_ID_BOARD_FLASH_37,	/* In case you didn't hear... */
     96 	BOOTSTAGE_ID_BOARD_ENV,		/* Environment is relocated & ready */
     97 	BOOTSTAGE_ID_BOARD_PCI,		/* PCI is up */
     98 
     99 	BOOTSTAGE_ID_BOARD_INTERRUPTS,	/* Exceptions / interrupts ready */
    100 	BOOTSTAGE_ID_BOARD_DONE,	/* Board init done, off to main loop */
    101 	/* ^^^ here ends the x86 sequence */
    102 
    103 	/* Boot stages related to loading a kernel from an IDE device */
    104 	BOOTSTAGE_ID_IDE_START = 41,
    105 	BOOTSTAGE_ID_IDE_ADDR,
    106 	BOOTSTAGE_ID_IDE_BOOT_DEVICE,
    107 	BOOTSTAGE_ID_IDE_TYPE,
    108 
    109 	BOOTSTAGE_ID_IDE_PART,
    110 	BOOTSTAGE_ID_IDE_PART_INFO,
    111 	BOOTSTAGE_ID_IDE_PART_TYPE,
    112 	BOOTSTAGE_ID_IDE_PART_READ,
    113 	BOOTSTAGE_ID_IDE_FORMAT,
    114 
    115 	BOOTSTAGE_ID_IDE_CHECKSUM,	/* 50 */
    116 	BOOTSTAGE_ID_IDE_READ,
    117 
    118 	/* Boot stages related to loading a kernel from an NAND device */
    119 	BOOTSTAGE_ID_NAND_PART,
    120 	BOOTSTAGE_ID_NAND_SUFFIX,
    121 	BOOTSTAGE_ID_NAND_BOOT_DEVICE,
    122 	BOOTSTAGE_ID_NAND_HDR_READ = 55,
    123 	BOOTSTAGE_ID_NAND_AVAILABLE = 55,
    124 	BOOTSTAGE_ID_NAND_TYPE = 57,
    125 	BOOTSTAGE_ID_NAND_READ,
    126 
    127 	/* Boot stages related to loading a kernel from an network device */
    128 	BOOTSTAGE_ID_NET_CHECKSUM = 60,
    129 	BOOTSTAGE_ID_NET_ETH_START = 64,
    130 	BOOTSTAGE_ID_NET_ETH_INIT,
    131 
    132 	BOOTSTAGE_ID_NET_START = 80,
    133 	BOOTSTAGE_ID_NET_NETLOOP_OK,
    134 	BOOTSTAGE_ID_NET_LOADED,
    135 	BOOTSTAGE_ID_NET_DONE_ERR,
    136 	BOOTSTAGE_ID_NET_DONE,
    137 
    138 	BOOTSTAGE_ID_FIT_FDT_START = 90,
    139 	/*
    140 	 * Boot stages related to loading a FIT image. Some of these are a
    141 	 * bit wonky.
    142 	 */
    143 	BOOTSTAGE_ID_FIT_KERNEL_START = 100,
    144 
    145 	BOOTSTAGE_ID_FIT_CONFIG = 110,
    146 	BOOTSTAGE_ID_FIT_TYPE,
    147 	BOOTSTAGE_ID_FIT_KERNEL_INFO,
    148 
    149 	BOOTSTAGE_ID_FIT_COMPRESSION,
    150 	BOOTSTAGE_ID_FIT_OS,
    151 	BOOTSTAGE_ID_FIT_LOADADDR,
    152 	BOOTSTAGE_ID_OVERWRITTEN,
    153 
    154 	/* Next 10 IDs used by BOOTSTAGE_SUB_... */
    155 	BOOTSTAGE_ID_FIT_RD_START = 120,	/* Ramdisk stages */
    156 
    157 	/* Next 10 IDs used by BOOTSTAGE_SUB_... */
    158 	BOOTSTAGE_ID_FIT_SETUP_START = 130,	/* x86 setup stages */
    159 
    160 	BOOTSTAGE_ID_IDE_FIT_READ = 140,
    161 	BOOTSTAGE_ID_IDE_FIT_READ_OK,
    162 
    163 	BOOTSTAGE_ID_NAND_FIT_READ = 150,
    164 	BOOTSTAGE_ID_NAND_FIT_READ_OK,
    165 
    166 	BOOTSTAGE_ID_FIT_LOADABLE_START = 160,	/* for Loadable Images */
    167 	/*
    168 	 * These boot stages are new, higher level, and not directly related
    169 	 * to the old boot progress numbers. They are useful for recording
    170 	 * rough boot timing information.
    171 	 */
    172 	BOOTSTAGE_ID_AWAKE,
    173 	BOOTSTAGE_ID_START_SPL,
    174 	BOOTSTAGE_ID_END_SPL,
    175 	BOOTSTAGE_ID_START_UBOOT_F,
    176 	BOOTSTAGE_ID_START_UBOOT_R,
    177 	BOOTSTAGE_ID_USB_START,
    178 	BOOTSTAGE_ID_ETH_START,
    179 	BOOTSTAGE_ID_BOOTP_START,
    180 	BOOTSTAGE_ID_BOOTP_STOP,
    181 	BOOTSTAGE_ID_BOOTM_START,
    182 	BOOTSTAGE_ID_BOOTM_HANDOFF,
    183 	BOOTSTAGE_ID_MAIN_LOOP,
    184 	BOOTSTAGE_KERNELREAD_START,
    185 	BOOTSTAGE_KERNELREAD_STOP,
    186 	BOOTSTAGE_ID_BOARD_INIT,
    187 	BOOTSTAGE_ID_BOARD_INIT_DONE,
    188 
    189 	BOOTSTAGE_ID_CPU_AWAKE,
    190 	BOOTSTAGE_ID_MAIN_CPU_AWAKE,
    191 	BOOTSTAGE_ID_MAIN_CPU_READY,
    192 
    193 	BOOTSTAGE_ID_ACCUM_LCD,
    194 	BOOTSTAGE_ID_ACCUM_SCSI,
    195 	BOOTSTAGE_ID_ACCUM_SPI,
    196 	BOOTSTAGE_ID_ACCUM_DECOMP,
    197 	BOOTSTAGE_ID_ACCUM_OF_LIVE,
    198 	BOOTSTAGE_ID_FPGA_INIT,
    199 	BOOTSTATE_ID_ACCUM_DM_SPL,
    200 	BOOTSTATE_ID_ACCUM_DM_F,
    201 	BOOTSTATE_ID_ACCUM_DM_R,
    202 
    203 	/* a few spare for the user, from here */
    204 	BOOTSTAGE_ID_USER,
    205 	BOOTSTAGE_ID_ALLOC,
    206 };
    207 
    208 /*
    209  * Return the time since boot in microseconds, This is needed for bootstage
    210  * and should be defined in CPU- or board-specific code. If undefined then
    211  * you will get a link error.
    212  */
    213 ulong timer_get_boot_us(void);
    214 
    215 #if defined(USE_HOSTCC)
    216 #define show_boot_progress(val) do {} while (0)
    217 #else
    218 /**
    219  * Board code can implement show_boot_progress() if needed.
    220  *
    221  * @param val	Progress state (enum bootstage_id), or -id if an error
    222  *		has occurred.
    223  */
    224 void show_boot_progress(int val);
    225 #endif
    226 
    227 #if !defined(USE_HOSTCC)
    228 #if CONFIG_IS_ENABLED(BOOTSTAGE)
    229 #define ENABLE_BOOTSTAGE
    230 #endif
    231 #endif
    232 
    233 #ifdef ENABLE_BOOTSTAGE
    234 
    235 /* This is the full bootstage implementation */
    236 
    237 /**
    238  * Relocate existing bootstage records
    239  *
    240  * Call this after relocation has happened and after malloc has been initted.
    241  * We need to copy any pointers in bootstage records that were added pre-
    242  * relocation, since memory can be overwritten later.
    243  * @return Always returns 0, to indicate success
    244  */
    245 int bootstage_relocate(void);
    246 
    247 /**
    248  * Add a new bootstage record
    249  *
    250  * @param id	Bootstage ID to use (ignored if flags & BOOTSTAGEF_ALLOC)
    251  * @param name	Name of record, or NULL for none
    252  * @param flags	Flags (BOOTSTAGEF_...)
    253  * @param mark	Time to record in this record, in microseconds
    254  */
    255 ulong bootstage_add_record(enum bootstage_id id, const char *name,
    256 			   int flags, ulong mark);
    257 
    258 /**
    259  * Mark a time stamp for the current boot stage.
    260  */
    261 ulong bootstage_mark(enum bootstage_id id);
    262 
    263 ulong bootstage_error(enum bootstage_id id);
    264 
    265 ulong bootstage_mark_name(enum bootstage_id id, const char *name);
    266 
    267 /**
    268  * Mark a time stamp in the given function and line number
    269  *
    270  * See BOOTSTAGE_MARKER() for a convenient macro.
    271  *
    272  * @param file		Filename to record (NULL if none)
    273  * @param func		Function name to record
    274  * @param linenum	Line number to record
    275  * @return recorded time stamp
    276  */
    277 ulong bootstage_mark_code(const char *file, const char *func,
    278 			  int linenum);
    279 
    280 /**
    281  * Mark the start of a bootstage activity. The end will be marked later with
    282  * bootstage_accum() and at that point we accumulate the time taken. Calling
    283  * this function turns the given id into a accumulator rather than and
    284  * absolute mark in time. Accumulators record the total amount of time spent
    285  * in an activty during boot.
    286  *
    287  * @param id	Bootstage id to record this timestamp against
    288  * @param name	Textual name to display for this id in the report (maybe NULL)
    289  * @return start timestamp in microseconds
    290  */
    291 uint32_t bootstage_start(enum bootstage_id id, const char *name);
    292 
    293 /**
    294  * Mark the end of a bootstage activity
    295  *
    296  * After previously marking the start of an activity with bootstage_start(),
    297  * call this function to mark the end. You can call these functions in pairs
    298  * as many times as you like.
    299  *
    300  * @param id	Bootstage id to record this timestamp against
    301  * @return time spent in this iteration of the activity (i.e. the time now
    302  *		less the start time recorded in the last bootstage_start() call
    303  *		with this id.
    304  */
    305 uint32_t bootstage_accum(enum bootstage_id id);
    306 
    307 /* Print a report about boot time */
    308 void bootstage_report(void);
    309 
    310 /**
    311  * Add bootstage information to the device tree
    312  *
    313  * @return 0 if ok, -ve on error
    314  */
    315 int bootstage_fdt_add_report(void);
    316 
    317 /**
    318  * Stash bootstage data into memory
    319  *
    320  * @param base	Base address of memory buffer
    321  * @param size	Size of memory buffer
    322  * @return 0 if stashed ok, -1 if out of space
    323  */
    324 int bootstage_stash(void *base, int size);
    325 
    326 /**
    327  * Read bootstage data from memory
    328  *
    329  * Bootstage data is read from memory and placed in the bootstage table
    330  * in the user records.
    331  *
    332  * @param base	Base address of memory buffer
    333  * @param size	Size of memory buffer (-1 if unknown)
    334  * @return 0 if unstashed ok, -ENOENT if bootstage info not found, -ENOSPC if
    335  *	there is not space for read the stacked data, or other error if
    336  *	something else went wrong
    337  */
    338 int bootstage_unstash(const void *base, int size);
    339 
    340 /**
    341  * bootstage_get_size() - Get the size of the bootstage data
    342  *
    343  * @return size of boostage data in bytes
    344  */
    345 int bootstage_get_size(void);
    346 
    347 /**
    348  * bootstage_init() - Prepare bootstage for use
    349  *
    350  * @first: true if this is the first time bootstage is set up. This causes it
    351  *	to add a 'reset' record with a time of 0.
    352  */
    353 int bootstage_init(bool first);
    354 
    355 #else
    356 static inline ulong bootstage_add_record(enum bootstage_id id,
    357 		const char *name, int flags, ulong mark)
    358 {
    359 	return 0;
    360 }
    361 
    362 /*
    363  * This is a dummy implementation which just calls show_boot_progress(),
    364  * and won't even do that unless CONFIG_SHOW_BOOT_PROGRESS is defined
    365  */
    366 
    367 static inline int bootstage_relocate(void)
    368 {
    369 	return 0;
    370 }
    371 
    372 static inline ulong bootstage_mark(enum bootstage_id id)
    373 {
    374 	show_boot_progress(id);
    375 	return 0;
    376 }
    377 
    378 static inline ulong bootstage_error(enum bootstage_id id)
    379 {
    380 	show_boot_progress(-id);
    381 	return 0;
    382 }
    383 
    384 static inline ulong bootstage_mark_name(enum bootstage_id id, const char *name)
    385 {
    386 	show_boot_progress(id);
    387 	return 0;
    388 }
    389 
    390 static inline ulong bootstage_mark_code(const char *file, const char *func,
    391 					int linenum)
    392 {
    393 	return 0;
    394 }
    395 
    396 static inline uint32_t bootstage_start(enum bootstage_id id, const char *name)
    397 {
    398 	return 0;
    399 }
    400 
    401 static inline uint32_t bootstage_accum(enum bootstage_id id)
    402 {
    403 	return 0;
    404 }
    405 
    406 static inline int bootstage_stash(void *base, int size)
    407 {
    408 	return 0;	/* Pretend to succeed */
    409 }
    410 
    411 static inline int bootstage_unstash(const void *base, int size)
    412 {
    413 	return 0;	/* Pretend to succeed */
    414 }
    415 
    416 static inline int bootstage_get_size(void)
    417 {
    418 	return 0;
    419 }
    420 
    421 static inline int bootstage_init(bool first)
    422 {
    423 	return 0;
    424 }
    425 
    426 #endif /* ENABLE_BOOTSTAGE */
    427 
    428 /* Helper macro for adding a bootstage to a line of code */
    429 #define BOOTSTAGE_MARKER()	\
    430 		bootstage_mark_code(__FILE__, __func__, __LINE__)
    431 
    432 #endif
    433