1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
8 #include <pc80/mc146818rtc.h>
11 /* option_table.h is autogenerated */
12 #include "option_table.h"
14 /* Don't warn for checking >= LB_CKS_RANGE_START even though it may be 0. */
15 #pragma GCC diagnostic ignored "-Wtype-limits"
18 * This routine returns the value of the requested bits.
19 * input bit = bit count from the beginning of the CMOS image
20 * length = number of bits to include in the value
21 * ret = a character pointer to where the value is to be returned
22 * returns CB_SUCCESS = successful, cb_err code if an error occurred
24 static enum cb_err
get_cmos_value(unsigned long bit
, unsigned long length
,
28 unsigned long byte
, byte_bit
;
33 * The table is checked when it is built to ensure all
37 byte
= bit
/ 8; /* find the byte where the data starts */
38 byte_bit
= bit
% 8; /* find the bit in the byte where the data starts */
39 if (length
< 9) { /* one byte or less */
40 uchar
= cmos_read(byte
); /* load the byte */
41 uchar
>>= byte_bit
; /* shift the bits to byte align */
42 /* clear unspecified bits */
43 ret
[0] = uchar
& ((1 << length
) - 1);
44 } else { /* more than one byte so transfer the whole bytes */
45 for (i
= 0; length
; i
++, length
-= 8, byte
++) {
47 ret
[i
] = cmos_read(byte
);
53 static struct cmos_option_table
*get_cmos_layout(void)
55 static struct cmos_option_table
*ct
= NULL
;
58 * In case VBOOT is enabled and this function is called from SMM,
59 * we have multiple CMOS layout files and to locate them we'd need to
60 * include VBOOT into SMM...
62 * Support only one CMOS layout in the RO CBFS for now.
65 ct
= cbfs_ro_map("cmos_layout.bin", NULL
);
67 printk(BIOS_ERR
, "RTC: cmos_layout.bin could not be found. "
68 "Options are disabled\n");
72 static struct cmos_entries
*find_cmos_entry(struct cmos_option_table
*ct
, const char *name
)
74 /* Figure out how long name is */
75 const size_t namelen
= strnlen(name
, CMOS_MAX_NAME_LENGTH
);
76 struct cmos_entries
*ce
;
78 /* Find the requested entry record */
79 ce
= (struct cmos_entries
*)((unsigned char *)ct
+ ct
->header_length
);
80 for (; ce
->tag
== LB_TAG_OPTION
;
81 ce
= (struct cmos_entries
*)((unsigned char *)ce
+ ce
->size
)) {
82 if (memcmp(ce
->name
, name
, namelen
) == 0)
88 static enum cb_err
cmos_get_uint_option(unsigned int *dest
, const char *name
)
90 struct cmos_option_table
*ct
;
91 struct cmos_entries
*ce
;
93 ct
= get_cmos_layout();
95 return CB_CMOS_LAYOUT_NOT_FOUND
;
97 ce
= find_cmos_entry(ct
, name
);
99 printk(BIOS_DEBUG
, "No CMOS option '%s'.\n", name
);
100 return CB_CMOS_OPTION_NOT_FOUND
;
103 if (ce
->config
!= 'e' && ce
->config
!= 'h') {
104 printk(BIOS_ERR
, "CMOS option '%s' is not of integer type.\n", name
);
108 if (!cmos_checksum_valid(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
, LB_CKS_LOC
))
109 return CB_CMOS_CHECKSUM_INVALID
;
111 if (get_cmos_value(ce
->bit
, ce
->length
, dest
) != CB_SUCCESS
)
112 return CB_CMOS_ACCESS_ERROR
;
117 unsigned int get_uint_option(const char *name
, const unsigned int fallback
)
119 unsigned int value
= 0;
120 return cmos_get_uint_option(&value
, name
) == CB_SUCCESS
? value
: fallback
;
123 static enum cb_err
set_cmos_value(unsigned long bit
, unsigned long length
,
127 unsigned long byte
, byte_bit
;
129 unsigned char uchar
, mask
;
130 unsigned int chksum_update_needed
= 0;
133 byte
= bit
/ 8; /* find the byte where the data starts */
134 byte_bit
= bit
% 8; /* find the bit where the data starts */
135 if (length
<= 8) { /* one byte or less */
136 mask
= (1 << length
) - 1;
139 uchar
= cmos_read(byte
);
141 uchar
|= (ret
[0] << byte_bit
);
142 cmos_write(uchar
, byte
);
143 if (byte
>= LB_CKS_RANGE_START
&& byte
<= LB_CKS_RANGE_END
)
144 chksum_update_needed
= 1;
145 } else { /* more that one byte so transfer the whole bytes */
146 if (byte_bit
|| length
% 8)
149 for (i
= 0; length
; i
++, length
-= 8, byte
++) {
150 cmos_write(ret
[i
], byte
);
151 if (byte
>= LB_CKS_RANGE_START
&&
152 byte
<= LB_CKS_RANGE_END
)
153 chksum_update_needed
= 1;
157 if (chksum_update_needed
) {
158 cmos_set_checksum(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
,
164 static enum cb_err
cmos_set_uint_option(const char *name
, unsigned int *value
)
166 struct cmos_option_table
*ct
;
167 struct cmos_entries
*ce
;
169 ct
= get_cmos_layout();
171 return CB_CMOS_LAYOUT_NOT_FOUND
;
173 ce
= find_cmos_entry(ct
, name
);
175 printk(BIOS_DEBUG
, "WARNING: No CMOS option '%s'.\n", name
);
176 return CB_CMOS_OPTION_NOT_FOUND
;
179 if (ce
->config
!= 'e' && ce
->config
!= 'h') {
180 printk(BIOS_ERR
, "CMOS option '%s' is not of integer type.\n", name
);
184 if (set_cmos_value(ce
->bit
, ce
->length
, value
) != CB_SUCCESS
)
185 return CB_CMOS_ACCESS_ERROR
;
190 enum cb_err
set_uint_option(const char *name
, unsigned int value
)
192 return cmos_set_uint_option(name
, &value
);
195 int cmos_lb_cks_valid(void)
197 return cmos_checksum_valid(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
, LB_CKS_LOC
);
200 void sanitize_cmos(void)
202 const unsigned char *cmos_default
;
203 const bool cmos_need_reset
=
204 (CONFIG(STATIC_OPTION_TABLE
) || cmos_error() || !cmos_lb_cks_valid())
205 && !acpi_is_wakeup_s3();
209 if (CONFIG(TPM_MEASURED_BOOT
) || cmos_need_reset
) {
210 cmos_default
= cbfs_map("cmos.default", &length
);
212 if (!cmos_default
|| !cmos_need_reset
)
215 u8 control_state
= cmos_disable_rtc();
216 /* Copy checked range and the checksum from the default */
217 for (i
= LB_CKS_RANGE_START
; i
< MIN(LB_CKS_RANGE_END
+ 1, length
); i
++)
218 cmos_write_inner(cmos_default
[i
], i
);
219 /* CMOS checksum takes 2 bytes */
220 cmos_write_inner(cmos_default
[LB_CKS_LOC
], LB_CKS_LOC
);
221 cmos_write_inner(cmos_default
[LB_CKS_LOC
+ 1], LB_CKS_LOC
+ 1);
222 cmos_restore_rtc(control_state
);