blob: 9d618f9500e6782f90544fbce5b28e4025c1b6db [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Duncan Laurief4d36232012-06-23 16:37:45 -07002
Julius Wernerde371092024-01-30 16:51:05 -08003#include <commonlib/bsd/ipchksum.h>
Duncan Laurief4d36232012-06-23 16:37:45 -07004#include <console/console.h>
Duncan Laurief4d36232012-06-23 16:37:45 -07005#include <pc80/mc146818rtc.h>
Duncan Laurief4d36232012-06-23 16:37:45 -07006#include <stdint.h>
7#include <elog.h>
8
9/*
10 * We need a region in CMOS to store the boot counter.
11 *
12 * This can either be declared as part of the option
13 * table or statically defined in the board config.
14 */
Julius Wernercd49cce2019-03-05 16:53:33 -080015#if CONFIG(USE_OPTION_TABLE)
Duncan Laurief4d36232012-06-23 16:37:45 -070016# include "option_table.h"
17# define BOOT_COUNT_CMOS_OFFSET (CMOS_VSTART_boot_count_offset >> 3)
18#else
Elyes HAOUASb58e99d2019-01-23 12:04:43 +010019# if (CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET != 0)
Duncan Laurief4d36232012-06-23 16:37:45 -070020# define BOOT_COUNT_CMOS_OFFSET CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET
21# else
Martin Roth46cf9f72015-07-11 13:56:58 -060022# error "Must configure CONFIG_ELOG_BOOT_COUNT_CMOS_OFFSET"
Duncan Laurief4d36232012-06-23 16:37:45 -070023# endif
24#endif
25
26#define BOOT_COUNT_SIGNATURE 0x4342 /* 'BC' */
27
28struct boot_count {
29 u16 signature;
30 u32 count;
31 u16 checksum;
Stefan Reinauer6a001132017-07-13 02:20:27 +020032} __packed;
Duncan Laurief4d36232012-06-23 16:37:45 -070033
34/* Read and validate boot count structure from CMOS */
35static int boot_count_cmos_read(struct boot_count *bc)
36{
37 u8 i, *p;
38 u16 csum;
39
Frans Hendriksa4ecf962021-01-27 09:23:59 +010040 for (p = (u8 *)bc, i = 0; i < sizeof(*bc); i++, p++)
Duncan Laurief4d36232012-06-23 16:37:45 -070041 *p = cmos_read(BOOT_COUNT_CMOS_OFFSET + i);
42
43 /* Verify signature */
44 if (bc->signature != BOOT_COUNT_SIGNATURE) {
45 printk(BIOS_DEBUG, "Boot Count invalid signature\n");
46 return -1;
47 }
48
49 /* Verify checksum over signature and counter only */
Julius Wernerde371092024-01-30 16:51:05 -080050 csum = ipchksum(bc, offsetof(struct boot_count, checksum));
Duncan Laurief4d36232012-06-23 16:37:45 -070051
52 if (csum != bc->checksum) {
53 printk(BIOS_DEBUG, "Boot Count checksum mismatch\n");
54 return -1;
55 }
56
57 return 0;
58}
59
60/* Write boot count structure to CMOS */
61static void boot_count_cmos_write(struct boot_count *bc)
62{
63 u8 i, *p;
64
65 /* Checksum over signature and counter only */
Julius Wernerde371092024-01-30 16:51:05 -080066 bc->checksum = ipchksum(
Duncan Laurief4d36232012-06-23 16:37:45 -070067 bc, offsetof(struct boot_count, checksum));
68
Frans Hendriksa4ecf962021-01-27 09:23:59 +010069 for (p = (u8 *)bc, i = 0; i < sizeof(*bc); i++, p++)
Duncan Laurief4d36232012-06-23 16:37:45 -070070 cmos_write(*p, BOOT_COUNT_CMOS_OFFSET + i);
71}
72
73/* Increment boot count and return the new value */
74u32 boot_count_increment(void)
75{
76 struct boot_count bc;
77
78 /* Read and increment boot count */
79 if (boot_count_cmos_read(&bc) < 0) {
80 /* Structure invalid, re-initialize */
81 bc.signature = BOOT_COUNT_SIGNATURE;
82 bc.count = 0;
83 }
84
85 /* Increment boot counter */
86 bc.count++;
87
88 /* Write the new count to CMOS */
89 boot_count_cmos_write(&bc);
90
91 printk(BIOS_DEBUG, "Boot Count incremented to %u\n", bc.count);
92 return bc.count;
93}
94
95/* Return the current boot count */
96u32 boot_count_read(void)
97{
98 struct boot_count bc;
99
100 if (boot_count_cmos_read(&bc) < 0)
101 return 0;
102
103 return bc.count;
104}