blob: 770c1d2c9b691e2f0115989d37449cd4c61f39d2 [file] [log] [blame]
Vadim Bendebury32da8be2011-09-29 17:27:15 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
18 */
19
20#include <console/console.h>
Kyösti Mälkki1d7541f2014-02-17 21:34:42 +020021#include <console/cbmem_console.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -070022#include <cbmem.h>
Stefan Reinauerfd4f4132013-06-19 12:25:44 -070023#include <arch/early_variables.h>
Julius Wernerec5e5e02014-08-20 15:29:56 -070024#include <symbols.h>
Vadim Bendebury32da8be2011-09-29 17:27:15 -070025#include <string.h>
26
27/*
28 * Structure describing console buffer. It is overlaid on a flat memory area,
Martin Rothcbf2bd72013-07-09 21:51:14 -060029 * with buffer_body covering the extent of the memory. Once the buffer is
Vadim Bendebury32da8be2011-09-29 17:27:15 -070030 * full, the cursor keeps going but the data is dropped on the floor. This
31 * allows to tell how much data was lost in the process.
32 */
33struct cbmem_console {
34 u32 buffer_size;
35 u32 buffer_cursor;
36 u8 buffer_body[0];
37} __attribute__ ((__packed__));
38
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050039static struct cbmem_console *cbmem_console_p CAR_GLOBAL;
40
Kyösti Mälkki8659e402014-12-21 08:55:47 +020041static void copy_console_buffer(struct cbmem_console *old_cons_p,
42 struct cbmem_console *new_cons_p);
43
Vadim Bendebury32da8be2011-09-29 17:27:15 -070044#ifdef __PRE_RAM__
45/*
46 * While running from ROM, before DRAM is initialized, some area in cache as
47 * ram space is used for the console buffer storage. The size and location of
Julius Wernerec5e5e02014-08-20 15:29:56 -070048 * the area are defined by the linker script with _(e)preram_cbmem_console.
Vadim Bendebury32da8be2011-09-29 17:27:15 -070049 */
Gabe Black19e7e7d2011-10-01 04:27:32 -070050
Vadim Bendebury32da8be2011-09-29 17:27:15 -070051#else
52
53/*
54 * When running from RAM, a lot of console output is generated before CBMEM is
55 * reinitialized. This static buffer is used to store that output temporarily,
56 * to be concatenated with the CBMEM console buffer contents accumulated
57 * during the ROM stage, once CBMEM becomes available at RAM stage.
58 */
Stefan Reinauer19d06b22013-09-09 11:22:18 -070059
Kyösti Mälkki2fb6b402014-12-19 08:20:45 +020060#if IS_ENABLED(CONFIG_EARLY_CBMEM_INIT)
Stefan Reinauer19d06b22013-09-09 11:22:18 -070061#define STATIC_CONSOLE_SIZE 1024
62#else
Kyösti Mälkki44c0e4e2013-11-27 22:54:11 +020063#define STATIC_CONSOLE_SIZE CONFIG_CONSOLE_CBMEM_BUFFER_SIZE
Stefan Reinauer19d06b22013-09-09 11:22:18 -070064#endif
65static u8 static_console[STATIC_CONSOLE_SIZE];
Vadim Bendebury32da8be2011-09-29 17:27:15 -070066#endif
67
Kyösti Mälkki8659e402014-12-21 08:55:47 +020068/* flags for init */
69#define CBMEMC_RESET (1<<0)
70#define CBMEMC_APPEND (1<<1)
71
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050072static inline struct cbmem_console *current_console(void)
Vadim Bendebury32da8be2011-09-29 17:27:15 -070073{
Kyösti Mälkkie4554252014-12-31 18:34:59 +020074 return car_sync_var(cbmem_console_p);
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050075}
76
77static inline void current_console_set(struct cbmem_console *new_console_p)
78{
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050079 car_set_var(cbmem_console_p, new_console_p);
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050080}
81
Kyösti Mälkki8659e402014-12-21 08:55:47 +020082static inline void init_console_ptr(void *storage, u32 total_space, int flags)
Aaron Durbin2ad6bd22013-05-10 00:45:37 -050083{
84 struct cbmem_console *cbm_cons_p = storage;
85
Kyösti Mälkki8659e402014-12-21 08:55:47 +020086 if (!cbm_cons_p) {
87 current_console_set(NULL);
88 return;
89 }
90
91 if (flags & CBMEMC_RESET) {
92 cbm_cons_p->buffer_size = total_space - sizeof(struct cbmem_console);
93 cbm_cons_p->buffer_cursor = 0;
94 }
95 if (flags & CBMEMC_APPEND) {
96 struct cbmem_console *tmp_cons_p = current_console();
97 if (tmp_cons_p)
98 copy_console_buffer(tmp_cons_p, cbm_cons_p);
99 }
100
101 current_console_set(cbm_cons_p);
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500102}
103
104void cbmemc_init(void)
105{
106#ifdef __PRE_RAM__
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200107 int flags = CBMEMC_RESET;
108
109 /* Do not clear output from bootblock. */
110 if (ENV_ROMSTAGE && !IS_ENABLED(CONFIG_CACHE_AS_RAM))
111 if (IS_ENABLED(CONFIG_BOOTBLOCK_CONSOLE))
112 flags = 0;
113
Julius Wernerec5e5e02014-08-20 15:29:56 -0700114 init_console_ptr(_preram_cbmem_console,
115 _preram_cbmem_console_size, flags);
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500116#else
117 /*
118 * Initializing before CBMEM is available, use static buffer to store
119 * the log.
120 */
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200121 init_console_ptr(static_console, sizeof(static_console), CBMEMC_RESET);
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500122#endif
123}
124
125void cbmemc_tx_byte(unsigned char data)
126{
127 struct cbmem_console *cbm_cons_p = current_console();
128 u32 cursor;
129
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700130 if (!cbm_cons_p)
131 return;
132
133 cursor = cbm_cons_p->buffer_cursor++;
134 if (cursor < cbm_cons_p->buffer_size)
135 cbm_cons_p->buffer_body[cursor] = data;
136}
137
138/*
139 * Copy the current console buffer (either from the cache as RAM area, or from
140 * the static buffer, pointed at by cbmem_console_p) into the CBMEM console
141 * buffer space (pointed at by new_cons_p), concatenating the copied data with
142 * the CBMEM console buffer contents.
143 *
144 * If there is overflow - add to the destination area a string, reporting the
Martin Rothcbf2bd72013-07-09 21:51:14 -0600145 * overflow and the number of dropped characters.
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700146 */
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200147static void copy_console_buffer(struct cbmem_console *old_cons_p,
148 struct cbmem_console *new_cons_p)
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700149{
Kyösti Mälkkia3c5ba32013-11-27 17:51:31 +0200150 u32 copy_size, dropped_chars;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700151 u32 cursor = new_cons_p->buffer_cursor;
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500152
Kyösti Mälkkia3c5ba32013-11-27 17:51:31 +0200153 if (old_cons_p->buffer_cursor < old_cons_p->buffer_size)
154 copy_size = old_cons_p->buffer_cursor;
155 else
156 copy_size = old_cons_p->buffer_size;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700157
Kyösti Mälkkia3c5ba32013-11-27 17:51:31 +0200158 if (cursor > new_cons_p->buffer_size)
159 copy_size = 0;
160 else if (cursor + copy_size > new_cons_p->buffer_size)
161 copy_size = new_cons_p->buffer_size - cursor;
162
163 dropped_chars = old_cons_p->buffer_cursor - copy_size;
164 if (dropped_chars) {
165 /* Reserve 80 chars to report overflow, if possible. */
166 if (copy_size < 80)
167 return;
168 copy_size -= 80;
169 dropped_chars += 80;
170 }
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700171
Aaron Durbin2ad6bd22013-05-10 00:45:37 -0500172 memcpy(new_cons_p->buffer_body + cursor, old_cons_p->buffer_body,
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700173 copy_size);
174
175 cursor += copy_size;
176
Kyösti Mälkkia3c5ba32013-11-27 17:51:31 +0200177 if (dropped_chars) {
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700178 const char loss_str1[] = "\n\n*** Log truncated, ";
179 const char loss_str2[] = " characters dropped. ***\n\n";
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700180
181 /*
182 * When running from ROM sprintf is not available, a simple
183 * itoa implementation is used instead.
184 */
185 int got_first_digit = 0;
186
187 /* Way more than possible number of dropped characters. */
188 u32 mult = 100000;
189
190 strcpy((char *)new_cons_p->buffer_body + cursor, loss_str1);
191 cursor += sizeof(loss_str1) - 1;
192
193 while (mult) {
194 int digit = dropped_chars / mult;
195 if (got_first_digit || digit) {
196 new_cons_p->buffer_body[cursor++] = digit + '0';
197 dropped_chars %= mult;
198 /* Excessive, but keeps it simple */
199 got_first_digit = 1;
200 }
201 mult /= 10;
202 }
203
204 strcpy((char *)new_cons_p->buffer_body + cursor, loss_str2);
205 cursor += sizeof(loss_str2) - 1;
206 }
207 new_cons_p->buffer_cursor = cursor;
208}
209
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300210void cbmemc_reinit(void)
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700211{
Kyösti Mälkki52a27222013-09-09 01:31:22 +0300212 struct cbmem_console *cbm_cons_p = NULL;
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200213 int flags = CBMEMC_APPEND;
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700214
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200215 if (ENV_ROMSTAGE && (CONFIG_CONSOLE_PRERAM_BUFFER_SIZE == 0))
Kyösti Mälkki71b21452014-11-28 10:13:03 +0200216 return;
Kyösti Mälkki71b21452014-11-28 10:13:03 +0200217
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200218 /* If CBMEM entry already existed, old contents is not altered. */
219 cbm_cons_p = cbmem_add(CBMEM_ID_CONSOLE,
220 CONFIG_CONSOLE_CBMEM_BUFFER_SIZE);
Kyösti Mälkki52a27222013-09-09 01:31:22 +0300221
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200222 /* Clear old contents of CBMEM buffer. */
223 if (ENV_ROMSTAGE || (CONFIG_CONSOLE_PRERAM_BUFFER_SIZE == 0))
224 flags |= CBMEMC_RESET;
Kyösti Mälkki52a27222013-09-09 01:31:22 +0300225
Kyösti Mälkki8659e402014-12-21 08:55:47 +0200226 init_console_ptr(cbm_cons_p,
227 CONFIG_CONSOLE_CBMEM_BUFFER_SIZE, flags);
Vadim Bendebury32da8be2011-09-29 17:27:15 -0700228}
Kyösti Mälkkicbf5bdf2013-09-10 00:07:21 +0300229/* Call cbmemc_reinit() at CAR migration time. */
230CAR_MIGRATE(cbmemc_reinit)