2 * This file is part of the coreinfo project.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <commonlib/timestamp_serialized.h>
17 #if IS_ENABLED(CONFIG_MODULE_TIMESTAMPS)
19 #define LINES_SHOWN 19
22 /* Globals that are used for tracking screen state */
25 static s32 g_lines_count
;
26 static s32 g_max_cursor_line
;
28 static unsigned long tick_freq_mhz
;
30 static const char *timestamp_name(uint32_t id
)
34 for (i
= 0; i
< ARRAY_SIZE(timestamp_ids
); i
++) {
35 if (timestamp_ids
[i
].id
== id
)
36 return timestamp_ids
[i
].name
;
42 static void timestamp_set_tick_freq(unsigned long table_tick_freq_mhz
)
44 tick_freq_mhz
= table_tick_freq_mhz
;
46 /* Honor table frequency. */
50 tick_freq_mhz
= lib_sysinfo
.cpu_khz
/ 1000;
53 fprintf(stderr
, "Cannot determine timestamp tick frequency.\n");
58 static u64
arch_convert_raw_ts_entry(u64 ts
)
60 return ts
/ tick_freq_mhz
;
63 static u32
char_width(char c
, u32 cursor
, u32 screen_width
)
66 return screen_width
- (cursor
% screen_width
);
75 static u32
calculate_chars_count(char *str
, u32 str_len
, u32 screen_width
,
80 for (i
= 0; i
< str_len
; i
++)
81 count
+= char_width(str
[i
], count
, screen_width
);
83 /* Ensure that 'count' can occupy at least the whole screen */
84 if (count
< screen_width
* screen_height
)
85 count
= screen_width
* screen_height
;
88 if (count
% screen_width
!= 0)
89 count
+= screen_width
- (count
% screen_width
);
95 * This method takes an input buffer and sanitizes it for display, which means:
96 * - '\n' is converted to spaces until end of line
97 * - Tabs are converted to spaces of size TAB_WIDTH
98 * - Only printable characters are preserved
100 static int sanitize_buffer_for_display(char *str
, u32 str_len
, char *out
,
101 u32 out_len
, u32 screen_width
)
106 for (i
= 0; i
< str_len
&& cursor
< out_len
; i
++) {
107 u32 width
= char_width(str
[i
], cursor
, screen_width
);
110 out
[cursor
++] = str
[i
];
112 while (width
-- && cursor
< out_len
)
116 /* Fill the rest of the out buffer with spaces */
117 while (cursor
< out_len
)
123 static uint64_t timestamp_print_entry(char *buffer
, size_t size
, uint32_t *cur
,
124 uint32_t id
, uint64_t stamp
, uint64_t prev_stamp
)
129 name
= timestamp_name(id
);
130 step_time
= arch_convert_raw_ts_entry(stamp
- prev_stamp
);
132 *cur
+= snprintf(buffer
+ *cur
, size
, "%4d: %-45s", id
, name
);
133 *cur
+= snprintf(buffer
+ *cur
, size
, "%llu",
134 arch_convert_raw_ts_entry(stamp
));
136 *cur
+= snprintf(buffer
+ *cur
, size
, " (");
137 *cur
+= snprintf(buffer
+ *cur
, size
, "%llu", step_time
);
138 *cur
+= snprintf(buffer
+ *cur
, size
, ")");
140 *cur
+= snprintf(buffer
+ *cur
, size
, "\n");
145 static int timestamps_module_init(void)
147 /* Make sure that lib_sysinfo is initialized */
148 int ret
= lib_get_sysinfo();
153 struct timestamp_table
*timestamps
= lib_sysinfo
.tstamp_table
;
155 if (timestamps
== NULL
)
158 /* Extract timestamps information */
159 u64 base_time
= timestamps
->base_time
;
160 u16 max_entries
= timestamps
->max_entries
;
161 u32 n_entries
= timestamps
->num_entries
;
163 timestamp_set_tick_freq(timestamps
->tick_freq_mhz
);
170 /* Allocate a buffer big enough to contain all of the possible
171 * entries plus the other information (number entries, total time). */
172 buffer
= malloc((max_entries
+ 4) * SCREEN_X
* sizeof(char));
177 /* Write the content */
178 buff_cur
+= snprintf(buffer
, SCREEN_X
, "%d entries total:\n\n",
182 timestamp_print_entry(buffer
, SCREEN_X
, &buff_cur
, 0, base_time
,
184 prev_stamp
= base_time
;
187 for (int i
= 0; i
< n_entries
; i
++) {
189 const struct timestamp_entry
*tse
= ×tamps
->entries
[i
];
191 stamp
= tse
->entry_stamp
+ base_time
;
192 total_time
+= timestamp_print_entry(buffer
, SCREEN_X
,
193 &buff_cur
, tse
->entry_id
, stamp
, prev_stamp
);
197 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "\nTotal Time: ");
198 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "%llu", total_time
);
199 buff_cur
+= snprintf(buffer
+ buff_cur
, SCREEN_X
, "\n");
201 /* Calculate how many characters will be displayed on screen */
202 u32 chars_count
= calculate_chars_count(buffer
, buff_cur
+ 1,
203 SCREEN_X
, LINES_SHOWN
);
205 /* Sanity check, chars_count must be padded to full line */
206 if (chars_count
% SCREEN_X
!= 0)
209 g_lines_count
= chars_count
/ SCREEN_X
;
210 g_max_cursor_line
= MAX(g_lines_count
- 1 - LINES_SHOWN
, 0);
212 g_buf
= malloc(chars_count
);
218 if (sanitize_buffer_for_display(buffer
, buff_cur
+ 1, g_buf
,
219 chars_count
, SCREEN_X
) < 0) {
231 static int timestamps_module_redraw(WINDOW
*win
)
233 print_module_title(win
, "coreboot Timestamps");
239 char *tmp
= g_buf
+ g_line
* SCREEN_X
;
241 for (y
= 0; y
< LINES_SHOWN
; y
++) {
242 for (x
= 0; x
< SCREEN_X
; x
++) {
243 mvwaddch(win
, y
+ 2, x
, *tmp
);
251 static int timestamps_module_handle(int key
)
263 case KEY_NPAGE
: /* Page up */
264 g_line
-= LINES_SHOWN
;
266 case KEY_PPAGE
: /* Page down */
267 g_line
+= LINES_SHOWN
;
274 if (g_line
> g_max_cursor_line
)
275 g_line
= g_max_cursor_line
;
280 struct coreinfo_module timestamps_module
= {
281 .name
= "Timestamps",
282 .init
= timestamps_module_init
,
283 .redraw
= timestamps_module_redraw
,
284 .handle
= timestamps_module_handle
,
289 struct coreinfo_module timestamps_module
= {