1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
7 #include <pc80/mc146818rtc.h>
10 /* option_table.h is autogenerated */
11 #include "option_table.h"
13 /* Don't warn for checking >= LB_CKS_RANGE_START even though it may be 0. */
14 #pragma GCC diagnostic ignored "-Wtype-limits"
17 * This routine returns the value of the requested bits.
18 * input bit = bit count from the beginning of the CMOS image
19 * length = number of bits to include in the value
20 * ret = a character pointer to where the value is to be returned
21 * returns CB_SUCCESS = successful, cb_err code if an error occurred
23 static enum cb_err
get_cmos_value(unsigned long bit
, unsigned long length
,
27 unsigned long byte
, byte_bit
;
32 * The table is checked when it is built to ensure all
36 byte
= bit
/ 8; /* find the byte where the data starts */
37 byte_bit
= bit
% 8; /* find the bit in the byte where the data starts */
38 if (length
< 9) { /* one byte or less */
39 uchar
= cmos_read(byte
); /* load the byte */
40 uchar
>>= byte_bit
; /* shift the bits to byte align */
41 /* clear unspecified bits */
42 ret
[0] = uchar
& ((1 << length
) - 1);
43 } else { /* more than one byte so transfer the whole bytes */
44 for (i
= 0; length
; i
++, length
-= 8, byte
++) {
46 ret
[i
] = cmos_read(byte
);
52 static struct cmos_option_table
*get_cmos_layout(void)
54 static struct cmos_option_table
*ct
= NULL
;
57 * In case VBOOT is enabled and this function is called from SMM,
58 * we have multiple CMOS layout files and to locate them we'd need to
59 * include VBOOT into SMM...
61 * Support only one CMOS layout in the RO CBFS for now.
64 ct
= cbfs_ro_map("cmos_layout.bin", NULL
);
66 printk(BIOS_ERR
, "RTC: cmos_layout.bin could not be found. "
67 "Options are disabled\n");
71 static struct cmos_entries
*find_cmos_entry(struct cmos_option_table
*ct
, const char *name
)
73 /* Figure out how long name is */
74 const size_t namelen
= strnlen(name
, CMOS_MAX_NAME_LENGTH
);
75 struct cmos_entries
*ce
;
77 /* Find the requested entry record */
78 ce
= (struct cmos_entries
*)((unsigned char *)ct
+ ct
->header_length
);
79 for (; ce
->tag
== LB_TAG_OPTION
;
80 ce
= (struct cmos_entries
*)((unsigned char *)ce
+ ce
->size
)) {
81 if (memcmp(ce
->name
, name
, namelen
) == 0)
87 static enum cb_err
cmos_get_uint_option(unsigned int *dest
, const char *name
)
89 struct cmos_option_table
*ct
;
90 struct cmos_entries
*ce
;
92 ct
= get_cmos_layout();
94 return CB_CMOS_LAYOUT_NOT_FOUND
;
96 ce
= find_cmos_entry(ct
, name
);
98 printk(BIOS_DEBUG
, "No CMOS option '%s'.\n", name
);
99 return CB_CMOS_OPTION_NOT_FOUND
;
102 if (ce
->config
!= 'e' && ce
->config
!= 'h') {
103 printk(BIOS_ERR
, "CMOS option '%s' is not of integer type.\n", name
);
107 if (!cmos_checksum_valid(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
, LB_CKS_LOC
))
108 return CB_CMOS_CHECKSUM_INVALID
;
110 if (get_cmos_value(ce
->bit
, ce
->length
, dest
) != CB_SUCCESS
)
111 return CB_CMOS_ACCESS_ERROR
;
116 unsigned int get_uint_option(const char *name
, const unsigned int fallback
)
118 unsigned int value
= 0;
119 return cmos_get_uint_option(&value
, name
) == CB_SUCCESS
? value
: fallback
;
122 static enum cb_err
set_cmos_value(unsigned long bit
, unsigned long length
,
126 unsigned long byte
, byte_bit
;
128 unsigned char uchar
, mask
;
129 unsigned int chksum_update_needed
= 0;
132 byte
= bit
/ 8; /* find the byte where the data starts */
133 byte_bit
= bit
% 8; /* find the bit where the data starts */
134 if (length
<= 8) { /* one byte or less */
135 mask
= (1 << length
) - 1;
138 uchar
= cmos_read(byte
);
140 uchar
|= (ret
[0] << byte_bit
);
141 cmos_write(uchar
, byte
);
142 if (byte
>= LB_CKS_RANGE_START
&& byte
<= LB_CKS_RANGE_END
)
143 chksum_update_needed
= 1;
144 } else { /* more that one byte so transfer the whole bytes */
145 if (byte_bit
|| length
% 8)
148 for (i
= 0; length
; i
++, length
-= 8, byte
++) {
149 cmos_write(ret
[i
], byte
);
150 if (byte
>= LB_CKS_RANGE_START
&&
151 byte
<= LB_CKS_RANGE_END
)
152 chksum_update_needed
= 1;
156 if (chksum_update_needed
) {
157 cmos_set_checksum(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
,
163 static enum cb_err
cmos_set_uint_option(const char *name
, unsigned int *value
)
165 struct cmos_option_table
*ct
;
166 struct cmos_entries
*ce
;
168 ct
= get_cmos_layout();
170 return CB_CMOS_LAYOUT_NOT_FOUND
;
172 ce
= find_cmos_entry(ct
, name
);
174 printk(BIOS_DEBUG
, "WARNING: No CMOS option '%s'.\n", name
);
175 return CB_CMOS_OPTION_NOT_FOUND
;
178 if (ce
->config
!= 'e' && ce
->config
!= 'h') {
179 printk(BIOS_ERR
, "CMOS option '%s' is not of integer type.\n", name
);
183 if (set_cmos_value(ce
->bit
, ce
->length
, value
) != CB_SUCCESS
)
184 return CB_CMOS_ACCESS_ERROR
;
189 enum cb_err
set_uint_option(const char *name
, unsigned int value
)
191 return cmos_set_uint_option(name
, &value
);
194 int cmos_lb_cks_valid(void)
196 return cmos_checksum_valid(LB_CKS_RANGE_START
, LB_CKS_RANGE_END
, LB_CKS_LOC
);
199 void sanitize_cmos(void)
201 const unsigned char *cmos_default
;
202 const bool cmos_need_reset
=
203 CONFIG(STATIC_OPTION_TABLE
) || cmos_error() || !cmos_lb_cks_valid();
207 if (CONFIG(TPM_MEASURED_BOOT
) || cmos_need_reset
) {
208 cmos_default
= cbfs_map("cmos.default", &length
);
210 if (!cmos_default
|| !cmos_need_reset
)
213 u8 control_state
= cmos_disable_rtc();
214 for (i
= 14; i
< MIN(128, length
); i
++)
215 cmos_write_inner(cmos_default
[i
], i
);
216 cmos_restore_rtc(control_state
);