blob: de18d5d82f1dc70a8351e7a6ce30f03080408dc5 [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
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070043
44#if CONFIG_ELOG_DEBUG
45#define elog_debug(STR...) printk(BIOS_DEBUG, STR)
46#else
47#define elog_debug(STR...)
48#endif
49
50/*
51 * Static variables for ELOG state
52 */
Gabe Black0bf1feb2013-04-26 03:34:00 -070053static struct elog_area *elog_area;
54static u16 total_size;
Sol Boucherb4191492015-03-12 18:22:31 -070055static u16 log_size; /* excluding header */
Gabe Black0bf1feb2013-04-26 03:34:00 -070056static u32 flash_base;
Sol Boucherb4191492015-03-12 18:22:31 -070057static u16 full_threshold; /* from end of header */
58static u16 shrink_size; /* from end of header */
Gabe Black0bf1feb2013-04-26 03:34:00 -070059
60static elog_area_state area_state;
61static elog_header_state header_state;
62static elog_event_buffer_state event_buffer_state;
63
Sol Boucherb4191492015-03-12 18:22:31 -070064static u16 next_event_offset; /* from end of header */
Gabe Black0bf1feb2013-04-26 03:34:00 -070065static u16 event_count;
66
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070067static struct spi_flash *elog_spi;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070068
Julius Werner5d686222015-01-27 15:40:47 -080069static enum {
70 ELOG_UNINITIALIZED = 0,
71 ELOG_INITIALIZED,
72 ELOG_BROKEN,
73} elog_initialized = ELOG_UNINITIALIZED;
Aaron Durbin10a070b2013-06-28 12:30:53 -070074
75static inline u32 get_rom_size(void)
76{
77 u32 rom_size;
78
79 /* Assume the used space of the ROM image starts from 0. The
80 * physical size of the device may not be completely used. */
81 rom_size = elog_spi->size;
82 if (rom_size > CONFIG_ROM_SIZE)
83 rom_size = CONFIG_ROM_SIZE;
84
85 return rom_size;
86}
87
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070088/*
89 * Convert a memory mapped flash address into a flash offset
90 */
91static inline u32 elog_flash_address_to_offset(u8 *address)
92{
David Hendricks259e49a2014-03-20 20:31:23 -070093#if CONFIG_ARCH_X86
94 /* For x86, assume address is memory-mapped near 4GB */
Aaron Durbin10a070b2013-06-28 12:30:53 -070095 u32 rom_size;
96
Duncan Laurie7d2b81c2012-06-23 16:08:47 -070097 if (!elog_spi)
98 return 0;
Aaron Durbin10a070b2013-06-28 12:30:53 -070099
100 rom_size = get_rom_size();
101
102 return (u32)address - ((u32)~0UL - rom_size + 1);
David Hendricks259e49a2014-03-20 20:31:23 -0700103#else
Furquan Shaikhfd2f0302014-11-12 16:19:37 -0800104 return (u32)(uintptr_t)address;
David Hendricks259e49a2014-03-20 20:31:23 -0700105#endif
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700106}
107
108/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700109 * Pointer to an event log header in the event data area
110 */
111static inline struct event_header*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700112elog_get_event_base(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700113{
Gabe Black0bf1feb2013-04-26 03:34:00 -0700114 return (struct event_header *)&elog_area->data[offset];
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700115}
116
117/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700118 * Update the checksum at the last byte
119 */
120static void elog_update_checksum(struct event_header *event, u8 checksum)
121{
122 u8 *event_data = (u8*)event;
123 event_data[event->length - 1] = checksum;
124}
125
126/*
127 * Simple byte checksum for events
128 */
129static u8 elog_checksum_event(struct event_header *event)
130{
131 u8 index, checksum = 0;
132 u8 *data = (u8*)event;
133
134 for (index = 0; index < event->length; index++)
135 checksum += data[index];
136 return checksum;
137}
138
139/*
140 * Check if a raw buffer is filled with ELOG_TYPE_EOL byte
141 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700142static int elog_is_buffer_clear(void *base, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700143{
144 u8 *current = base;
145 u8 *end = current + size;
146
147 elog_debug("elog_is_buffer_clear(base=0x%p size=%u)\n", base, size);
148
149 for (; current != end; current++) {
150 if (*current != ELOG_TYPE_EOL)
151 return 0;
152 }
153 return 1;
154}
155
156/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700157 * Check that the ELOG area has been initialized and is valid.
158 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700159static int elog_is_area_valid(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700160{
161 elog_debug("elog_is_area_valid()\n");
162
Gabe Black0bf1feb2013-04-26 03:34:00 -0700163 if (area_state != ELOG_AREA_HAS_CONTENT)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700164 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700165 if (header_state != ELOG_HEADER_VALID)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700166 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700167 if (event_buffer_state != ELOG_EVENT_BUFFER_OK)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700168 return 0;
169 return 1;
170}
171
172/*
173 * Verify the contents of an ELOG Header structure
174 * Returns 1 if the header is valid, 0 otherwise
175 */
176static int elog_is_header_valid(struct elog_header *header)
177{
178 elog_debug("elog_is_header_valid()\n");
179
180 if (header->magic != ELOG_SIGNATURE) {
181 printk(BIOS_ERR, "ELOG: header magic 0x%X != 0x%X\n",
182 header->magic, ELOG_SIGNATURE);
183 return 0;
184 }
185 if (header->version != ELOG_VERSION) {
186 printk(BIOS_ERR, "ELOG: header version %u != %u\n",
187 header->version, ELOG_VERSION);
188 return 0;
189 }
190 if (header->header_size != sizeof(*header)) {
Denis 'GNUtoo' Cariklibc2c9ef2013-06-26 20:04:49 +0200191 printk(BIOS_ERR, "ELOG: header size mismatch %u != %zu\n",
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700192 header->header_size, sizeof(*header));
193 return 0;
194 }
195 return 1;
196}
197
198/*
199 * Validate the event header and data.
200 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700201static int elog_is_event_valid(u32 offset)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700202{
203 struct event_header *event;
204
Gabe Black0bf1feb2013-04-26 03:34:00 -0700205 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700206 if (!event)
207 return 0;
208
209 /* Validate event length */
210 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700211 sizeof(event->type) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700212 return 0;
213
214 /* End of event marker has been found */
215 if (event->type == ELOG_TYPE_EOL)
216 return 0;
217
218 /* Check if event fits in area */
219 if ((offsetof(struct event_header, length) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700220 sizeof(event->length) - 1 + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700221 return 0;
222
223 /*
224 * If the current event length + the current offset exceeds
225 * the area size then the event area is corrupt.
226 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700227 if ((event->length + offset) >= log_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700228 return 0;
229
230 /* Event length must be at least header size + checksum */
231 if (event->length < (sizeof(*event) + 1))
232 return 0;
233
234 /* If event checksum is invalid the area is corrupt */
235 if (elog_checksum_event(event) != 0)
236 return 0;
237
238 /* Event is valid */
239 return 1;
240}
241
242/*
Gabe Black331eb082013-04-24 04:11:40 -0700243 * Write 'size' bytes of data pointed to by 'address' in the flash backing
244 * store into flash. This will not erase the flash and it assumes the flash
245 * area has been erased appropriately.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700246 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700247static void elog_flash_write(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700248{
249 u32 offset;
250
Gabe Black331eb082013-04-24 04:11:40 -0700251 if (!address || !size || !elog_spi)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700252 return;
253
Gabe Black0bf1feb2013-04-26 03:34:00 -0700254 offset = flash_base;
255 offset += (u8 *)address - (u8 *)elog_area;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700256
Gabe Black331eb082013-04-24 04:11:40 -0700257 elog_debug("elog_flash_write(address=0x%p offset=0x%08x size=%u)\n",
258 address, offset, size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700259
260 /* Write the data to flash */
Gabe Black331eb082013-04-24 04:11:40 -0700261 elog_spi->write(elog_spi, offset, size, address);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700262}
263
264/*
265 * Erase the first block specified in the address.
266 * Only handles flash area within a single flash block.
267 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700268static void elog_flash_erase(void *address, u32 size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700269{
270 u32 offset;
271
272 if (!address || !size || !elog_spi)
273 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
278 elog_debug("elog_flash_erase(address=0x%p offset=0x%08x size=%u)\n",
279 address, offset, size);
280
281 /* Erase the sectors in this region */
282 elog_spi->erase(elog_spi, offset, size);
283}
284
285/*
Gabe Black0bf1feb2013-04-26 03:34:00 -0700286 * Scan the event area and validate each entry and update the ELOG state.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700287 */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700288static void elog_update_event_buffer_state(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700289{
290 u32 count = 0;
291 u32 offset = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700292 struct event_header *event;
293
294 elog_debug("elog_update_event_buffer_state()\n");
295
296 /* Go through each event and validate it */
297 while (1) {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700298 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700299
300 /* Do not de-reference anything past the area length */
301 if ((offsetof(struct event_header, type) +
Gabe Black0bf1feb2013-04-26 03:34:00 -0700302 sizeof(event->type) - 1 + offset) >= log_size) {
303 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700304 break;
305 }
306
307 /* The end of the event marker has been found */
308 if (event->type == ELOG_TYPE_EOL)
309 break;
310
311 /* Validate the event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700312 if (!elog_is_event_valid(offset)) {
313 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700314 break;
315 }
316
317 /* Move to the next event */
318 count++;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700319 offset += event->length;
320 }
321
322 /* Ensure the remaining buffer is empty */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700323 if (!elog_is_buffer_clear(&elog_area->data[offset], log_size - offset))
324 event_buffer_state = ELOG_EVENT_BUFFER_CORRUPTED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700325
Gabe Black0bf1feb2013-04-26 03:34:00 -0700326 /* Update ELOG state */
327 event_count = count;
328 next_event_offset = offset;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700329}
330
Gabe Black0bf1feb2013-04-26 03:34:00 -0700331static void elog_scan_flash(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700332{
Gabe Black84a93d12013-04-24 23:31:41 -0700333 elog_debug("elog_scan_flash()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700334
Gabe Black0bf1feb2013-04-26 03:34:00 -0700335 area_state = ELOG_AREA_UNDEFINED;
336 header_state = ELOG_HEADER_INVALID;
337 event_buffer_state = ELOG_EVENT_BUFFER_OK;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700338
Duncan Laurie215f27852012-10-10 14:34:49 -0700339 /* Fill memory buffer by reading from SPI */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700340 elog_spi->read(elog_spi, flash_base, total_size, elog_area);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700341
Gabe Black0bf1feb2013-04-26 03:34:00 -0700342 next_event_offset = 0;
343 event_count = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700344
Gabe Black455c68e2013-04-24 17:54:37 -0700345 /* Check if the area is empty or not */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700346 if (elog_is_buffer_clear(elog_area, total_size)) {
347 area_state = ELOG_AREA_EMPTY;
Gabe Black455c68e2013-04-24 17:54:37 -0700348 return;
349 }
350
Gabe Black0bf1feb2013-04-26 03:34:00 -0700351 area_state = ELOG_AREA_HAS_CONTENT;
Gabe Black455c68e2013-04-24 17:54:37 -0700352
353 /* Validate the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700354 if (!elog_is_header_valid(&elog_area->header)) {
355 header_state = ELOG_HEADER_INVALID;
Gabe Black455c68e2013-04-24 17:54:37 -0700356 return;
357 }
358
Gabe Black0bf1feb2013-04-26 03:34:00 -0700359 header_state = ELOG_HEADER_VALID;
360 elog_update_event_buffer_state();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700361}
362
Gabe Black0bf1feb2013-04-26 03:34:00 -0700363static void elog_prepare_empty(void)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700364{
365 struct elog_header *header;
366
Gabe Black0bf1feb2013-04-26 03:34:00 -0700367 elog_debug("elog_prepare_empty()\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700368
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700369 /* Write out the header */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700370 header = &elog_area->header;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700371 header->magic = ELOG_SIGNATURE;
372 header->version = ELOG_VERSION;
373 header->header_size = sizeof(struct elog_header);
374 header->reserved[0] = ELOG_TYPE_EOL;
375 header->reserved[1] = ELOG_TYPE_EOL;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700376 elog_flash_write(elog_area, header->header_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700377
Gabe Black0bf1feb2013-04-26 03:34:00 -0700378 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700379}
380
381/*
382 * Shrink the log, deleting old entries and moving the
Martin Roth56889792013-07-09 21:39:46 -0600383 * remaining ones to the front of the log.
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700384 */
385static int elog_shrink(void)
386{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700387 struct event_header *event;
388 u16 discard_count = 0;
389 u16 offset = 0;
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700390 u16 new_size = 0;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700391
392 elog_debug("elog_shrink()\n");
393
Sol Boucherb4191492015-03-12 18:22:31 -0700394 if (next_event_offset < shrink_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700395 return 0;
396
397 while (1) {
398 /* Next event has exceeded constraints */
Sol Boucherb4191492015-03-12 18:22:31 -0700399 if (offset > shrink_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700400 break;
401
Gabe Black0bf1feb2013-04-26 03:34:00 -0700402 event = elog_get_event_base(offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700403
404 /* Reached the end of the area */
405 if (!event || event->type == ELOG_TYPE_EOL)
406 break;
407
408 offset += event->length;
409 discard_count++;
410 }
411
Gabe Black0bf1feb2013-04-26 03:34:00 -0700412 new_size = next_event_offset - offset;
413 memmove(&elog_area->data[0], &elog_area->data[offset], new_size);
414 memset(&elog_area->data[new_size], ELOG_TYPE_EOL, log_size - new_size);
Gabe Blackbfae4aa2013-04-24 03:16:21 -0700415
Gabe Black0bf1feb2013-04-26 03:34:00 -0700416 elog_flash_erase(elog_area, total_size);
417 elog_flash_write(elog_area, total_size);
418 elog_scan_flash();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700419
Duncan Laurie032be822013-05-23 07:23:09 -0700420 /* Ensure the area was successfully erased */
Sol Boucherb4191492015-03-12 18:22:31 -0700421 if (next_event_offset >= full_threshold) {
Duncan Laurie032be822013-05-23 07:23:09 -0700422 printk(BIOS_ERR, "ELOG: Flash area was not erased!\n");
423 return -1;
424 }
425
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700426 /* Add clear event */
427 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, offset);
428
429 return 0;
430}
431
Duncan Laurie215f27852012-10-10 14:34:49 -0700432#ifndef __SMM__
Furquan Shaikh7f4221c2014-11-12 16:19:37 -0800433#if IS_ENABLED(CONFIG_ARCH_X86)
434
435/*
436 * Convert a flash offset into a memory mapped flash address
437 */
438static inline u8 *elog_flash_offset_to_address(u32 offset)
439{
440 u32 rom_size;
441
442 if (!elog_spi)
443 return NULL;
444
445 rom_size = get_rom_size();
446
447 return (u8 *)((u32)~0UL - rom_size + 1 + offset);
448}
449
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700450/*
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700451 * Fill out SMBIOS Type 15 table entry so the
452 * event log can be discovered at runtime.
453 */
454int elog_smbios_write_type15(unsigned long *current, int handle)
455{
456 struct smbios_type15 *t = (struct smbios_type15 *)*current;
457 int len = sizeof(struct smbios_type15);
458
Duncan Laurie215f27852012-10-10 14:34:49 -0700459#if CONFIG_ELOG_CBMEM
460 /* Save event log buffer into CBMEM for the OS to read */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700461 void *cbmem = cbmem_add(CBMEM_ID_ELOG, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700462 if (!cbmem)
463 return 0;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700464 memcpy(cbmem, elog_area, total_size);
Duncan Laurie215f27852012-10-10 14:34:49 -0700465#endif
466
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700467 memset(t, 0, len);
468 t->type = SMBIOS_EVENT_LOG;
469 t->length = len - 2;
470 t->handle = handle;
Gabe Black0bf1feb2013-04-26 03:34:00 -0700471 t->area_length = total_size - 1;
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700472 t->header_offset = 0;
473 t->data_offset = sizeof(struct elog_header);
474 t->access_method = SMBIOS_EVENTLOG_ACCESS_METHOD_MMIO32;
475 t->log_status = SMBIOS_EVENTLOG_STATUS_VALID;
476 t->change_token = 0;
Duncan Laurie215f27852012-10-10 14:34:49 -0700477#if CONFIG_ELOG_CBMEM
478 t->address = (u32)cbmem;
479#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700480 t->address = (u32)elog_flash_offset_to_address(flash_base);
Duncan Laurie215f27852012-10-10 14:34:49 -0700481#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700482 t->header_format = ELOG_HEADER_TYPE_OEM;
483 t->log_type_descriptors = 0;
484 t->log_type_descriptor_length = 2;
485
486 *current += len;
487 return len;
488}
Duncan Laurie215f27852012-10-10 14:34:49 -0700489#endif
Furquan Shaikh7f4221c2014-11-12 16:19:37 -0800490#endif
Duncan Laurie472ec9c2012-06-23 16:13:42 -0700491
492/*
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700493 * Clear the entire event log
494 */
495int elog_clear(void)
496{
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700497 elog_debug("elog_clear()\n");
498
Gabe Black8f4baec2013-04-25 17:21:58 -0700499 /* Make sure ELOG structures are initialized */
500 if (elog_init() < 0)
501 return -1;
502
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700503 /* Erase flash area */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700504 elog_flash_erase(elog_area, total_size);
505 elog_prepare_empty();
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700506
Gabe Black0bf1feb2013-04-26 03:34:00 -0700507 if (!elog_is_area_valid())
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700508 return -1;
509
510 /* Log the clear event */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700511 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700512
513 return 0;
514}
515
Gabe Black0bf1feb2013-04-26 03:34:00 -0700516static void elog_find_flash(void)
Gabe Black84a93d12013-04-24 23:31:41 -0700517{
Gabe Black0bf1feb2013-04-26 03:34:00 -0700518 elog_debug("elog_find_flash()\n");
Gabe Black84a93d12013-04-24 23:31:41 -0700519
520#if CONFIG_CHROMEOS
521 /* Find the ELOG base and size in FMAP */
Julius Werner5d686222015-01-27 15:40:47 -0800522 u8 *flash_base_ptr;
523 int fmap_size = find_fmap_entry("RW_ELOG", (void **)&flash_base_ptr);
524 if (fmap_size < 0) {
525 printk(BIOS_WARNING, "ELOG: Unable to find RW_ELOG in FMAP\n");
526 flash_base = total_size = 0;
Gabe Black84a93d12013-04-24 23:31:41 -0700527 } else {
Gabe Black0bf1feb2013-04-26 03:34:00 -0700528 flash_base = elog_flash_address_to_offset(flash_base_ptr);
Julius Werner5d686222015-01-27 15:40:47 -0800529 total_size = MIN(fmap_size, CONFIG_ELOG_AREA_SIZE);
Gabe Black84a93d12013-04-24 23:31:41 -0700530 }
531#else
Gabe Black0bf1feb2013-04-26 03:34:00 -0700532 flash_base = CONFIG_ELOG_FLASH_BASE;
533 total_size = CONFIG_ELOG_AREA_SIZE;
Gabe Black84a93d12013-04-24 23:31:41 -0700534#endif
Gabe Black0bf1feb2013-04-26 03:34:00 -0700535 log_size = total_size - sizeof(struct elog_header);
Sol Boucherb4191492015-03-12 18:22:31 -0700536 full_threshold = log_size - ELOG_MIN_AVAILABLE_ENTRIES * MAX_EVENT_SIZE;
537 shrink_size = MIN(total_size * ELOG_SHRINK_PERCENTAGE / 100,
538 full_threshold);
Gabe Black84a93d12013-04-24 23:31:41 -0700539}
540
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700541/*
542 * Event log main entry point
543 */
544int elog_init(void)
545{
Julius Werner5d686222015-01-27 15:40:47 -0800546 switch (elog_initialized) {
547 case ELOG_UNINITIALIZED:
548 break;
549 case ELOG_INITIALIZED:
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700550 return 0;
Julius Werner5d686222015-01-27 15:40:47 -0800551 case ELOG_BROKEN:
552 return -1;
553 }
554 elog_initialized = ELOG_BROKEN;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700555
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;
Sol Boucherb4191492015-03-12 18:22:31 -0700570 } else if (total_size < sizeof(struct elog_header) + MAX_EVENT_SIZE) {
571 printk(BIOS_ERR, "ELOG: Region too small to hold any events\n");
572 return -1;
573 } else if (log_size - shrink_size >= full_threshold) {
574 printk(BIOS_ERR,
575 "ELOG: SHRINK_PERCENTAGE set too small for MIN_AVAILABLE_ENTRIES\n");
576 return -1;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700577 }
578
Gabe Black0bf1feb2013-04-26 03:34:00 -0700579 elog_area = malloc(total_size);
580 if (!elog_area) {
Gabe Black84a93d12013-04-24 23:31:41 -0700581 printk(BIOS_ERR, "ELOG: Unable to allocate backing store\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700582 return -1;
583 }
Gabe Black84a93d12013-04-24 23:31:41 -0700584
585 /* Load the log from flash */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700586 elog_scan_flash();
Gabe Black84a93d12013-04-24 23:31:41 -0700587
588 /* Prepare the flash if necessary */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700589 if (header_state == ELOG_HEADER_INVALID ||
590 event_buffer_state == ELOG_EVENT_BUFFER_CORRUPTED) {
Gabe Black84a93d12013-04-24 23:31:41 -0700591 /* If the header is invalid or the events are corrupted,
592 * no events can be salvaged so erase the entire area. */
593 printk(BIOS_ERR, "ELOG: flash area invalid\n");
Gabe Black0bf1feb2013-04-26 03:34:00 -0700594 elog_flash_erase(elog_area, total_size);
595 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700596 }
597
Gabe Black0bf1feb2013-04-26 03:34:00 -0700598 if (area_state == ELOG_AREA_EMPTY)
599 elog_prepare_empty();
Gabe Black84a93d12013-04-24 23:31:41 -0700600
Gabe Black0bf1feb2013-04-26 03:34:00 -0700601 if (!elog_is_area_valid()) {
Gabe Black84a93d12013-04-24 23:31:41 -0700602 printk(BIOS_ERR, "ELOG: Unable to prepare flash\n");
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700603 return -1;
604 }
605
Gabe Black331eb082013-04-24 04:11:40 -0700606 printk(BIOS_INFO, "ELOG: FLASH @0x%p [SPI 0x%08x]\n",
Gabe Black0bf1feb2013-04-26 03:34:00 -0700607 elog_area, flash_base);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700608
Gabe Black84a93d12013-04-24 23:31:41 -0700609 printk(BIOS_INFO, "ELOG: area is %d bytes, full threshold %d,"
Sol Boucherb4191492015-03-12 18:22:31 -0700610 " shrink size %d\n", total_size, full_threshold, shrink_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700611
Julius Wernerefae69a2015-02-05 12:55:45 -0800612 elog_initialized = ELOG_INITIALIZED;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700613
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700614 /* Shrink the log if we are getting too full */
Sol Boucherb4191492015-03-12 18:22:31 -0700615 if (next_event_offset >= full_threshold)
Duncan Laurie032be822013-05-23 07:23:09 -0700616 if (elog_shrink() < 0)
617 return -1;
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700618
Julius Wernerefae69a2015-02-05 12:55:45 -0800619 /* Log a clear event if necessary */
620 if (event_count == 0)
621 elog_add_event_word(ELOG_TYPE_LOG_CLEAR, total_size);
622
Gabe Black84a93d12013-04-24 23:31:41 -0700623#if !defined(__SMM__)
Duncan Laurief4d36232012-06-23 16:37:45 -0700624 /* Log boot count event except in S3 resume */
David Hendricks259e49a2014-03-20 20:31:23 -0700625#if CONFIG_ELOG_BOOT_COUNT == 1
626#if CONFIG_HAVE_ACPI_RESUME == 1
627 if (!acpi_is_wakeup_s3())
628#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700629 elog_add_event_dword(ELOG_TYPE_BOOT, boot_count_read());
David Hendricks6a29e6c2014-06-18 13:03:03 -0700630#else
631 /* If boot count is not implemented, fake it. */
632 elog_add_event_dword(ELOG_TYPE_BOOT, 0);
David Hendricks259e49a2014-03-20 20:31:23 -0700633#endif
Duncan Laurief4d36232012-06-23 16:37:45 -0700634
David Hendricks259e49a2014-03-20 20:31:23 -0700635#if CONFIG_ARCH_X86
Duncan Laurie1fc34612012-09-09 19:14:45 -0700636 /* Check and log POST codes from previous boot */
Gabe Black84a93d12013-04-24 23:31:41 -0700637 if (CONFIG_CMOS_POST)
638 cmos_post_log();
Duncan Laurie1fc34612012-09-09 19:14:45 -0700639#endif
David Hendricks259e49a2014-03-20 20:31:23 -0700640#endif
Duncan Laurie1fc34612012-09-09 19:14:45 -0700641
Julius Werner5d686222015-01-27 15:40:47 -0800642 elog_initialized = ELOG_INITIALIZED;
643
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700644 return 0;
645}
646
647/*
648 * Populate timestamp in event header with current time
649 */
650static void elog_fill_timestamp(struct event_header *event)
651{
Gabe Blacka4c4b1c2014-04-30 21:41:23 -0700652 struct rtc_time time;
653
654 rtc_get(&time);
655 event->second = bin2bcd(time.sec);
656 event->minute = bin2bcd(time.min);
657 event->hour = bin2bcd(time.hour);
658 event->day = bin2bcd(time.mday);
659 event->month = bin2bcd(time.mon);
660 event->year = bin2bcd(time.year) & 0xff;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700661
662 /* Basic sanity check of expected ranges */
663 if (event->month > 0x12 || event->day > 0x31 || event->hour > 0x23 ||
664 event->minute > 0x59 || event->second > 0x59) {
665 event->year = 0;
666 event->month = 0;
667 event->day = 0;
668 event->hour = 0;
669 event->minute = 0;
670 event->second = 0;
671 }
672}
673
674/*
Gabe Black331eb082013-04-24 04:11:40 -0700675 * Add an event to the log
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700676 */
Gabe Black331eb082013-04-24 04:11:40 -0700677void elog_add_event_raw(u8 event_type, void *data, u8 data_size)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700678{
679 struct event_header *event;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700680 u8 event_size;
681
Gabe Black331eb082013-04-24 04:11:40 -0700682 elog_debug("elog_add_event_raw(type=%X)\n", event_type);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700683
684 /* Make sure ELOG structures are initialized */
685 if (elog_init() < 0)
Gabe Black331eb082013-04-24 04:11:40 -0700686 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700687
688 /* Header + Data + Checksum */
689 event_size = sizeof(*event) + data_size + 1;
690 if (event_size > MAX_EVENT_SIZE) {
691 printk(BIOS_ERR, "ELOG: Event(%X) data size too "
692 "big (%d)\n", event_type, event_size);
Gabe Black331eb082013-04-24 04:11:40 -0700693 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700694 }
695
696 /* Make sure event data can fit */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700697 if ((next_event_offset + event_size) >= log_size) {
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700698 printk(BIOS_ERR, "ELOG: Event(%X) does not fit\n",
699 event_type);
Gabe Black331eb082013-04-24 04:11:40 -0700700 return;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700701 }
702
703 /* Fill out event data */
Gabe Black0bf1feb2013-04-26 03:34:00 -0700704 event = elog_get_event_base(next_event_offset);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700705 event->type = event_type;
706 event->length = event_size;
707 elog_fill_timestamp(event);
708
709 if (data_size)
710 memcpy(&event[1], data, data_size);
711
712 /* Zero the checksum byte and then compute checksum */
713 elog_update_checksum(event, 0);
714 elog_update_checksum(event, -(elog_checksum_event(event)));
715
Gabe Black0bf1feb2013-04-26 03:34:00 -0700716 /* Update the ELOG state */
717 event_count++;
Gabe Black331eb082013-04-24 04:11:40 -0700718
719 elog_flash_write((void *)event, event_size);
720
Gabe Black0bf1feb2013-04-26 03:34:00 -0700721 next_event_offset += event_size;
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700722
723 printk(BIOS_INFO, "ELOG: Event(%X) added with size %d\n",
724 event_type, event_size);
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700725
726 /* Shrink the log if we are getting too full */
Sol Boucherb4191492015-03-12 18:22:31 -0700727 if (next_event_offset >= full_threshold)
Duncan Laurie7d2b81c2012-06-23 16:08:47 -0700728 elog_shrink();
729}
730
731void elog_add_event(u8 event_type)
732{
733 elog_add_event_raw(event_type, NULL, 0);
734}
735
736void elog_add_event_byte(u8 event_type, u8 data)
737{
738 elog_add_event_raw(event_type, &data, sizeof(data));
739}
740
741void elog_add_event_word(u8 event_type, u16 data)
742{
743 elog_add_event_raw(event_type, &data, sizeof(data));
744}
745
746void elog_add_event_dword(u8 event_type, u32 data)
747{
748 elog_add_event_raw(event_type, &data, sizeof(data));
749}
750
751void elog_add_event_wake(u8 source, u32 instance)
752{
753 struct elog_event_data_wake wake = {
754 .source = source,
755 .instance = instance
756 };
757 elog_add_event_raw(ELOG_TYPE_WAKE_SOURCE, &wake, sizeof(wake));
758}