blob: 7cc7e45aa2692f72ecdce89e9b9963b6dfd2ca92 [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
Duncan Laurie472ec9c2012-06-23 16:13:42 -070028#include <smbios.h>
Zheng Bao600784e2013-02-07 17:30:23 +080029#include <spi-generic.h>
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070030#include <spi_flash.h>
31#include <stdint.h>
32#include <string.h>
33#include <elog.h>
34#include "elog_internal.h"
35
David Hendricks259e49a2014-03-20 20:31:23 -070036#if CONFIG_CHROMEOS
Duncan Laurie86bf3f52012-08-15 13:14:58 -070037#include <vendorcode/google/chromeos/fmap.h>
Edward O'Callaghana3119e52014-06-18 14:28:03 +100038
39#if CONFIG_ELOG_FLASH_BASE == 0
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070040#error "CONFIG_ELOG_FLASH_BASE is invalid"
41#endif
42#if CONFIG_ELOG_FULL_THRESHOLD >= CONFIG_ELOG_AREA_SIZE
43#error "CONFIG_ELOG_FULL_THRESHOLD is larger than CONFIG_ELOG_AREA_SIZE"
44#endif
45#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_FULL_THRESHOLD) < (MAX_EVENT_SIZE + 1)
46#error "CONFIG_ELOG_FULL_THRESHOLD is too small"
47#endif
48#if CONFIG_ELOG_SHRINK_SIZE >= CONFIG_ELOG_AREA_SIZE
49#error "CONFIG_ELOG_SHRINK_SIZE is larger than CONFIG_ELOG_AREA_SIZE"
50#endif
51#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_SHRINK_SIZE) > \
52 CONFIG_ELOG_FULL_THRESHOLD
53#error "CONFIG_ELOG_SHRINK_SIZE is too large"
54#endif
55
56#if CONFIG_ELOG_DEBUG
57#define elog_debug(STR...) printk(BIOS_DEBUG, STR)
58#else
59#define elog_debug(STR...)
60#endif
61
62/*
63 * Static variables for ELOG state
64 */
Gabe Black0bf1feb2013-04-26 03:34:00 -070065static struct elog_area *elog_area;
66static u16 total_size;
67static u16 log_size;
68static u32 flash_base;
69
70static elog_area_state area_state;
71static elog_header_state header_state;
72static elog_event_buffer_state event_buffer_state;
73
74static u16 next_event_offset;
75static u16 event_count;
76
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070077static int elog_initialized;
78static struct spi_flash *elog_spi;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070079
Aaron Durbin10a070b2013-06-28 12:30:53 -070080
81static inline u32 get_rom_size(void)
82{
83 u32 rom_size;
84
85 /* Assume the used space of the ROM image starts from 0. The
86 * physical size of the device may not be completely used. */
87 rom_size = elog_spi->size;
88 if (rom_size > CONFIG_ROM_SIZE)
89 rom_size = CONFIG_ROM_SIZE;
90
91 return rom_size;
92}
93
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070094/*
95 * Convert a memory mapped flash address into a flash offset
96 */
97static inline u32 elog_flash_address_to_offset(u8 *address)
98{
David Hendricks259e49a2014-03-20 20:31:23 -070099#if CONFIG_ARCH_X86
100 /* For x86, assume address is memory-mapped near 4GB */
Aaron Durbin10a070b2013-06-28 12:30:53 -0700101 u32 rom_size;
102
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700103 if (!elog_spi)
104 return 0;
Aaron Durbin10a070b2013-06-28 12:30:53 -0700105
106 rom_size = get_rom_size();
107
108 return (u32)address - ((u32)~0UL - rom_size + 1);
David Hendricks259e49a2014-03-20 20:31:23 -0700109#else
110 return (u32)address;
111#endif
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700112}
113
114/*
115 * Convert a flash offset into a memory mapped flash address
116 */
117static inline u8* elog_flash_offset_to_address(u32 offset)
118{
Aaron Durbin10a070b2013-06-28 12:30:53 -0700119 u32 rom_size;
120
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700121 if (!elog_spi)
122 return NULL;
Aaron Durbin10a070b2013-06-28 12:30:53 -0700123
124 rom_size = get_rom_size();
125
126 return (u8*)((u32)~0UL - rom_size + 1 + offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700127}
128
129/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700130 * Pointer to an event log header in the event data area
131 */
132static inline struct event_header*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700133elog_get_event_base(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700134{
Gabe Black0bf1feb2013-04-26 03:34:00 -0700135 return (struct event_header *)&elog_area->data[offset];
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700136}
137
138/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700139 * Update the checksum at the last byte
140 */
141static void elog_update_checksum(struct event_header *event, u8 checksum)
142{
143 u8 *event_data = (u8*)event;
144 event_data[event->length - 1] = checksum;
145}
146
147/*
148 * Simple byte checksum for events
149 */
150static u8 elog_checksum_event(struct event_header *event)
151{
152 u8 index, checksum = 0;
153 u8 *data = (u8*)event;
154
155 for (index = 0; index < event->length; index++)
156 checksum += data[index];
157 return checksum;
158}
159
160/*
161 * Check if a raw buffer is filled with ELOG_TYPE_EOL byte
162 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700163static int elog_is_buffer_clear(void *base, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700164{
165 u8 *current = base;
166 u8 *end = current + size;
167
168 elog_debug("elog_is_buffer_clear(base=0x%p size=%u)\n", base, size);
169
170 for (; current != end; current++) {
171 if (*current != ELOG_TYPE_EOL)
172 return 0;
173 }
174 return 1;
175}
176
177/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700178 * Check that the ELOG area has been initialized and is valid.
179 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700180static int elog_is_area_valid(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700181{
182 elog_debug("elog_is_area_valid()\n");
183
Gabe Black0bf1feb2013-04-26 03:34:00 -0700184 if (area_state != ELOG_AREA_HAS_CONTENT)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700185 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700186 if (header_state != ELOG_HEADER_VALID)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700187 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700188 if (event_buffer_state != ELOG_EVENT_BUFFER_OK)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700189 return 0;
190 return 1;
191}
192
193/*
194 * Verify the contents of an ELOG Header structure
195 * Returns 1 if the header is valid, 0 otherwise
196 */
197static int elog_is_header_valid(struct elog_header *header)
198{
199 elog_debug("elog_is_header_valid()\n");
200
201 if (header->magic != ELOG_SIGNATURE) {
202 printk(BIOS_ERR, "ELOG: header magic 0x%X != 0x%X\n",
203 header->magic, ELOG_SIGNATURE);
204 return 0;
205 }
206 if (header->version != ELOG_VERSION) {
207 printk(BIOS_ERR, "ELOG: header version %u != %u\n",
208 header->version, ELOG_VERSION);
209 return 0;
210 }
211 if (header->header_size != sizeof(*header)) {
Denis 'GNUtoo' Cariklibc2c9ef2013-06-26 20:04:49 +0200212 printk(BIOS_ERR, "ELOG: header size mismatch %u != %zu\n",
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700213 header->header_size, sizeof(*header));
214 return 0;
215 }
216 return 1;
217}
218
219/*
220 * Validate the event header and data.
221 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700222static int elog_is_event_valid(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700223{
224 struct event_header *event;
225
Gabe Black0bf1feb2013-04-26 03:34:00 -0700226 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700227 if (!event)
228 return 0;
229
230 /* Validate event length */
231 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700232 sizeof(event->type) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700233 return 0;
234
235 /* End of event marker has been found */
236 if (event->type == ELOG_TYPE_EOL)
237 return 0;
238
239 /* Check if event fits in area */
240 if ((offsetof(struct event_header, length) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700241 sizeof(event->length) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700242 return 0;
243
244 /*
245 * If the current event length + the current offset exceeds
246 * the area size then the event area is corrupt.
247 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700248 if ((event->length + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700249 return 0;
250
251 /* Event length must be at least header size + checksum */
252 if (event->length < (sizeof(*event) + 1))
253 return 0;
254
255 /* If event checksum is invalid the area is corrupt */
256 if (elog_checksum_event(event) != 0)
257 return 0;
258
259 /* Event is valid */
260 return 1;
261}
262
263/*
Gabe Black331eb082013-04-24 04:11:40 -0700264 * Write 'size' bytes of data pointed to by 'address' in the flash backing
265 * store into flash. This will not erase the flash and it assumes the flash
266 * area has been erased appropriately.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700267 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700268static void elog_flash_write(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700269{
270 u32 offset;
271
Gabe Black331eb082013-04-24 04:11:40 -0700272 if (!address || !size || !elog_spi)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700273 return;
274
Gabe Black0bf1feb2013-04-26 03:34:00 -0700275 offset = flash_base;
276 offset += (u8 *)address - (u8 *)elog_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700277
Gabe Black331eb082013-04-24 04:11:40 -0700278 elog_debug("elog_flash_write(address=0x%p offset=0x%08x size=%u)\n",
279 address, offset, size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700280
281 /* Write the data to flash */
Gabe Black331eb082013-04-24 04:11:40 -0700282 elog_spi->write(elog_spi, offset, size, address);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700283}
284
285/*
286 * Erase the first block specified in the address.
287 * Only handles flash area within a single flash block.
288 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700289static void elog_flash_erase(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700290{
291 u32 offset;
292
293 if (!address || !size || !elog_spi)
294 return;
295
Gabe Black0bf1feb2013-04-26 03:34:00 -0700296 offset = flash_base;
297 offset += (u8 *)address - (u8*)elog_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700298
299 elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
300 address, offset, size);
301
302 /* Erase the sectors in this region */
303 elog_spi->erase(elog_spi, offset, size);
304}
305
306/*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700307 * Scan the event area and validate each entry and update the ELOG state.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700308 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700309static void elog_update_event_buffer_state(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700310{
311 u32 count = 0;
312 u32 offset = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700313 struct event_header *event;
314
315 elog_debug("elog_update_event_buffer_state()\n");
316
317 /* Go through each event and validate it */
318 while (1) {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700319 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700320
321 /* Do not de-reference anything past the area length */
322 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700323 sizeof(event->type) - 1 + offset) >= log_size) {
324 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700325 break;
326 }
327
328 /* The end of the event marker has been found */
329 if (event->type == ELOG_TYPE_EOL)
330 break;
331
332 /* Validate the event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700333 if (!elog_is_event_valid(offset)) {
334 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700335 break;
336 }
337
338 /* Move to the next event */
339 count++;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700340 offset += event->length;
341 }
342
343 /* Ensure the remaining buffer is empty */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700344 if (!elog_is_buffer_clear(&elog_area->data[offset], log_size - offset))
345 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700346
Gabe Black0bf1feb2013-04-26 03:34:00 -0700347 /* Update ELOG state */
348 event_count = count;
349 next_event_offset = offset;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700350}
351
Gabe Black0bf1feb2013-04-26 03:34:00 -0700352static void elog_scan_flash(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700353{
Gabe Black84a93d12013-04-24 23:31:41 -0700354 elog_debug("elog_scan_flash()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700355
Gabe Black0bf1feb2013-04-26 03:34:00 -0700356 area_state = ELOG_AREA_UNDEFINED;
357 header_state = ELOG_HEADER_INVALID;
358 event_buffer_state = ELOG_EVENT_BUFFER_OK;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700359
Duncan Laurie215f27852012-10-10 14:34:49 -0700360 /* Fill memory buffer by reading from SPI */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700361 elog_spi->read(elog_spi, flash_base, total_size, elog_area);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700362
Gabe Black0bf1feb2013-04-26 03:34:00 -0700363 next_event_offset = 0;
364 event_count = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700365
Gabe Black455c68e2013-04-24 17:54:37 -0700366 /* Check if the area is empty or not */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700367 if (elog_is_buffer_clear(elog_area, total_size)) {
368 area_state = ELOG_AREA_EMPTY;
Gabe Black455c68e2013-04-24 17:54:37 -0700369 return;
370 }
371
Gabe Black0bf1feb2013-04-26 03:34:00 -0700372 area_state = ELOG_AREA_HAS_CONTENT;
Gabe Black455c68e2013-04-24 17:54:37 -0700373
374 /* Validate the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700375 if (!elog_is_header_valid(&elog_area->header)) {
376 header_state = ELOG_HEADER_INVALID;
Gabe Black455c68e2013-04-24 17:54:37 -0700377 return;
378 }
379
Gabe Black0bf1feb2013-04-26 03:34:00 -0700380 header_state = ELOG_HEADER_VALID;
381 elog_update_event_buffer_state();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700382}
383
Gabe Black0bf1feb2013-04-26 03:34:00 -0700384static void elog_prepare_empty(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700385{
386 struct elog_header *header;
387
Gabe Black0bf1feb2013-04-26 03:34:00 -0700388 elog_debug("elog_prepare_empty()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700389
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700390 /* Write out the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700391 header = &elog_area->header;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700392 header->magic = ELOG_SIGNATURE;
393 header->version = ELOG_VERSION;
394 header->header_size = sizeof(struct elog_header);
395 header->reserved[0] = ELOG_TYPE_EOL;
396 header->reserved[1] = ELOG_TYPE_EOL;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700397 elog_flash_write(elog_area, header->header_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700398
Gabe Black0bf1feb2013-04-26 03:34:00 -0700399 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700400}
401
402/*
403 * Shrink the log, deleting old entries and moving the
Martin Roth56889792013-07-09 21:39:46 -0600404 * remaining ones to the front of the log.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700405 */
406static int elog_shrink(void)
407{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700408 struct event_header *event;
409 u16 discard_count = 0;
410 u16 offset = 0;
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700411 u16 new_size = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700412
413 elog_debug("elog_shrink()\n");
414
Gabe Black0bf1feb2013-04-26 03:34:00 -0700415 if (next_event_offset < CONFIG_ELOG_SHRINK_SIZE)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700416 return 0;
417
418 while (1) {
419 /* Next event has exceeded constraints */
420 if (offset > CONFIG_ELOG_SHRINK_SIZE)
421 break;
422
Gabe Black0bf1feb2013-04-26 03:34:00 -0700423 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700424
425 /* Reached the end of the area */
426 if (!event || event->type == ELOG_TYPE_EOL)
427 break;
428
429 offset += event->length;
430 discard_count++;
431 }
432
Gabe Black0bf1feb2013-04-26 03:34:00 -0700433 new_size = next_event_offset - offset;
434 memmove(&elog_area->data[0], &elog_area->data[offset], new_size);
435 memset(&elog_area->data[new_size], ELOG_TYPE_EOL, log_size - new_size);
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700436
Gabe Black0bf1feb2013-04-26 03:34:00 -0700437 elog_flash_erase(elog_area, total_size);
438 elog_flash_write(elog_area, total_size);
439 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700440
Duncan Laurie032be822013-05-23 07:23:09 -0700441 /* Ensure the area was successfully erased */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700442 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD) {
Duncan Laurie032be822013-05-23 07:23:09 -0700443 printk(BIOS_ERR, "ELOG: Flash area was not erased!\n");
444 return -1;
445 }
446
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700447 /* Add clear event */
448 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, offset);
449
450 return 0;
451}
452
Duncan Laurie215f27852012-10-10 14:34:49 -0700453#ifndef __SMM__
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700454/*
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700455 * Fill out SMBIOS Type 15 table entry so the
456 * event log can be discovered at runtime.
457 */
458int elog_smbios_write_type15(unsigned long *current, int handle)
459{
460 struct smbios_type15 *t = (struct smbios_type15 *)*current;
461 int len = sizeof(struct smbios_type15);
462
Duncan Laurie215f27852012-10-10 14:34:49 -0700463#if CONFIG_ELOG_CBMEM
464 /* Save event log buffer into CBMEM for the OS to read */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700465 void *cbmem = cbmem_add(CBMEM_ID_ELOG, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700466 if (!cbmem)
467 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700468 memcpy(cbmem, elog_area, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700469#endif
470
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700471 memset(t, 0, len);
472 t->type = SMBIOS_EVENT_LOG;
473 t->length = len - 2;
474 t->handle = handle;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700475 t->area_length = total_size - 1;
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700476 t->header_offset = 0;
477 t->data_offset = sizeof(struct elog_header);
478 t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
479 t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
480 t->change_token = 0;
Duncan Laurie215f27852012-10-10 14:34:49 -0700481#if CONFIG_ELOG_CBMEM
482 t->address = (u32)cbmem;
483#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700484 t->address = (u32)elog_flash_offset_to_address(flash_base);
Duncan Laurie215f27852012-10-10 14:34:49 -0700485#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700486 t->header_format = ELOG_HEADER_TYPE_OEM;
487 t->log_type_descriptors = 0;
488 t->log_type_descriptor_length = 2;
489
490 *current += len;
491 return len;
492}
Duncan Laurie215f27852012-10-10 14:34:49 -0700493#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700494
495/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700496 * Clear the entire event log
497 */
498int elog_clear(void)
499{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700500 elog_debug("elog_clear()\n");
501
Gabe Black8f4baec2013-04-25 17:21:58 -0700502 /* Make sure ELOG structures are initialized */
503 if (elog_init() < 0)
504 return -1;
505
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700506 /* Erase flash area */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700507 elog_flash_erase(elog_area, total_size);
508 elog_prepare_empty();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700509
Gabe Black0bf1feb2013-04-26 03:34:00 -0700510 if (!elog_is_area_valid())
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700511 return -1;
512
513 /* Log the clear event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700514 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700515
516 return 0;
517}
518
Gabe Black0bf1feb2013-04-26 03:34:00 -0700519static void elog_find_flash(void)
Gabe Black84a93d12013-04-24 23:31:41 -0700520{
521#if CONFIG_CHROMEOS
522 u8 *flash_base_ptr;
523#endif
524
Gabe Black0bf1feb2013-04-26 03:34:00 -0700525 elog_debug("elog_find_flash()\n");
Gabe Black84a93d12013-04-24 23:31:41 -0700526
527#if CONFIG_CHROMEOS
528 /* Find the ELOG base and size in FMAP */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700529 total_size = find_fmap_entry("RW_ELOG", (void **)&flash_base_ptr);
530 if (total_size < 0) {
Gabe Black84a93d12013-04-24 23:31:41 -0700531 printk(BIOS_WARNING, "ELOG: Unable to find RW_ELOG in FMAP, "
532 "using CONFIG_ELOG_FLASH_BASE instead\n");
Gabe Black0bf1feb2013-04-26 03:34:00 -0700533 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700534 } else {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700535 flash_base = elog_flash_address_to_offset(flash_base_ptr);
Gabe Black84a93d12013-04-24 23:31:41 -0700536
537 /* Use configured size if smaller than FMAP size */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700538 if (total_size > CONFIG_ELOG_AREA_SIZE)
539 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700540 }
541#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700542 flash_base = CONFIG_ELOG_FLASH_BASE;
543 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700544#endif
Gabe Black0bf1feb2013-04-26 03:34:00 -0700545 log_size = total_size - sizeof(struct elog_header);
Gabe Black84a93d12013-04-24 23:31:41 -0700546}
547
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700548/*
549 * Event log main entry point
550 */
551int elog_init(void)
552{
553 if (elog_initialized)
554 return 0;
555
556 elog_debug("elog_init()\n");
557
David Hendricks9acbd6f2014-04-13 16:45:31 -0700558 /* Probe SPI chip. SPI controller must already be initialized. */
David Hendricksc9470242014-04-14 14:57:36 -0700559 elog_spi = spi_flash_probe(CONFIG_BOOT_MEDIA_SPI_BUS, 0);
Gabe Black84a93d12013-04-24 23:31:41 -0700560 if (!elog_spi) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700561 printk(BIOS_ERR, "ELOG: Unable to find SPI flash\n");
562 return -1;
563 }
564
Gabe Black84a93d12013-04-24 23:31:41 -0700565 /* Set up the backing store */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700566 elog_find_flash();
Gabe Black84a93d12013-04-24 23:31:41 -0700567 if (flash_base == 0) {
568 printk(BIOS_ERR, "ELOG: Invalid flash base\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700569 return -1;
570 }
571
Gabe Black0bf1feb2013-04-26 03:34:00 -0700572 elog_area = malloc(total_size);
573 if (!elog_area) {
Gabe Black84a93d12013-04-24 23:31:41 -0700574 printk(BIOS_ERR, "ELOG: Unable to allocate backing store\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700575 return -1;
576 }
Gabe Black84a93d12013-04-24 23:31:41 -0700577
578 /* Load the log from flash */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700579 elog_scan_flash();
Gabe Black84a93d12013-04-24 23:31:41 -0700580
581 /* Prepare the flash if necessary */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700582 if (header_state == ELOG_HEADER_INVALID ||
583 event_buffer_state == ELOG_EVENT_BUFFER_CORRUPTED) {
Gabe Black84a93d12013-04-24 23:31:41 -0700584 /* If the header is invalid or the events are corrupted,
585 * no events can be salvaged so erase the entire area. */
586 printk(BIOS_ERR, "ELOG: flash area invalid\n");
Gabe Black0bf1feb2013-04-26 03:34:00 -0700587 elog_flash_erase(elog_area, total_size);
588 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700589 }
590
Gabe Black0bf1feb2013-04-26 03:34:00 -0700591 if (area_state == ELOG_AREA_EMPTY)
592 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700593
Gabe Black0bf1feb2013-04-26 03:34:00 -0700594 if (!elog_is_area_valid()) {
Gabe Black84a93d12013-04-24 23:31:41 -0700595 printk(BIOS_ERR, "ELOG: Unable to prepare flash\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700596 return -1;
597 }
598
599 elog_initialized = 1;
600
Gabe Black331eb082013-04-24 04:11:40 -0700601 printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08x]\n",
Gabe Black0bf1feb2013-04-26 03:34:00 -0700602 elog_area, flash_base);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700603
Gabe Black84a93d12013-04-24 23:31:41 -0700604 printk(BIOS_INFO, "ELOG: area is %d bytes, full threshold %d,"
Gabe Black0bf1feb2013-04-26 03:34:00 -0700605 " shrink size %d\n", total_size,
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700606 CONFIG_ELOG_FULL_THRESHOLD, CONFIG_ELOG_SHRINK_SIZE);
607
608 /* Log a clear event if necessary */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700609 if (event_count == 0)
610 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700611
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700612 /* Shrink the log if we are getting too full */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700613 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie032be822013-05-23 07:23:09 -0700614 if (elog_shrink() < 0)
615 return -1;
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700616
Gabe Black84a93d12013-04-24 23:31:41 -0700617#if !defined(__SMM__)
Duncan Laurief4d36232012-06-23 16:37:45 -0700618 /* Log boot count event except in S3 resume */
David Hendricks259e49a2014-03-20 20:31:23 -0700619#if CONFIG_ELOG_BOOT_COUNT == 1
620#if CONFIG_HAVE_ACPI_RESUME == 1
621 if (!acpi_is_wakeup_s3())
622#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700623 elog_add_event_dword(ELOG_TYPE_BOOT, boot_count_read());
David Hendricks259e49a2014-03-20 20:31:23 -0700624#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700625
David Hendricks259e49a2014-03-20 20:31:23 -0700626#if CONFIG_ARCH_X86
Duncan Laurie1fc34612012-09-09 19:14:45 -0700627 /* Check and log POST codes from previous boot */
Gabe Black84a93d12013-04-24 23:31:41 -0700628 if (CONFIG_CMOS_POST)
629 cmos_post_log();
Duncan Laurie1fc34612012-09-09 19:14:45 -0700630#endif
David Hendricks259e49a2014-03-20 20:31:23 -0700631#endif
Duncan Laurie1fc34612012-09-09 19:14:45 -0700632
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700633 return 0;
634}
635
636/*
637 * Populate timestamp in event header with current time
638 */
639static void elog_fill_timestamp(struct event_header *event)
640{
David Hendricks259e49a2014-03-20 20:31:23 -0700641#if CONFIG_ARCH_X86
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700642 event->second = cmos_read(RTC_CLK_SECOND);
643 event->minute = cmos_read(RTC_CLK_MINUTE);
644 event->hour = cmos_read(RTC_CLK_HOUR);
645 event->day = cmos_read(RTC_CLK_DAYOFMONTH);
646 event->month = cmos_read(RTC_CLK_MONTH);
647 event->year = cmos_read(RTC_CLK_YEAR);
David Hendricks259e49a2014-03-20 20:31:23 -0700648#else
649 /*
650 * FIXME: We need to abstract the CMOS stuff on non-x86 platforms.
651 * Until then, use bogus data here to force the values to 0.
652 */
653 event->month = 0xff;
654#endif
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700655
656 /* Basic sanity check of expected ranges */
657 if (event->month > 0x12 || event->day > 0x31 || event->hour > 0x23 ||
658 event->minute > 0x59 || event->second > 0x59) {
659 event->year = 0;
660 event->month = 0;
661 event->day = 0;
662 event->hour = 0;
663 event->minute = 0;
664 event->second = 0;
665 }
666}
667
668/*
Gabe Black331eb082013-04-24 04:11:40 -0700669 * Add an event to the log
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700670 */
Gabe Black331eb082013-04-24 04:11:40 -0700671void elog_add_event_raw(u8 event_type, void *data, u8 data_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700672{
673 struct event_header *event;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700674 u8 event_size;
675
Gabe Black331eb082013-04-24 04:11:40 -0700676 elog_debug("elog_add_event_raw(type=%X)\n", event_type);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700677
678 /* Make sure ELOG structures are initialized */
679 if (elog_init() < 0)
Gabe Black331eb082013-04-24 04:11:40 -0700680 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700681
682 /* Header + Data + Checksum */
683 event_size = sizeof(*event) + data_size + 1;
684 if (event_size > MAX_EVENT_SIZE) {
685 printk(BIOS_ERR, "ELOG: Event(%X) data size too "
686 "big (%d)\n", event_type, event_size);
Gabe Black331eb082013-04-24 04:11:40 -0700687 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700688 }
689
690 /* Make sure event data can fit */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700691 if ((next_event_offset + event_size) >= log_size) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700692 printk(BIOS_ERR, "ELOG: Event(%X) does not fit\n",
693 event_type);
Gabe Black331eb082013-04-24 04:11:40 -0700694 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700695 }
696
697 /* Fill out event data */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700698 event = elog_get_event_base(next_event_offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700699 event->type = event_type;
700 event->length = event_size;
701 elog_fill_timestamp(event);
702
703 if (data_size)
704 memcpy(&event[1], data, data_size);
705
706 /* Zero the checksum byte and then compute checksum */
707 elog_update_checksum(event, 0);
708 elog_update_checksum(event, -(elog_checksum_event(event)));
709
Gabe Black0bf1feb2013-04-26 03:34:00 -0700710 /* Update the ELOG state */
711 event_count++;
Gabe Black331eb082013-04-24 04:11:40 -0700712
713 elog_flash_write((void *)event, event_size);
714
Gabe Black0bf1feb2013-04-26 03:34:00 -0700715 next_event_offset += event_size;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700716
717 printk(BIOS_INFO, "ELOG: Event(%X) added with size %d\n",
718 event_type, event_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700719
720 /* Shrink the log if we are getting too full */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700721 if (next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700722 elog_shrink();
723}
724
725void elog_add_event(u8 event_type)
726{
727 elog_add_event_raw(event_type, NULL, 0);
728}
729
730void elog_add_event_byte(u8 event_type, u8 data)
731{
732 elog_add_event_raw(event_type, &data, sizeof(data));
733}
734
735void elog_add_event_word(u8 event_type, u16 data)
736{
737 elog_add_event_raw(event_type, &data, sizeof(data));
738}
739
740void elog_add_event_dword(u8 event_type, u32 data)
741{
742 elog_add_event_raw(event_type, &data, sizeof(data));
743}
744
745void elog_add_event_wake(u8 source, u32 instance)
746{
747 struct elog_event_data_wake wake = {
748 .source = source,
749 .instance = instance
750 };
751 elog_add_event_raw(ELOG_TYPE_WAKE_SOURCE, &wake, sizeof(wake));
752}