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