blob: f6b0006db896091cb616320bd581e98195b720fc [file] [log] [blame]
Duncan Laurie7d2b81c2012-06-23 16:08:47 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 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
David Hendricks259e49a2014-03-20 20:31:23 -070020#if CONFIG_HAVE_ACPI_RESUME == 1
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070021#include <arch/acpi.h>
David Hendricks259e49a2014-03-20 20:31:23 -070022#endif
Duncan Laurie215f27852012-10-10 14:34:49 -070023#include <cbmem.h>
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070024#include <console/console.h>
David Hendricks259e49a2014-03-20 20:31:23 -070025#if CONFIG_ARCH_X86
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070026#include <pc80/mc146818rtc.h>
David Hendricks259e49a2014-03-20 20:31:23 -070027#endif
Gabe Blacka4c4b1c2014-04-30 21:41:23 -070028#include <bcd.h>
29#include <rtc.h>
Duncan Laurie472ec9c2012-06-23 16:13:42 -070030#include <smbios.h>
Zheng Bao600784e2013-02-07 17:30:23 +080031#include <spi-generic.h>
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070032#include <spi_flash.h>
33#include <stdint.h>
34#include <string.h>
35#include <elog.h>
36#include "elog_internal.h"
37
Duncan Laurie86bf3f52012-08-15 13:14:58 -070038#include <vendorcode/google/chromeos/fmap.h>
Edward O'Callaghana3119e52014-06-18 14:28:03 +100039
Stefan Reinauer45a225b2015-03-16 16:47:39 -070040#if !IS_ENABLED(CONFIG_CHROMEOS) && CONFIG_ELOG_FLASH_BASE == 0
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070041#error "CONFIG_ELOG_FLASH_BASE is invalid"
42#endif
43#if CONFIG_ELOG_FULL_THRESHOLD >= CONFIG_ELOG_AREA_SIZE
44#error "CONFIG_ELOG_FULL_THRESHOLD is larger than CONFIG_ELOG_AREA_SIZE"
45#endif
46#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_FULL_THRESHOLD) < (MAX_EVENT_SIZE + 1)
47#error "CONFIG_ELOG_FULL_THRESHOLD is too small"
48#endif
49#if CONFIG_ELOG_SHRINK_SIZE >= CONFIG_ELOG_AREA_SIZE
50#error "CONFIG_ELOG_SHRINK_SIZE is larger than CONFIG_ELOG_AREA_SIZE"
51#endif
52#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_SHRINK_SIZE) > \
53 CONFIG_ELOG_FULL_THRESHOLD
54#error "CONFIG_ELOG_SHRINK_SIZE is too large"
55#endif
56
57#if CONFIG_ELOG_DEBUG
58#define elog_debug(STR...) printk(BIOS_DEBUG, STR)
59#else
60#define elog_debug(STR...)
61#endif
62
63/*
64 * Static variables for ELOG state
65 */
Gabe Black0bf1feb2013-04-26 03:34:00 -070066static struct elog_area *elog_area;
67static u16 total_size;
68static u16 log_size;
69static u32 flash_base;
70
71static elog_area_state area_state;
72static elog_header_state header_state;
73static elog_event_buffer_state event_buffer_state;
74
75static u16 next_event_offset;
76static u16 event_count;
77
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070078static int elog_initialized;
79static struct spi_flash *elog_spi;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070080
Aaron Durbin10a070b2013-06-28 12:30:53 -070081
82static inline u32 get_rom_size(void)
83{
84 u32 rom_size;
85
86 /* Assume the used space of the ROM image starts from 0. The
87 * physical size of the device may not be completely used. */
88 rom_size = elog_spi->size;
89 if (rom_size > CONFIG_ROM_SIZE)
90 rom_size = CONFIG_ROM_SIZE;
91
92 return rom_size;
93}
94
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070095/*
96 * Convert a memory mapped flash address into a flash offset
97 */
98static inline u32 elog_flash_address_to_offset(u8 *address)
99{
David Hendricks259e49a2014-03-20 20:31:23 -0700100#if CONFIG_ARCH_X86
101 /* For x86, assume address is memory-mapped near 4GB */
Aaron Durbin10a070b2013-06-28 12:30:53 -0700102 u32 rom_size;
103
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700104 if (!elog_spi)
105 return 0;
Aaron Durbin10a070b2013-06-28 12:30:53 -0700106
107 rom_size = get_rom_size();
108
109 return (u32)address - ((u32)~0UL - rom_size + 1);
David Hendricks259e49a2014-03-20 20:31:23 -0700110#else
Furquan Shaikhfd2f0302014-11-12 16:19:37 -0800111 return (u32)(uintptr_t)address;
David Hendricks259e49a2014-03-20 20:31:23 -0700112#endif
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700113}
114
115/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700116 * Pointer to an event log header in the event data area
117 */
118static inline struct event_header*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700119elog_get_event_base(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700120{
Gabe Black0bf1feb2013-04-26 03:34:00 -0700121 return (struct event_header *)&elog_area->data[offset];
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700122}
123
124/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700125 * Update the checksum at the last byte
126 */
127static void elog_update_checksum(struct event_header *event, u8 checksum)
128{
129 u8 *event_data = (u8*)event;
130 event_data[event->length - 1] = checksum;
131}
132
133/*
134 * Simple byte checksum for events
135 */
136static u8 elog_checksum_event(struct event_header *event)
137{
138 u8 index, checksum = 0;
139 u8 *data = (u8*)event;
140
141 for (index = 0; index < event->length; index++)
142 checksum += data[index];
143 return checksum;
144}
145
146/*
147 * Check if a raw buffer is filled with ELOG_TYPE_EOL byte
148 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700149static int elog_is_buffer_clear(void *base, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700150{
151 u8 *current = base;
152 u8 *end = current + size;
153
154 elog_debug("elog_is_buffer_clear(base=0x%p size=%u)\n", base, size);
155
156 for (; current != end; current++) {
157 if (*current != ELOG_TYPE_EOL)
158 return 0;
159 }
160 return 1;
161}
162
163/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700164 * Check that the ELOG area has been initialized and is valid.
165 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700166static int elog_is_area_valid(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700167{
168 elog_debug("elog_is_area_valid()\n");
169
Gabe Black0bf1feb2013-04-26 03:34:00 -0700170 if (area_state != ELOG_AREA_HAS_CONTENT)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700171 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700172 if (header_state != ELOG_HEADER_VALID)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700173 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700174 if (event_buffer_state != ELOG_EVENT_BUFFER_OK)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700175 return 0;
176 return 1;
177}
178
179/*
180 * Verify the contents of an ELOG Header structure
181 * Returns 1 if the header is valid, 0 otherwise
182 */
183static int elog_is_header_valid(struct elog_header *header)
184{
185 elog_debug("elog_is_header_valid()\n");
186
187 if (header->magic != ELOG_SIGNATURE) {
188 printk(BIOS_ERR, "ELOG: header magic 0x%X != 0x%X\n",
189 header->magic, ELOG_SIGNATURE);
190 return 0;
191 }
192 if (header->version != ELOG_VERSION) {
193 printk(BIOS_ERR, "ELOG: header version %u != %u\n",
194 header->version, ELOG_VERSION);
195 return 0;
196 }
197 if (header->header_size != sizeof(*header)) {
Denis 'GNUtoo' Cariklibc2c9ef2013-06-26 20:04:49 +0200198 printk(BIOS_ERR, "ELOG: header size mismatch %u != %zu\n",
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700199 header->header_size, sizeof(*header));
200 return 0;
201 }
202 return 1;
203}
204
205/*
206 * Validate the event header and data.
207 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700208static int elog_is_event_valid(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700209{
210 struct event_header *event;
211
Gabe Black0bf1feb2013-04-26 03:34:00 -0700212 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700213 if (!event)
214 return 0;
215
216 /* Validate event length */
217 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700218 sizeof(event->type) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700219 return 0;
220
221 /* End of event marker has been found */
222 if (event->type == ELOG_TYPE_EOL)
223 return 0;
224
225 /* Check if event fits in area */
226 if ((offsetof(struct event_header, length) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700227 sizeof(event->length) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700228 return 0;
229
230 /*
231 * If the current event length + the current offset exceeds
232 * the area size then the event area is corrupt.
233 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700234 if ((event->length + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700235 return 0;
236
237 /* Event length must be at least header size + checksum */
238 if (event->length < (sizeof(*event) + 1))
239 return 0;
240
241 /* If event checksum is invalid the area is corrupt */
242 if (elog_checksum_event(event) != 0)
243 return 0;
244
245 /* Event is valid */
246 return 1;
247}
248
249/*
Gabe Black331eb082013-04-24 04:11:40 -0700250 * Write 'size' bytes of data pointed to by 'address' in the flash backing
251 * store into flash. This will not erase the flash and it assumes the flash
252 * area has been erased appropriately.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700253 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700254static void elog_flash_write(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700255{
256 u32 offset;
257
Gabe Black331eb082013-04-24 04:11:40 -0700258 if (!address || !size || !elog_spi)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700259 return;
260
Gabe Black0bf1feb2013-04-26 03:34:00 -0700261 offset = flash_base;
262 offset += (u8 *)address - (u8 *)elog_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700263
Gabe Black331eb082013-04-24 04:11:40 -0700264 elog_debug("elog_flash_write(address=0x%p offset=0x%08x size=%u)\n",
265 address, offset, size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700266
267 /* Write the data to flash */
Gabe Black331eb082013-04-24 04:11:40 -0700268 elog_spi->write(elog_spi, offset, size, address);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700269}
270
271/*
272 * Erase the first block specified in the address.
273 * Only handles flash area within a single flash block.
274 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700275static void elog_flash_erase(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700276{
277 u32 offset;
278
279 if (!address || !size || !elog_spi)
280 return;
281
Gabe Black0bf1feb2013-04-26 03:34:00 -0700282 offset = flash_base;
283 offset += (u8 *)address - (u8*)elog_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700284
285 elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
286 address, offset, size);
287
288 /* Erase the sectors in this region */
289 elog_spi->erase(elog_spi, offset, size);
290}
291
292/*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700293 * Scan the event area and validate each entry and update the ELOG state.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700294 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700295static void elog_update_event_buffer_state(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700296{
297 u32 count = 0;
298 u32 offset = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700299 struct event_header *event;
300
301 elog_debug("elog_update_event_buffer_state()\n");
302
303 /* Go through each event and validate it */
304 while (1) {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700305 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700306
307 /* Do not de-reference anything past the area length */
308 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700309 sizeof(event->type) - 1 + offset) >= log_size) {
310 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700311 break;
312 }
313
314 /* The end of the event marker has been found */
315 if (event->type == ELOG_TYPE_EOL)
316 break;
317
318 /* Validate the event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700319 if (!elog_is_event_valid(offset)) {
320 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700321 break;
322 }
323
324 /* Move to the next event */
325 count++;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700326 offset += event->length;
327 }
328
329 /* Ensure the remaining buffer is empty */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700330 if (!elog_is_buffer_clear(&elog_area->data[offset], log_size - offset))
331 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700332
Gabe Black0bf1feb2013-04-26 03:34:00 -0700333 /* Update ELOG state */
334 event_count = count;
335 next_event_offset = offset;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700336}
337
Gabe Black0bf1feb2013-04-26 03:34:00 -0700338static void elog_scan_flash(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700339{
Gabe Black84a93d12013-04-24 23:31:41 -0700340 elog_debug("elog_scan_flash()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700341
Gabe Black0bf1feb2013-04-26 03:34:00 -0700342 area_state = ELOG_AREA_UNDEFINED;
343 header_state = ELOG_HEADER_INVALID;
344 event_buffer_state = ELOG_EVENT_BUFFER_OK;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700345
Duncan Laurie215f27852012-10-10 14:34:49 -0700346 /* Fill memory buffer by reading from SPI */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700347 elog_spi->read(elog_spi, flash_base, total_size, elog_area);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700348
Gabe Black0bf1feb2013-04-26 03:34:00 -0700349 next_event_offset = 0;
350 event_count = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700351
Gabe Black455c68e2013-04-24 17:54:37 -0700352 /* Check if the area is empty or not */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700353 if (elog_is_buffer_clear(elog_area, total_size)) {
354 area_state = ELOG_AREA_EMPTY;
Gabe Black455c68e2013-04-24 17:54:37 -0700355 return;
356 }
357
Gabe Black0bf1feb2013-04-26 03:34:00 -0700358 area_state = ELOG_AREA_HAS_CONTENT;
Gabe Black455c68e2013-04-24 17:54:37 -0700359
360 /* Validate the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700361 if (!elog_is_header_valid(&elog_area->header)) {
362 header_state = ELOG_HEADER_INVALID;
Gabe Black455c68e2013-04-24 17:54:37 -0700363 return;
364 }
365
Gabe Black0bf1feb2013-04-26 03:34:00 -0700366 header_state = ELOG_HEADER_VALID;
367 elog_update_event_buffer_state();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700368}
369
Gabe Black0bf1feb2013-04-26 03:34:00 -0700370static void elog_prepare_empty(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700371{
372 struct elog_header *header;
373
Gabe Black0bf1feb2013-04-26 03:34:00 -0700374 elog_debug("elog_prepare_empty()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700375
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700376 /* Write out the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700377 header = &elog_area->header;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700378 header->magic = ELOG_SIGNATURE;
379 header->version = ELOG_VERSION;
380 header->header_size = sizeof(struct elog_header);
381 header->reserved[0] = ELOG_TYPE_EOL;
382 header->reserved[1] = ELOG_TYPE_EOL;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700383 elog_flash_write(elog_area, header->header_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700384
Gabe Black0bf1feb2013-04-26 03:34:00 -0700385 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700386}
387
388/*
389 * Shrink the log, deleting old entries and moving the
Martin Roth56889792013-07-09 21:39:46 -0600390 * remaining ones to the front of the log.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700391 */
392static int elog_shrink(void)
393{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700394 struct event_header *event;
395 u16 discard_count = 0;
396 u16 offset = 0;
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700397 u16 new_size = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700398
399 elog_debug("elog_shrink()\n");
400
Gabe Black0bf1feb2013-04-26 03:34:00 -0700401 if (next_event_offset < CONFIG_ELOG_SHRINK_SIZE)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700402 return 0;
403
404 while (1) {
405 /* Next event has exceeded constraints */
406 if (offset > CONFIG_ELOG_SHRINK_SIZE)
407 break;
408
Gabe Black0bf1feb2013-04-26 03:34:00 -0700409 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700410
411 /* Reached the end of the area */
412 if (!event || event->type == ELOG_TYPE_EOL)
413 break;
414
415 offset += event->length;
416 discard_count++;
417 }
418
Gabe Black0bf1feb2013-04-26 03:34:00 -0700419 new_size = next_event_offset - offset;
420 memmove(&elog_area->data[0], &elog_area->data[offset], new_size);
421 memset(&elog_area->data[new_size], ELOG_TYPE_EOL, log_size - new_size);
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700422
Gabe Black0bf1feb2013-04-26 03:34:00 -0700423 elog_flash_erase(elog_area, total_size);
424 elog_flash_write(elog_area, total_size);
425 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700426
Duncan Laurie032be822013-05-23 07:23:09 -0700427 /* Ensure the area was successfully erased */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700428 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD) {
Duncan Laurie032be822013-05-23 07:23:09 -0700429 printk(BIOS_ERR, "ELOG: Flash area was not erased!\n");
430 return -1;
431 }
432
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700433 /* Add clear event */
434 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, offset);
435
436 return 0;
437}
438
Duncan Laurie215f27852012-10-10 14:34:49 -0700439#ifndef __SMM__
Furquan Shaikh7f4221c2014-11-12 16:19:37 -0800440#if IS_ENABLED(CONFIG_ARCH_X86)
441
442/*
443 * Convert a flash offset into a memory mapped flash address
444 */
445static inline u8 *elog_flash_offset_to_address(u32 offset)
446{
447 u32 rom_size;
448
449 if (!elog_spi)
450 return NULL;
451
452 rom_size = get_rom_size();
453
454 return (u8 *)((u32)~0UL - rom_size + 1 + offset);
455}
456
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700457/*
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700458 * Fill out SMBIOS Type 15 table entry so the
459 * event log can be discovered at runtime.
460 */
461int elog_smbios_write_type15(unsigned long *current, int handle)
462{
463 struct smbios_type15 *t = (struct smbios_type15 *)*current;
464 int len = sizeof(struct smbios_type15);
465
Duncan Laurie215f27852012-10-10 14:34:49 -0700466#if CONFIG_ELOG_CBMEM
467 /* Save event log buffer into CBMEM for the OS to read */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700468 void *cbmem = cbmem_add(CBMEM_ID_ELOG, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700469 if (!cbmem)
470 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700471 memcpy(cbmem, elog_area, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700472#endif
473
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700474 memset(t, 0, len);
475 t->type = SMBIOS_EVENT_LOG;
476 t->length = len - 2;
477 t->handle = handle;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700478 t->area_length = total_size - 1;
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700479 t->header_offset = 0;
480 t->data_offset = sizeof(struct elog_header);
481 t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
482 t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
483 t->change_token = 0;
Duncan Laurie215f27852012-10-10 14:34:49 -0700484#if CONFIG_ELOG_CBMEM
485 t->address = (u32)cbmem;
486#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700487 t->address = (u32)elog_flash_offset_to_address(flash_base);
Duncan Laurie215f27852012-10-10 14:34:49 -0700488#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700489 t->header_format = ELOG_HEADER_TYPE_OEM;
490 t->log_type_descriptors = 0;
491 t->log_type_descriptor_length = 2;
492
493 *current += len;
494 return len;
495}
Duncan Laurie215f27852012-10-10 14:34:49 -0700496#endif
Furquan Shaikh7f4221c2014-11-12 16:19:37 -0800497#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700498
499/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700500 * Clear the entire event log
501 */
502int elog_clear(void)
503{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700504 elog_debug("elog_clear()\n");
505
Gabe Black8f4baec2013-04-25 17:21:58 -0700506 /* Make sure ELOG structures are initialized */
507 if (elog_init() < 0)
508 return -1;
509
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700510 /* Erase flash area */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700511 elog_flash_erase(elog_area, total_size);
512 elog_prepare_empty();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700513
Gabe Black0bf1feb2013-04-26 03:34:00 -0700514 if (!elog_is_area_valid())
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700515 return -1;
516
517 /* Log the clear event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700518 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700519
520 return 0;
521}
522
Gabe Black0bf1feb2013-04-26 03:34:00 -0700523static void elog_find_flash(void)
Gabe Black84a93d12013-04-24 23:31:41 -0700524{
525#if CONFIG_CHROMEOS
526 u8 *flash_base_ptr;
527#endif
528
Gabe Black0bf1feb2013-04-26 03:34:00 -0700529 elog_debug("elog_find_flash()\n");
Gabe Black84a93d12013-04-24 23:31:41 -0700530
531#if CONFIG_CHROMEOS
532 /* Find the ELOG base and size in FMAP */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700533 total_size = find_fmap_entry("RW_ELOG", (void **)&flash_base_ptr);
534 if (total_size < 0) {
Gabe Black84a93d12013-04-24 23:31:41 -0700535 printk(BIOS_WARNING, "ELOG: Unable to find RW_ELOG in FMAP, "
536 "using CONFIG_ELOG_FLASH_BASE instead\n");
Gabe Black0bf1feb2013-04-26 03:34:00 -0700537 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700538 } else {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700539 flash_base = elog_flash_address_to_offset(flash_base_ptr);
Gabe Black84a93d12013-04-24 23:31:41 -0700540
541 /* Use configured size if smaller than FMAP size */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700542 if (total_size > CONFIG_ELOG_AREA_SIZE)
543 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700544 }
545#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700546 flash_base = CONFIG_ELOG_FLASH_BASE;
547 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700548#endif
Gabe Black0bf1feb2013-04-26 03:34:00 -0700549 log_size = total_size - sizeof(struct elog_header);
Gabe Black84a93d12013-04-24 23:31:41 -0700550}
551
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700552/*
553 * Event log main entry point
554 */
555int elog_init(void)
556{
557 if (elog_initialized)
558 return 0;
559
560 elog_debug("elog_init()\n");
561
David Hendricks9acbd6f2014-04-13 16:45:31 -0700562 /* Probe SPI chip. SPI controller must already be initialized. */
David Hendricksc9470242014-04-14 14:57:36 -0700563 elog_spi = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
Gabe Black84a93d12013-04-24 23:31:41 -0700564 if (!elog_spi) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700565 printk(BIOS_ERR, "ELOG: Unable to find SPI flash\n");
566 return -1;
567 }
568
Gabe Black84a93d12013-04-24 23:31:41 -0700569 /* Set up the backing store */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700570 elog_find_flash();
Gabe Black84a93d12013-04-24 23:31:41 -0700571 if (flash_base == 0) {
572 printk(BIOS_ERR, "ELOG: Invalid flash base\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700573 return -1;
574 }
575
Gabe Black0bf1feb2013-04-26 03:34:00 -0700576 elog_area = malloc(total_size);
577 if (!elog_area) {
Gabe Black84a93d12013-04-24 23:31:41 -0700578 printk(BIOS_ERR, "ELOG: Unable to allocate backing store\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700579 return -1;
580 }
Gabe Black84a93d12013-04-24 23:31:41 -0700581
582 /* Load the log from flash */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700583 elog_scan_flash();
Gabe Black84a93d12013-04-24 23:31:41 -0700584
585 /* Prepare the flash if necessary */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700586 if (header_state == ELOG_HEADER_INVALID ||
587 event_buffer_state == ELOG_EVENT_BUFFER_CORRUPTED) {
Gabe Black84a93d12013-04-24 23:31:41 -0700588 /* If the header is invalid or the events are corrupted,
589 * no events can be salvaged so erase the entire area. */
590 printk(BIOS_ERR, "ELOG: flash area invalid\n");
Gabe Black0bf1feb2013-04-26 03:34:00 -0700591 elog_flash_erase(elog_area, total_size);
592 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700593 }
594
Gabe Black0bf1feb2013-04-26 03:34:00 -0700595 if (area_state == ELOG_AREA_EMPTY)
596 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700597
Gabe Black0bf1feb2013-04-26 03:34:00 -0700598 if (!elog_is_area_valid()) {
Gabe Black84a93d12013-04-24 23:31:41 -0700599 printk(BIOS_ERR, "ELOG: Unable to prepare flash\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700600 return -1;
601 }
602
603 elog_initialized = 1;
604
Gabe Black331eb082013-04-24 04:11:40 -0700605 printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08x]\n",
Gabe Black0bf1feb2013-04-26 03:34:00 -0700606 elog_area, flash_base);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700607
Gabe Black84a93d12013-04-24 23:31:41 -0700608 printk(BIOS_INFO, "ELOG: area is %d bytes, full threshold %d,"
Gabe Black0bf1feb2013-04-26 03:34:00 -0700609 " shrink size %d\n", total_size,
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700610 CONFIG_ELOG_FULL_THRESHOLD, CONFIG_ELOG_SHRINK_SIZE);
611
612 /* Log a clear event if necessary */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700613 if (event_count == 0)
614 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700615
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700616 /* Shrink the log if we are getting too full */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700617 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie032be822013-05-23 07:23:09 -0700618 if (elog_shrink() < 0)
619 return -1;
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700620
Gabe Black84a93d12013-04-24 23:31:41 -0700621#if !defined(__SMM__)
Duncan Laurief4d36232012-06-23 16:37:45 -0700622 /* Log boot count event except in S3 resume */
David Hendricks259e49a2014-03-20 20:31:23 -0700623#if CONFIG_ELOG_BOOT_COUNT == 1
624#if CONFIG_HAVE_ACPI_RESUME == 1
625 if (!acpi_is_wakeup_s3())
626#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700627 elog_add_event_dword(ELOG_TYPE_BOOT, boot_count_read());
David Hendricks6a29e6c2014-06-18 13:03:03 -0700628#else
629 /* If boot count is not implemented, fake it. */
630 elog_add_event_dword(ELOG_TYPE_BOOT, 0);
David Hendricks259e49a2014-03-20 20:31:23 -0700631#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700632
David Hendricks259e49a2014-03-20 20:31:23 -0700633#if CONFIG_ARCH_X86
Duncan Laurie1fc34612012-09-09 19:14:45 -0700634 /* Check and log POST codes from previous boot */
Gabe Black84a93d12013-04-24 23:31:41 -0700635 if (CONFIG_CMOS_POST)
636 cmos_post_log();
Duncan Laurie1fc34612012-09-09 19:14:45 -0700637#endif
David Hendricks259e49a2014-03-20 20:31:23 -0700638#endif
Duncan Laurie1fc34612012-09-09 19:14:45 -0700639
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700640 return 0;
641}
642
643/*
644 * Populate timestamp in event header with current time
645 */
646static void elog_fill_timestamp(struct event_header *event)
647{
Gabe Blacka4c4b1c2014-04-30 21:41:23 -0700648 struct rtc_time time;
649
650 rtc_get(&time);
651 event->second = bin2bcd(time.sec);
652 event->minute = bin2bcd(time.min);
653 event->hour = bin2bcd(time.hour);
654 event->day = bin2bcd(time.mday);
655 event->month = bin2bcd(time.mon);
656 event->year = bin2bcd(time.year) & 0xff;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700657
658 /* Basic sanity check of expected ranges */
659 if (event->month > 0x12 || event->day > 0x31 || event->hour > 0x23 ||
660 event->minute > 0x59 || event->second > 0x59) {
661 event->year = 0;
662 event->month = 0;
663 event->day = 0;
664 event->hour = 0;
665 event->minute = 0;
666 event->second = 0;
667 }
668}
669
670/*
Gabe Black331eb082013-04-24 04:11:40 -0700671 * Add an event to the log
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700672 */
Gabe Black331eb082013-04-24 04:11:40 -0700673void elog_add_event_raw(u8 event_type, void *data, u8 data_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700674{
675 struct event_header *event;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700676 u8 event_size;
677
Gabe Black331eb082013-04-24 04:11:40 -0700678 elog_debug("elog_add_event_raw(type=%X)\n", event_type);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700679
680 /* Make sure ELOG structures are initialized */
681 if (elog_init() < 0)
Gabe Black331eb082013-04-24 04:11:40 -0700682 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700683
684 /* Header + Data + Checksum */
685 event_size = sizeof(*event) + data_size + 1;
686 if (event_size > MAX_EVENT_SIZE) {
687 printk(BIOS_ERR, "ELOG: Event(%X) data size too "
688 "big (%d)\n", event_type, event_size);
Gabe Black331eb082013-04-24 04:11:40 -0700689 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700690 }
691
692 /* Make sure event data can fit */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700693 if ((next_event_offset + event_size) >= log_size) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700694 printk(BIOS_ERR, "ELOG: Event(%X) does not fit\n",
695 event_type);
Gabe Black331eb082013-04-24 04:11:40 -0700696 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700697 }
698
699 /* Fill out event data */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700700 event = elog_get_event_base(next_event_offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700701 event->type = event_type;
702 event->length = event_size;
703 elog_fill_timestamp(event);
704
705 if (data_size)
706 memcpy(&event[1], data, data_size);
707
708 /* Zero the checksum byte and then compute checksum */
709 elog_update_checksum(event, 0);
710 elog_update_checksum(event, -(elog_checksum_event(event)));
711
Gabe Black0bf1feb2013-04-26 03:34:00 -0700712 /* Update the ELOG state */
713 event_count++;
Gabe Black331eb082013-04-24 04:11:40 -0700714
715 elog_flash_write((void *)event, event_size);
716
Gabe Black0bf1feb2013-04-26 03:34:00 -0700717 next_event_offset += event_size;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700718
719 printk(BIOS_INFO, "ELOG: Event(%X) added with size %d\n",
720 event_type, event_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700721
722 /* Shrink the log if we are getting too full */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700723 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700724 elog_shrink();
725}
726
727void elog_add_event(u8 event_type)
728{
729 elog_add_event_raw(event_type, NULL, 0);
730}
731
732void elog_add_event_byte(u8 event_type, u8 data)
733{
734 elog_add_event_raw(event_type, &data, sizeof(data));
735}
736
737void elog_add_event_word(u8 event_type, u16 data)
738{
739 elog_add_event_raw(event_type, &data, sizeof(data));
740}
741
742void elog_add_event_dword(u8 event_type, u32 data)
743{
744 elog_add_event_raw(event_type, &data, sizeof(data));
745}
746
747void elog_add_event_wake(u8 source, u32 instance)
748{
749 struct elog_event_data_wake wake = {
750 .source = source,
751 .instance = instance
752 };
753 elog_add_event_raw(ELOG_TYPE_WAKE_SOURCE, &wake, sizeof(wake));
754}