blob: 439ccc363c0ef790ac6d06b40d4b148405049ec9 [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
20#include <arch/acpi.h>
Duncan Laurie215f27852012-10-10 14:34:49 -070021#include <cbmem.h>
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070022#include <console/console.h>
23#include <pc80/mc146818rtc.h>
Duncan Laurie472ec9c2012-06-23 16:13:42 -070024#include <smbios.h>
Zheng Bao600784e2013-02-07 17:30:23 +080025#include <spi-generic.h>
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070026#include <spi_flash.h>
27#include <stdint.h>
28#include <string.h>
29#include <elog.h>
30#include "elog_internal.h"
31
Duncan Laurie86bf3f52012-08-15 13:14:58 -070032#if CONFIG_CHROMEOS
33#include <vendorcode/google/chromeos/fmap.h>
34#elif CONFIG_ELOG_FLASH_BASE == 0
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070035#error "CONFIG_ELOG_FLASH_BASE is invalid"
36#endif
37#if CONFIG_ELOG_FULL_THRESHOLD >= CONFIG_ELOG_AREA_SIZE
38#error "CONFIG_ELOG_FULL_THRESHOLD is larger than CONFIG_ELOG_AREA_SIZE"
39#endif
40#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_FULL_THRESHOLD) < (MAX_EVENT_SIZE + 1)
41#error "CONFIG_ELOG_FULL_THRESHOLD is too small"
42#endif
43#if CONFIG_ELOG_SHRINK_SIZE >= CONFIG_ELOG_AREA_SIZE
44#error "CONFIG_ELOG_SHRINK_SIZE is larger than CONFIG_ELOG_AREA_SIZE"
45#endif
46#if (CONFIG_ELOG_AREA_SIZE - CONFIG_ELOG_SHRINK_SIZE) > \
47 CONFIG_ELOG_FULL_THRESHOLD
48#error "CONFIG_ELOG_SHRINK_SIZE is too large"
49#endif
50
51#if CONFIG_ELOG_DEBUG
52#define elog_debug(STR...) printk(BIOS_DEBUG, STR)
53#else
54#define elog_debug(STR...)
55#endif
56
57/*
58 * Static variables for ELOG state
59 */
60static int elog_initialized;
61static struct spi_flash *elog_spi;
62static struct elog_descriptor elog_flash_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070063
64static inline struct elog_descriptor* elog_get_flash(void)
65{
66 return &elog_flash_area;
67}
68
69/*
70 * Convert a memory mapped flash address into a flash offset
71 */
72static inline u32 elog_flash_address_to_offset(u8 *address)
73{
74 if (!elog_spi)
75 return 0;
76 return (u32)address - ((u32)~0UL - elog_spi->size + 1);
77}
78
79/*
80 * Convert a flash offset into a memory mapped flash address
81 */
82static inline u8* elog_flash_offset_to_address(u32 offset)
83{
84 if (!elog_spi)
85 return NULL;
86 return (u8*)((u32)~0UL - elog_spi->size + 1 + offset);
87}
88
89/*
90 * The ELOG header is at the very beginning of the area
91 */
92static inline struct elog_header*
93elog_get_header(struct elog_descriptor *elog)
94{
95 return elog->backing_store;
96}
97
98/*
99 * Pointer to an event log header in the event data area
100 */
101static inline struct event_header*
102elog_get_event_base(struct elog_descriptor *elog, u32 offset)
103{
104 return (struct event_header *)&elog->data[offset];
105}
106
107/*
108 * Pointer to where the next event should be stored
109 */
110static inline struct event_header*
111elog_get_next_event_base(struct elog_descriptor *elog)
112{
113 return elog_get_event_base(elog, elog->next_event_offset);
114}
115
116/*
117 * Pointer to the last logged event
118 */
119static inline struct event_header*
120elog_get_last_event_base(struct elog_descriptor *elog)
121{
122 return elog_get_event_base(elog, elog->last_event_offset);
123}
124
125/*
126 * Update the checksum at the last byte
127 */
128static void elog_update_checksum(struct event_header *event, u8 checksum)
129{
130 u8 *event_data = (u8*)event;
131 event_data[event->length - 1] = checksum;
132}
133
134/*
135 * Simple byte checksum for events
136 */
137static u8 elog_checksum_event(struct event_header *event)
138{
139 u8 index, checksum = 0;
140 u8 *data = (u8*)event;
141
142 for (index = 0; index < event->length; index++)
143 checksum += data[index];
144 return checksum;
145}
146
147/*
148 * Check if a raw buffer is filled with ELOG_TYPE_EOL byte
149 */
150static int elog_is_buffer_clear(u8 *base, u32 size)
151{
152 u8 *current = base;
153 u8 *end = current + size;
154
155 elog_debug("elog_is_buffer_clear(base=0x%p size=%u)\n", base, size);
156
157 for (; current != end; current++) {
158 if (*current != ELOG_TYPE_EOL)
159 return 0;
160 }
161 return 1;
162}
163
164/*
165 * Verify whether ELOG area is filled with ELOG_TYPE_EOL byte
166 */
167static int elog_is_area_clear(struct elog_descriptor *elog)
168{
169 return elog_is_buffer_clear(elog->backing_store, elog->total_size);
170}
171
172/*
173 * Check that the ELOG area has been initialized and is valid.
174 */
175static int elog_is_area_valid(struct elog_descriptor *elog)
176{
177 elog_debug("elog_is_area_valid()\n");
178
179 if (elog->area_state != ELOG_AREA_HAS_CONTENT)
180 return 0;
181 if (elog->header_state != ELOG_HEADER_VALID)
182 return 0;
183 if (elog->event_buffer_state != ELOG_EVENT_BUFFER_OK)
184 return 0;
185 return 1;
186}
187
188/*
189 * Verify the contents of an ELOG Header structure
190 * Returns 1 if the header is valid, 0 otherwise
191 */
192static int elog_is_header_valid(struct elog_header *header)
193{
194 elog_debug("elog_is_header_valid()\n");
195
196 if (header->magic != ELOG_SIGNATURE) {
197 printk(BIOS_ERR, "ELOG: header magic 0x%X != 0x%X\n",
198 header->magic, ELOG_SIGNATURE);
199 return 0;
200 }
201 if (header->version != ELOG_VERSION) {
202 printk(BIOS_ERR, "ELOG: header version %u != %u\n",
203 header->version, ELOG_VERSION);
204 return 0;
205 }
206 if (header->header_size != sizeof(*header)) {
Denis 'GNUtoo' Cariklibc2c9ef2013-06-26 20:04:49 +0200207 printk(BIOS_ERR, "ELOG: header size mismatch %u != %zu\n",
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700208 header->header_size, sizeof(*header));
209 return 0;
210 }
211 return 1;
212}
213
214/*
215 * Validate the event header and data.
216 */
217static int elog_is_event_valid(struct elog_descriptor *elog, u32 offset)
218{
219 struct event_header *event;
220
221 event = elog_get_event_base(elog, offset);
222 if (!event)
223 return 0;
224
225 /* Validate event length */
226 if ((offsetof(struct event_header, type) +
227 sizeof(event->type) - 1 + offset) >= elog->data_size)
228 return 0;
229
230 /* End of event marker has been found */
231 if (event->type == ELOG_TYPE_EOL)
232 return 0;
233
234 /* Check if event fits in area */
235 if ((offsetof(struct event_header, length) +
236 sizeof(event->length) - 1 + offset) >= elog->data_size)
237 return 0;
238
239 /*
240 * If the current event length + the current offset exceeds
241 * the area size then the event area is corrupt.
242 */
243 if ((event->length + offset) >= elog->data_size)
244 return 0;
245
246 /* Event length must be at least header size + checksum */
247 if (event->length < (sizeof(*event) + 1))
248 return 0;
249
250 /* If event checksum is invalid the area is corrupt */
251 if (elog_checksum_event(event) != 0)
252 return 0;
253
254 /* Event is valid */
255 return 1;
256}
257
258/*
Gabe Black331eb082013-04-24 04:11:40 -0700259 * Write 'size' bytes of data pointed to by 'address' in the flash backing
260 * store into flash. This will not erase the flash and it assumes the flash
261 * area has been erased appropriately.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700262 */
Gabe Black331eb082013-04-24 04:11:40 -0700263static void elog_flash_write(u8 *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700264{
Duncan Laurie215f27852012-10-10 14:34:49 -0700265 struct elog_descriptor *flash = elog_get_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700266 u32 offset;
267
Gabe Black331eb082013-04-24 04:11:40 -0700268 if (!address || !size || !elog_spi)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700269 return;
270
Duncan Laurie215f27852012-10-10 14:34:49 -0700271 offset = flash->flash_base;
272 offset += address - (u8*)flash->backing_store;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700273
Gabe Black331eb082013-04-24 04:11:40 -0700274 elog_debug("elog_flash_write(address=0x%p offset=0x%08x size=%u)\n",
275 address, offset, size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700276
277 /* Write the data to flash */
Gabe Black331eb082013-04-24 04:11:40 -0700278 elog_spi->write(elog_spi, offset, size, address);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700279}
280
281/*
282 * Erase the first block specified in the address.
283 * Only handles flash area within a single flash block.
284 */
285static void elog_flash_erase(u8 *address, u32 size)
286{
Duncan Laurie215f27852012-10-10 14:34:49 -0700287 struct elog_descriptor *flash = elog_get_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700288 u32 offset;
289
290 if (!address || !size || !elog_spi)
291 return;
292
Duncan Laurie215f27852012-10-10 14:34:49 -0700293 offset = flash->flash_base;
294 offset += address - (u8*)flash->backing_store;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700295
296 elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
297 address, offset, size);
298
299 /* Erase the sectors in this region */
300 elog_spi->erase(elog_spi, offset, size);
301}
302
303/*
304 * Scan the event area and validate each entry and
305 * update the ELOG descriptor state.
306 */
307static void elog_update_event_buffer_state(struct elog_descriptor *elog)
308{
309 u32 count = 0;
310 u32 offset = 0;
311 u32 last_offset = 0;
312 u32 last_event_size = 0;
313 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) {
319 event = elog_get_event_base(elog, offset);
320
321 /* Do not de-reference anything past the area length */
322 if ((offsetof(struct event_header, type) +
323 sizeof(event->type) - 1 + offset) >= elog->data_size) {
324 elog->event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
325 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 */
333 if (!elog_is_event_valid(elog, offset)) {
334 elog->event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
335 break;
336 }
337
338 /* Move to the next event */
339 count++;
340 last_offset = offset;
341 last_event_size = event->length;
342 offset += event->length;
343 }
344
345 /* Ensure the remaining buffer is empty */
346 if (!elog_is_buffer_clear(&elog->data[offset],
347 elog->data_size - offset))
348 elog->event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
349
350 /* Update data into elog descriptor */
351 elog->event_count = count;
352 elog->next_event_offset = offset;
353 elog->last_event_offset = last_offset;
354 elog->last_event_size = last_event_size;
355}
356
357static void elog_validate_and_fill(struct elog_descriptor *elog)
358{
359 elog_debug("elog_validate_and_fill()\n");
360
361 /* Check if the area is empty or not */
362 if (elog_is_area_clear(elog)) {
363 elog->area_state = ELOG_AREA_EMPTY;
364 return;
365 }
366
367 elog->area_state = ELOG_AREA_HAS_CONTENT;
368
369 /* Validate the header */
Gabe Blacke62e0362013-04-23 19:36:01 -0700370 if (!elog_is_header_valid(elog_get_header(elog))) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700371 elog->header_state = ELOG_HEADER_INVALID;
372 return;
373 }
374
375 elog->header_state = ELOG_HEADER_VALID;
376 elog_update_event_buffer_state(elog);
377}
378
379/*
380 * Initialize a new ELOG descriptor
381 */
382static void elog_init_descriptor(struct elog_descriptor *elog,
Gabe Blacke62e0362013-04-23 19:36:01 -0700383 u8 *buffer, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700384{
Gabe Black331eb082013-04-24 04:11:40 -0700385 elog_debug("elog_init_descriptor(buffer=0x%p size=%u)\n", buffer, size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700386
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700387 elog->area_state = ELOG_AREA_UNDEFINED;
388 elog->header_state = ELOG_HEADER_INVALID;
389 elog->event_buffer_state = ELOG_EVENT_BUFFER_OK;
390 elog->backing_store = buffer;
391 elog->total_size = size;
392
Duncan Laurie215f27852012-10-10 14:34:49 -0700393 /* Fill memory buffer by reading from SPI */
Gabe Black331eb082013-04-24 04:11:40 -0700394 elog_spi->read(elog_spi, elog->flash_base, size, buffer);
Duncan Laurie215f27852012-10-10 14:34:49 -0700395
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700396 /* Data starts immediately after header */
397 elog->data = &buffer[sizeof(struct elog_header)];
398 elog->data_size = size - sizeof(struct elog_header);
399
400 elog->next_event_offset = 0;
401 elog->last_event_offset = 0;
402 elog->last_event_size = 0;
403 elog->event_count = 0;
404
405 elog_validate_and_fill(elog);
406}
407
408/*
409 * Re-initialize an existing ELOG descriptor
410 */
411static void elog_reinit_descriptor(struct elog_descriptor *elog)
412{
413 elog_debug("elog_reinit_descriptor()\n");
Gabe Black331eb082013-04-24 04:11:40 -0700414 elog_init_descriptor(elog, elog->backing_store, elog->total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700415}
416
417/*
418 * Create ELOG descriptor data structures for all ELOG areas.
419 */
420static int elog_setup_descriptors(u32 flash_base, u32 area_size)
421{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700422 u8 *area;
423
424 elog_debug("elog_setup_descriptors(base=0x%08x size=%u)\n",
425 flash_base, area_size);
426
427 /* Prepare flash descriptors */
428 if (flash_base == 0) {
429 printk(BIOS_ERR, "ELOG: Invalid flash base\n");
430 return -1;
431 }
432
Duncan Laurie215f27852012-10-10 14:34:49 -0700433 area = malloc(area_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700434 if (!area) {
Gabe Blacke62e0362013-04-23 19:36:01 -0700435 printk(BIOS_ERR, "ELOG: Unable to allocate backing store\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700436 return -1;
437 }
Duncan Laurie215f27852012-10-10 14:34:49 -0700438 elog_get_flash()->flash_base = flash_base;
Gabe Black331eb082013-04-24 04:11:40 -0700439 elog_init_descriptor(elog_get_flash(), area, area_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700440
441 return 0;
442}
443
444static void elog_flash_erase_area(void)
445{
446 struct elog_descriptor *elog = elog_get_flash();
447
448 elog_debug("elog_flash_erase_area()\n");
449
450 elog_flash_erase(elog->backing_store, elog->total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700451 memset(elog->backing_store, ELOG_TYPE_EOL, elog->total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700452 elog_reinit_descriptor(elog);
453}
454
Gabe Black331eb082013-04-24 04:11:40 -0700455static void elog_prepare_empty(struct elog_descriptor *elog)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700456{
457 struct elog_header *header;
458
459 elog_debug("elog_prepare_empty(%u bytes)\n", data_size);
460
461 if (!elog_is_area_clear(elog))
462 return;
463
464 /* Write out the header */
Gabe Blacke62e0362013-04-23 19:36:01 -0700465 header = elog_get_header(elog);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700466 header->magic = ELOG_SIGNATURE;
467 header->version = ELOG_VERSION;
468 header->header_size = sizeof(struct elog_header);
469 header->reserved[0] = ELOG_TYPE_EOL;
470 header->reserved[1] = ELOG_TYPE_EOL;
Gabe Black331eb082013-04-24 04:11:40 -0700471 elog_flash_write(elog->backing_store, header->header_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700472
473 elog_reinit_descriptor(elog);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700474}
475
476static int elog_sync_flash_to_mem(void)
477{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700478 struct elog_descriptor *flash = elog_get_flash();
479
480 elog_debug("elog_sync_flash_to_mem()\n");
481
482 /* Fill with empty pattern first */
Gabe Black331eb082013-04-24 04:11:40 -0700483 memset(flash->backing_store, ELOG_TYPE_EOL, flash->total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700484
Duncan Laurie215f27852012-10-10 14:34:49 -0700485 /* Read the header from SPI to memory */
486 elog_spi->read(elog_spi, flash->flash_base,
Gabe Black331eb082013-04-24 04:11:40 -0700487 sizeof(struct elog_header), flash->backing_store);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700488
Duncan Laurie215f27852012-10-10 14:34:49 -0700489 /* Read the valid flash contents from SPI to memory */
490 elog_spi->read(elog_spi, flash->flash_base + sizeof(struct elog_header),
Gabe Black331eb082013-04-24 04:11:40 -0700491 flash->next_event_offset, flash->data);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700492
Gabe Black331eb082013-04-24 04:11:40 -0700493 elog_reinit_descriptor(flash);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700494
Gabe Black331eb082013-04-24 04:11:40 -0700495 return elog_is_area_valid(flash) ? 0 : -1;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700496}
497
498/*
499 * Called during ELOG entry handler to prepare state for flash.
500 */
501static int elog_flash_area_bootstrap(void)
502{
503 struct elog_descriptor *elog = elog_get_flash();
504
505 elog_debug("elog_flash_area_bootstrap()\n");
506
507 switch (elog->area_state) {
508 case ELOG_AREA_UNDEFINED:
509 printk(BIOS_ERR, "ELOG: flash area undefined\n");
510 return -1;
511
512 case ELOG_AREA_EMPTY:
513 /* Write a new header with no data */
Gabe Black331eb082013-04-24 04:11:40 -0700514 elog_prepare_empty(elog);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700515 break;
516
517 case ELOG_AREA_HAS_CONTENT:
518 break;
519 }
520
Gabe Black331eb082013-04-24 04:11:40 -0700521 if (elog->header_state == ELOG_HEADER_INVALID ||
522 elog->event_buffer_state == ELOG_EVENT_BUFFER_CORRUPTED) {
523 /* If the header is invalid or the events are corrupted,
524 * no events can be salvaged so erase the entire area. */
525 printk(BIOS_ERR, "ELOG: flash area invalid\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700526 elog_flash_erase_area();
Gabe Black331eb082013-04-24 04:11:40 -0700527 elog_prepare_empty(elog);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700528 }
529
530 return 0;
531}
532
533/*
534 * Shrink the log, deleting old entries and moving the
Martin Roth56889792013-07-09 21:39:46 -0600535 * remaining ones to the front of the log.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700536 */
537static int elog_shrink(void)
538{
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700539 struct elog_descriptor *flash = elog_get_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700540 struct event_header *event;
541 u16 discard_count = 0;
542 u16 offset = 0;
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700543 u16 new_size = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700544
545 elog_debug("elog_shrink()\n");
546
Gabe Black331eb082013-04-24 04:11:40 -0700547 if (flash->next_event_offset < CONFIG_ELOG_SHRINK_SIZE)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700548 return 0;
549
550 while (1) {
551 /* Next event has exceeded constraints */
552 if (offset > CONFIG_ELOG_SHRINK_SIZE)
553 break;
554
Gabe Black331eb082013-04-24 04:11:40 -0700555 event = elog_get_event_base(flash, offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700556
557 /* Reached the end of the area */
558 if (!event || event->type == ELOG_TYPE_EOL)
559 break;
560
561 offset += event->length;
562 discard_count++;
563 }
564
Gabe Black331eb082013-04-24 04:11:40 -0700565 new_size = flash->next_event_offset - offset;
566 memmove(&flash->data[0], &flash->data[offset], new_size);
567 memset(&flash->data[new_size], ELOG_TYPE_EOL,
568 flash->data_size - new_size);
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700569
570 elog_flash_erase(flash->backing_store, flash->total_size);
Gabe Black331eb082013-04-24 04:11:40 -0700571 elog_flash_write(flash->backing_store, flash->total_size);
572 elog_reinit_descriptor(flash);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700573
Duncan Laurie032be822013-05-23 07:23:09 -0700574 /* Ensure the area was successfully erased */
Gabe Black331eb082013-04-24 04:11:40 -0700575 if (flash->next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD) {
Duncan Laurie032be822013-05-23 07:23:09 -0700576 printk(BIOS_ERR, "ELOG: Flash area was not erased!\n");
577 return -1;
578 }
579
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700580 /* Add clear event */
581 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, offset);
582
583 return 0;
584}
585
586/*
587 * Initialize the SPI bus and probe for a flash chip
588 */
589static int elog_spi_init(void)
590{
591 elog_debug("elog_spi_init()\n");
592
593 /* Prepare SPI subsystem */
594 spi_init();
595
596 /* Look for flash chip */
597 elog_spi = spi_flash_probe(0, 0, 0, 0);
598
599 return elog_spi ? 0 : -1;
600}
601
Duncan Laurie215f27852012-10-10 14:34:49 -0700602#ifndef __SMM__
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700603/*
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700604 * Fill out SMBIOS Type 15 table entry so the
605 * event log can be discovered at runtime.
606 */
607int elog_smbios_write_type15(unsigned long *current, int handle)
608{
Duncan Laurie215f27852012-10-10 14:34:49 -0700609 struct elog_descriptor *flash = elog_get_flash();
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700610 struct smbios_type15 *t = (struct smbios_type15 *)*current;
611 int len = sizeof(struct smbios_type15);
612
Duncan Laurie215f27852012-10-10 14:34:49 -0700613#if CONFIG_ELOG_CBMEM
614 /* Save event log buffer into CBMEM for the OS to read */
615 void *cbmem = cbmem_add(CBMEM_ID_ELOG, flash->total_size);
616 if (!cbmem)
617 return 0;
618 memcpy(cbmem, flash->backing_store, flash->total_size);
619#endif
620
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700621 memset(t, 0, len);
622 t->type = SMBIOS_EVENT_LOG;
623 t->length = len - 2;
624 t->handle = handle;
Duncan Laurie215f27852012-10-10 14:34:49 -0700625 t->area_length = flash->total_size - 1;
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700626 t->header_offset = 0;
627 t->data_offset = sizeof(struct elog_header);
628 t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
629 t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
630 t->change_token = 0;
Duncan Laurie215f27852012-10-10 14:34:49 -0700631#if CONFIG_ELOG_CBMEM
632 t->address = (u32)cbmem;
633#else
634 t->address = (u32)elog_flash_offset_to_address(flash->flash_base);
635#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700636 t->header_format = ELOG_HEADER_TYPE_OEM;
637 t->log_type_descriptors = 0;
638 t->log_type_descriptor_length = 2;
639
640 *current += len;
641 return len;
642}
Duncan Laurie215f27852012-10-10 14:34:49 -0700643#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700644
645/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700646 * Clear the entire event log
647 */
648int elog_clear(void)
649{
650 struct elog_descriptor *flash = elog_get_flash();
651
652 elog_debug("elog_clear()\n");
653
Gabe Black8f4baec2013-04-25 17:21:58 -0700654 /* Make sure ELOG structures are initialized */
655 if (elog_init() < 0)
656 return -1;
657
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700658 /* Erase flash area */
659 elog_flash_erase_area();
660
661 /* Prepare new empty area */
Gabe Black331eb082013-04-24 04:11:40 -0700662 elog_prepare_empty(flash);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700663
664 /* Update memory area from flash */
665 if (elog_sync_flash_to_mem() < 0)
666 return -1;
667
668 /* Log the clear event */
669 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, flash->total_size);
670
671 return 0;
672}
673
674/*
675 * Event log main entry point
676 */
677int elog_init(void)
678{
Duncan Laurie86bf3f52012-08-15 13:14:58 -0700679 u32 flash_base = CONFIG_ELOG_FLASH_BASE;
680 int flash_size = CONFIG_ELOG_AREA_SIZE;
681#if CONFIG_CHROMEOS
682 u8 *flash_base_ptr;
683#endif
684
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700685 if (elog_initialized)
686 return 0;
687
688 elog_debug("elog_init()\n");
689
690 /* Find SPI flash chip for backing store */
691 if (elog_spi_init() < 0) {
692 printk(BIOS_ERR, "ELOG: Unable to find SPI flash\n");
693 return -1;
694 }
695
Duncan Laurie86bf3f52012-08-15 13:14:58 -0700696#if CONFIG_CHROMEOS
697 /* Find the ELOG base and size in FMAP */
698 flash_size = find_fmap_entry("RW_ELOG", (void **)&flash_base_ptr);
699 if (flash_size < 0) {
700 printk(BIOS_WARNING, "ELOG: Unable to find RW_ELOG in FMAP, "
701 "using CONFIG_ELOG_FLASH_BASE instead\n");
702 flash_size = CONFIG_ELOG_AREA_SIZE;
703 } else {
704 flash_base = elog_flash_address_to_offset(flash_base_ptr);
705
706 /* Use configured size if smaller than FMAP size */
707 if (flash_size > CONFIG_ELOG_AREA_SIZE)
708 flash_size = CONFIG_ELOG_AREA_SIZE;
709 }
710#endif
711
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700712 /* Setup descriptors for flash and memory areas */
Duncan Laurie86bf3f52012-08-15 13:14:58 -0700713 if (elog_setup_descriptors(flash_base, flash_size) < 0) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700714 printk(BIOS_ERR, "ELOG: Unable to initialize descriptors\n");
715 return -1;
716 }
717
718 /* Bootstrap the flash area */
719 if (elog_flash_area_bootstrap() < 0) {
720 printk(BIOS_ERR, "ELOG: Unable to bootstrap flash area\n");
721 return -1;
722 }
723
724 /* Initialize the memory area */
725 if (elog_sync_flash_to_mem() < 0) {
726 printk(BIOS_ERR, "ELOG: Unable to initialize memory area\n");
727 return -1;
728 }
729
730 elog_initialized = 1;
731
Gabe Black331eb082013-04-24 04:11:40 -0700732 printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08x]\n",
Duncan Laurie215f27852012-10-10 14:34:49 -0700733 elog_get_flash()->backing_store, elog_get_flash()->flash_base);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700734
735 printk(BIOS_INFO, "ELOG: areas are %d bytes, full threshold %d,"
736 " shrink size %d\n", CONFIG_ELOG_AREA_SIZE,
737 CONFIG_ELOG_FULL_THRESHOLD, CONFIG_ELOG_SHRINK_SIZE);
738
739 /* Log a clear event if necessary */
740 if (elog_get_flash()->event_count == 0)
741 elog_add_event_word(ELOG_TYPE_LOG_CLEAR,
742 elog_get_flash()->total_size);
743
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700744 /* Shrink the log if we are getting too full */
Gabe Black331eb082013-04-24 04:11:40 -0700745 if (elog_get_flash()->next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie032be822013-05-23 07:23:09 -0700746 if (elog_shrink() < 0)
747 return -1;
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700748
Duncan Laurief4d36232012-06-23 16:37:45 -0700749#if CONFIG_ELOG_BOOT_COUNT && !defined(__SMM__)
750 /* Log boot count event except in S3 resume */
751 if (acpi_slp_type != 3)
752 elog_add_event_dword(ELOG_TYPE_BOOT, boot_count_read());
753#endif
754
Duncan Laurie1fc34612012-09-09 19:14:45 -0700755#if CONFIG_CMOS_POST && !defined(__SMM__)
756 /* Check and log POST codes from previous boot */
757 cmos_post_log();
758#endif
759
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700760 return 0;
761}
762
763/*
764 * Populate timestamp in event header with current time
765 */
766static void elog_fill_timestamp(struct event_header *event)
767{
768 event->second = cmos_read(RTC_CLK_SECOND);
769 event->minute = cmos_read(RTC_CLK_MINUTE);
770 event->hour = cmos_read(RTC_CLK_HOUR);
771 event->day = cmos_read(RTC_CLK_DAYOFMONTH);
772 event->month = cmos_read(RTC_CLK_MONTH);
773 event->year = cmos_read(RTC_CLK_YEAR);
774
775 /* Basic sanity check of expected ranges */
776 if (event->month > 0x12 || event->day > 0x31 || event->hour > 0x23 ||
777 event->minute > 0x59 || event->second > 0x59) {
778 event->year = 0;
779 event->month = 0;
780 event->day = 0;
781 event->hour = 0;
782 event->minute = 0;
783 event->second = 0;
784 }
785}
786
787/*
Gabe Black331eb082013-04-24 04:11:40 -0700788 * Add an event to the log
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700789 */
Gabe Black331eb082013-04-24 04:11:40 -0700790void elog_add_event_raw(u8 event_type, void *data, u8 data_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700791{
792 struct event_header *event;
Gabe Black331eb082013-04-24 04:11:40 -0700793 struct elog_descriptor *flash = elog_get_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700794 u8 event_size;
795
Gabe Black331eb082013-04-24 04:11:40 -0700796 elog_debug("elog_add_event_raw(type=%X)\n", event_type);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700797
798 /* Make sure ELOG structures are initialized */
799 if (elog_init() < 0)
Gabe Black331eb082013-04-24 04:11:40 -0700800 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700801
802 /* Header + Data + Checksum */
803 event_size = sizeof(*event) + data_size + 1;
804 if (event_size > MAX_EVENT_SIZE) {
805 printk(BIOS_ERR, "ELOG: Event(%X) data size too "
806 "big (%d)\n", event_type, event_size);
Gabe Black331eb082013-04-24 04:11:40 -0700807 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700808 }
809
810 /* Make sure event data can fit */
Gabe Black331eb082013-04-24 04:11:40 -0700811 if ((flash->next_event_offset + event_size) >= flash->data_size) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700812 printk(BIOS_ERR, "ELOG: Event(%X) does not fit\n",
813 event_type);
Gabe Black331eb082013-04-24 04:11:40 -0700814 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700815 }
816
817 /* Fill out event data */
Gabe Black331eb082013-04-24 04:11:40 -0700818 event = elog_get_next_event_base(flash);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700819 event->type = event_type;
820 event->length = event_size;
821 elog_fill_timestamp(event);
822
823 if (data_size)
824 memcpy(&event[1], data, data_size);
825
826 /* Zero the checksum byte and then compute checksum */
827 elog_update_checksum(event, 0);
828 elog_update_checksum(event, -(elog_checksum_event(event)));
829
830 /* Update memory descriptor parameters */
Gabe Black331eb082013-04-24 04:11:40 -0700831 flash->event_count++;
832
833 elog_flash_write((void *)event, event_size);
834
835 flash->last_event_offset = flash->next_event_offset;
836 flash->last_event_size = event_size;
837 flash->next_event_offset += event_size;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700838
839 printk(BIOS_INFO, "ELOG: Event(%X) added with size %d\n",
840 event_type, event_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700841
842 /* Shrink the log if we are getting too full */
Gabe Black331eb082013-04-24 04:11:40 -0700843 if (flash->next_event_offset >= CONFIG_ELOG_FULL_THRESHOLD)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700844 elog_shrink();
845}
846
847void elog_add_event(u8 event_type)
848{
849 elog_add_event_raw(event_type, NULL, 0);
850}
851
852void elog_add_event_byte(u8 event_type, u8 data)
853{
854 elog_add_event_raw(event_type, &data, sizeof(data));
855}
856
857void elog_add_event_word(u8 event_type, u16 data)
858{
859 elog_add_event_raw(event_type, &data, sizeof(data));
860}
861
862void elog_add_event_dword(u8 event_type, u32 data)
863{
864 elog_add_event_raw(event_type, &data, sizeof(data));
865}
866
867void elog_add_event_wake(u8 source, u32 instance)
868{
869 struct elog_event_data_wake wake = {
870 .source = source,
871 .instance = instance
872 };
873 elog_add_event_raw(ELOG_TYPE_WAKE_SOURCE, &wake, sizeof(wake));
874}