blob: e853e36e7b498e61474e1133fd2a2b11c94cd70f [file] [log] [blame]
Duncan Laurief4d36232012-06-23 16:37:45 -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
Patrick Georgib890a122015-03-26 15:17:45 +010017 * Foundation, Inc.
Duncan Laurief4d36232012-06-23 16:37:45 -070018 */
19
20#include <console/console.h>
21#include <ip_checksum.h>
22#include <pc80/mc146818rtc.h>
23#include <stddef.h>
24#include <stdint.h>
25#include <elog.h>
26
27/*
28 * We need a region in CMOS to store the boot counter.
29 *
30 * This can either be declared as part of the option
31 * table or statically defined in the board config.
32 */
33#if CONFIG_USE_OPTION_TABLE
34# include "option_table.h"
35# define BOOT_COUNT_CMOS_OFFSET (CMOS_VSTART_boot_count_offset >> 3)
36#else
Martin Roth46cf9f72015-07-11 13:56:58 -060037# if defined(CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET) && CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET
Duncan Laurief4d36232012-06-23 16:37:45 -070038# define BOOT_COUNT_CMOS_OFFSET CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET
39# else
Martin Roth46cf9f72015-07-11 13:56:58 -060040# error "Must configure CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET"
Duncan Laurief4d36232012-06-23 16:37:45 -070041# endif
42#endif
43
44#define BOOT_COUNT_SIGNATURE 0x4342 /* 'BC' */
45
46struct boot_count {
47 u16 signature;
48 u32 count;
49 u16 checksum;
50} __attribute__ ((packed));
51
52/* Read and validate boot count structure from CMOS */
53static int boot_count_cmos_read(struct boot_count *bc)
54{
55 u8 i, *p;
56 u16 csum;
57
58 for (p = (u8*)bc, i = 0; i < sizeof(*bc); i++, p++)
59 *p = cmos_read(BOOT_COUNT_CMOS_OFFSET + i);
60
61 /* Verify signature */
62 if (bc->signature != BOOT_COUNT_SIGNATURE) {
63 printk(BIOS_DEBUG, "Boot Count invalid signature\n");
64 return -1;
65 }
66
67 /* Verify checksum over signature and counter only */
68 csum = compute_ip_checksum(bc, offsetof(struct boot_count, checksum));
69
70 if (csum != bc->checksum) {
71 printk(BIOS_DEBUG, "Boot Count checksum mismatch\n");
72 return -1;
73 }
74
75 return 0;
76}
77
78/* Write boot count structure to CMOS */
79static void boot_count_cmos_write(struct boot_count *bc)
80{
81 u8 i, *p;
82
83 /* Checksum over signature and counter only */
84 bc->checksum = compute_ip_checksum(
85 bc, offsetof(struct boot_count, checksum));
86
87 for (p = (u8*)bc, i = 0; i < sizeof(*bc); i++, p++)
88 cmos_write(*p, BOOT_COUNT_CMOS_OFFSET + i);
89}
90
91/* Increment boot count and return the new value */
92u32 boot_count_increment(void)
93{
94 struct boot_count bc;
95
96 /* Read and increment boot count */
97 if (boot_count_cmos_read(&bc) < 0) {
98 /* Structure invalid, re-initialize */
99 bc.signature = BOOT_COUNT_SIGNATURE;
100 bc.count = 0;
101 }
102
103 /* Increment boot counter */
104 bc.count++;
105
106 /* Write the new count to CMOS */
107 boot_count_cmos_write(&bc);
108
109 printk(BIOS_DEBUG, "Boot Count incremented to %u\n", bc.count);
110 return bc.count;
111}
112
113/* Return the current boot count */
114u32 boot_count_read(void)
115{
116 struct boot_count bc;
117
118 if (boot_count_cmos_read(&bc) < 0)
119 return 0;
120
121 return bc.count;
122}