1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/timestamp_serialized.h>
6 #if CONFIG(MODULE_TIMESTAMPS)
11 /* Globals that are used for tracking screen state */
14 static s32 g_lines_count
;
15 static s32 g_max_cursor_line
;
17 static unsigned long tick_freq_mhz
;
19 static const char *timestamp_name(uint32_t id
)
21 for (size_t i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
22 if (timestamp_ids
[i
].id
== id
)
23 return timestamp_ids
[i
].name
;
29 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
31 tick_freq_mhz
= table_tick_freq_mhz
;
33 /* Honor table frequency. */
37 tick_freq_mhz
= lib_sysinfo
.cpu_khz
/ 1000;
40 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
45 static u64
arch_convert_raw_ts_entry(u64 ts
)
47 return ts
/ tick_freq_mhz
;
50 static u32
char_width(char c
, u32 cursor
, u32 screen_width
)
53 return screen_width
- (cursor
% screen_width
);
62 static u32
calculate_chars_count(char *str
, u32 str_len
, u32 screen_width
,
67 for (i
= 0; i
< str_len
; i
++)
68 count
+= char_width(str
[i
], count
, screen_width
);
70 /* Ensure that 'count' can occupy at least the whole screen */
71 if (count
< screen_width
* screen_height
)
72 count
= screen_width
* screen_height
;
75 if (count
% screen_width
!= 0)
76 count
+= screen_width
- (count
% screen_width
);
82 * This method takes an input buffer and sanitizes it for display, which means:
83 * - '\n' is converted to spaces until end of line
84 * - Tabs are converted to spaces of size TAB_WIDTH
85 * - Only printable characters are preserved
87 static int sanitize_buffer_for_display(char *str
, u32 str_len
, char *out
,
88 u32 out_len
, u32 screen_width
)
93 for (i
= 0; i
< str_len
&& cursor
< out_len
; i
++) {
94 u32 width
= char_width(str
[i
], cursor
, screen_width
);
97 out
[cursor
++] = str
[i
];
99 while (width
-- && cursor
< out_len
)
103 /* Fill the rest of the out buffer with spaces */
104 while (cursor
< out_len
)
110 static uint64_t timestamp_print_entry(char *buffer
, size_t size
, uint32_t *cur
,
111 uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
116 name
= timestamp_name(id
);
117 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
119 *cur
+= snprintf(buffer
+ *cur
, size
, "%4d: %-45s", id
, name
);
120 *cur
+= snprintf(buffer
+ *cur
, size
, "%llu",
121 arch_convert_raw_ts_entry(stamp
));
123 *cur
+= snprintf(buffer
+ *cur
, size
, " (");
124 *cur
+= snprintf(buffer
+ *cur
, size
, "%llu", step_time
);
125 *cur
+= snprintf(buffer
+ *cur
, size
, ")");
127 *cur
+= snprintf(buffer
+ *cur
, size
, "\n");
132 static int timestamps_module_init(void)
134 /* Make sure that lib_sysinfo is initialized */
135 int ret
= lib_get_sysinfo();
140 struct timestamp_table
*timestamps
= phys_to_virt(lib_sysinfo
.tstamp_table
);
142 if (timestamps
== NULL
)
145 /* Extract timestamps information */
146 u64 base_time
= timestamps
->base_time
;
147 u16 max_entries
= timestamps
->max_entries
;
148 u32 n_entries
= timestamps
->num_entries
;
150 timestamp_set_tick_freq(timestamps
->tick_freq_mhz
);
157 /* Allocate a buffer big enough to contain all of the possible
158 * entries plus the other information (number entries, total time). */
159 buffer
= malloc((max_entries
+ 4) * SCREEN_X
* sizeof(char));
164 /* Write the content */
165 buff_cur
+= snprintf(buffer
, SCREEN_X
, "%d entries total:\n\n",
169 timestamp_print_entry(buffer
, SCREEN_X
, &buff_cur
, 0, base_time
,
171 prev_stamp
= base_time
;
174 for (u32 i
= 0; i
< n_entries
; i
++) {
176 const struct timestamp_entry
*tse
= ×tamps
->entries
[i
];
178 stamp
= tse
->entry_stamp
+ base_time
;
179 total_time
+= timestamp_print_entry(buffer
, SCREEN_X
,
180 &buff_cur
, tse
->entry_id
, stamp
, prev_stamp
);
184 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "\nTotal Time: ");
185 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "%llu", total_time
);
186 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "\n");
188 /* Calculate how many characters will be displayed on screen */
189 u32 chars_count
= calculate_chars_count(buffer
, buff_cur
+ 1,
190 SCREEN_X
, LINES_SHOWN
);
192 /* Sanity check, chars_count must be padded to full line */
193 if (chars_count
% SCREEN_X
!= 0) {
198 g_lines_count
= chars_count
/ SCREEN_X
;
199 g_max_cursor_line
= MAX(g_lines_count
- 1 - LINES_SHOWN
, 0);
201 g_buf
= malloc(chars_count
);
207 if (sanitize_buffer_for_display(buffer
, buff_cur
+ 1, g_buf
,
208 chars_count
, SCREEN_X
) < 0) {
220 static int timestamps_module_redraw(WINDOW
*win
)
222 print_module_title(win
, "coreboot Timestamps");
228 char *tmp
= g_buf
+ g_line
* SCREEN_X
;
230 for (y
= 0; y
< LINES_SHOWN
; y
++) {
231 for (x
= 0; x
< SCREEN_X
; x
++) {
232 mvwaddch(win
, y
+ 2, x
, *tmp
);
240 static int timestamps_module_handle(int key
)
252 case KEY_NPAGE
: /* Page up */
253 g_line
-= LINES_SHOWN
;
255 case KEY_PPAGE
: /* Page down */
256 g_line
+= LINES_SHOWN
;
263 if (g_line
> g_max_cursor_line
)
264 g_line
= g_max_cursor_line
;
269 struct coreinfo_module timestamps_module
= {
270 .name
= "Timestamps",
271 .init
= timestamps_module_init
,
272 .redraw
= timestamps_module_redraw
,
273 .handle
= timestamps_module_handle
,
278 struct coreinfo_module timestamps_module
= {