3 * Copyright (C) 2008 coresystems GmbH
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #define __STDC_FORMAT_MACROS
31 #include <libpayload.h>
32 #include <coreboot_tables.h>
35 u8
*mem_accessor_base
;
37 static u8
mem_read(u8 reg
)
39 return mem_accessor_base
[reg
];
42 static void mem_write(u8 val
, u8 reg
)
44 mem_accessor_base
[reg
] = val
;
47 struct nvram_accessor
*use_nvram
= &(struct nvram_accessor
) {
52 struct nvram_accessor
*use_mem
= &(struct nvram_accessor
) {
57 struct cb_cmos_option_table
*get_system_option_table(void)
59 return phys_to_virt(lib_sysinfo
.cmos_option_table
);
62 int options_checksum_valid(const struct nvram_accessor
*nvram
)
65 int range_start
= lib_sysinfo
.cmos_range_start
/ 8;
66 int range_end
= lib_sysinfo
.cmos_range_end
/ 8;
67 int checksum_location
= lib_sysinfo
.cmos_checksum_location
/ 8;
68 u16 checksum
= 0, checksum_old
;
70 for(i
= range_start
; i
<= range_end
; i
++) {
71 checksum
+= nvram
->read(i
);
74 checksum_old
= ((nvram
->read(checksum_location
)<<8) | nvram
->read(checksum_location
+1));
76 return (checksum_old
== checksum
);
79 void fix_options_checksum_with(const struct nvram_accessor
*nvram
)
82 int range_start
= lib_sysinfo
.cmos_range_start
/ 8;
83 int range_end
= lib_sysinfo
.cmos_range_end
/ 8;
84 int checksum_location
= lib_sysinfo
.cmos_checksum_location
/ 8;
87 for(i
= range_start
; i
<= range_end
; i
++) {
88 checksum
+= nvram
->read(i
);
91 nvram
->write((checksum
>> 8), checksum_location
);
92 nvram
->write((checksum
& 0xff), checksum_location
+ 1);
95 void fix_options_checksum(void)
97 fix_options_checksum_with(use_nvram
);
100 static int get_cmos_value(const struct nvram_accessor
*nvram
, u32 bitnum
, u32 len
, void *valptr
)
107 /* Convert to byte borders */
111 /* Handle single byte or less */
113 reg8
= nvram
->read(addr
);
115 value
[0] = reg8
& ((1 << len
) -1);
119 /* When handling more than a byte, copy whole bytes */
122 value
[offs
++]=nvram
->read(addr
++);
128 static int set_cmos_value(const struct nvram_accessor
*nvram
, u32 bitnum
, u32 len
, const void *valptr
)
130 const u8
*value
= valptr
;
135 /* Convert to byte borders */
139 /* Handle single byte or less */
141 reg8
= nvram
->read(addr
);
142 reg8
&= ~(((1 << len
) - 1) << bit
);
143 reg8
|= (value
[0] & ((1 << len
) - 1)) << bit
;
144 nvram
->write(reg8
, addr
);
148 /* When handling more than a byte, copy whole bytes */
151 nvram
->write(value
[offs
++], addr
++);
157 static struct cb_cmos_entries
*lookup_cmos_entry(struct cb_cmos_option_table
*option_table
, const char *name
)
159 struct cb_cmos_entries
*cmos_entry
;
160 int len
= name
? strnlen(name
, CB_CMOS_MAX_NAME_LENGTH
) : 0;
162 /* CMOS entries are located right after the option table */
163 cmos_entry
= first_cmos_entry(option_table
);
165 if (memcmp((const char*)cmos_entry
->name
, name
, len
) == 0)
167 cmos_entry
= next_cmos_entry(cmos_entry
);
170 printf("ERROR: No such CMOS option (%s)\n", name
);
174 struct cb_cmos_entries
*first_cmos_entry(struct cb_cmos_option_table
*option_table
)
176 return (struct cb_cmos_entries
*)((unsigned char *)option_table
+ option_table
->header_length
);
179 struct cb_cmos_entries
*next_cmos_entry(struct cb_cmos_entries
*cmos_entry
)
181 struct cb_cmos_entries
*next
= (struct cb_cmos_entries
*)((unsigned char *)cmos_entry
+ cmos_entry
->size
);
182 if (next
->tag
== CB_TAG_OPTION
)
188 struct cb_cmos_enums
*first_cmos_enum(struct cb_cmos_option_table
*option_table
)
190 struct cb_cmos_entries
*cmos_entry
;
191 /* CMOS entries are located right after the option table. Skip them */
192 cmos_entry
= (struct cb_cmos_entries
*)((unsigned char *)option_table
+ option_table
->header_length
);
193 while (cmos_entry
->tag
== CB_TAG_OPTION
)
194 cmos_entry
= (struct cb_cmos_entries
*)((unsigned char *)cmos_entry
+ cmos_entry
->size
);
196 /* CMOS enums are located after CMOS entries. */
197 return (struct cb_cmos_enums
*)cmos_entry
;
200 struct cb_cmos_enums
*next_cmos_enum(struct cb_cmos_enums
*cmos_enum
)
206 cmos_enum
= (struct cb_cmos_enums
*)((unsigned char *)cmos_enum
+ cmos_enum
->size
);
207 if (cmos_enum
->tag
== CB_TAG_OPTION_ENUM
) {
214 struct cb_cmos_enums
*next_cmos_enum_of_id(struct cb_cmos_enums
*cmos_enum
, int id
)
216 while ((cmos_enum
= next_cmos_enum(cmos_enum
))) {
217 if (cmos_enum
->config_id
== id
) {
224 struct cb_cmos_enums
*first_cmos_enum_of_id(struct cb_cmos_option_table
*option_table
, int id
)
226 struct cb_cmos_enums
*cmos_enum
= first_cmos_enum(option_table
);
230 if (cmos_enum
->config_id
== id
) {
234 return next_cmos_enum_of_id(cmos_enum
, id
);
237 /* Either value or text must be NULL. Returns the field that matches "the other" for a given config_id */
238 static struct cb_cmos_enums
*lookup_cmos_enum_core(struct cb_cmos_option_table
*option_table
, int config_id
, const u8
*value
, const char *text
)
240 int len
= strnlen(text
, CB_CMOS_MAX_TEXT_LENGTH
);
242 /* CMOS enums are located after CMOS entries. */
243 struct cb_cmos_enums
*cmos_enum
;
244 for ( cmos_enum
= first_cmos_enum_of_id(option_table
, config_id
);
246 cmos_enum
= next_cmos_enum_of_id(cmos_enum
, config_id
)) {
247 if (((value
== NULL
) || (cmos_enum
->value
== *value
)) &&
248 ((text
== NULL
) || (memcmp((const char*)cmos_enum
->text
, text
, len
) == 0))) {
256 static struct cb_cmos_enums
*lookup_cmos_enum_by_value(struct cb_cmos_option_table
*option_table
, int config_id
, const u8
*value
)
258 return lookup_cmos_enum_core(option_table
, config_id
, value
, NULL
);
261 static struct cb_cmos_enums
*lookup_cmos_enum_by_label(struct cb_cmos_option_table
*option_table
, int config_id
, const char *label
)
263 return lookup_cmos_enum_core(option_table
, config_id
, NULL
, label
);
266 int get_option_with(const struct nvram_accessor
*nvram
, struct cb_cmos_option_table
*option_table
, void *dest
, const char *name
)
268 struct cb_cmos_entries
*cmos_entry
= lookup_cmos_entry(option_table
, name
);
270 if(get_cmos_value(nvram
, cmos_entry
->bit
, cmos_entry
->length
, dest
))
273 if(!options_checksum_valid(nvram
))
281 int get_option_from(struct cb_cmos_option_table
*option_table
, void *dest
, const char *name
)
283 return get_option_with(use_nvram
, option_table
, dest
, name
);
286 int get_option(void *dest
, const char *name
)
288 return get_option_from(get_system_option_table(), dest
, name
);
291 int set_option_with(const struct nvram_accessor
*nvram
, struct cb_cmos_option_table
*option_table
, const void *value
, const char *name
)
293 struct cb_cmos_entries
*cmos_entry
= lookup_cmos_entry(option_table
, name
);
295 set_cmos_value(nvram
, cmos_entry
->bit
, cmos_entry
->length
, value
);
296 fix_options_checksum_with(nvram
);
302 int set_option(const void *value
, const char *name
)
304 return set_option_with(use_nvram
, get_system_option_table(), value
, name
);
307 int get_option_as_string(const struct nvram_accessor
*nvram
, struct cb_cmos_option_table
*option_table
, char **dest
, const char *name
)
310 struct cb_cmos_entries
*cmos_entry
= lookup_cmos_entry(option_table
, name
);
313 int cmos_length
= (cmos_entry
->length
+7)/8;
315 /* ensure we have enough space for u64 */
319 /* extra byte to ensure 0-terminated strings */
320 raw
= malloc(cmos_length
+1);
321 memset(raw
, 0, cmos_length
+1);
323 int ret
= get_option_with(nvram
, option_table
, raw
, name
);
325 struct cb_cmos_enums
*cmos_enum
;
326 switch (cmos_entry
->config
) {
328 /* only works on little endian.
329 26 bytes is enough for a 64bit value in decimal */
331 sprintf(*dest
, "%" PRIu64
, *(u64
*)raw
);
337 cmos_enum
= lookup_cmos_enum_by_value(option_table
, cmos_entry
->config_id
, (u8
*)raw
);
338 *dest
= strdup((const char*)cmos_enum
->text
);
347 int set_option_from_string(const struct nvram_accessor
*nvram
, struct cb_cmos_option_table
*option_table
, const char *value
, const char *name
)
350 struct cb_cmos_entries
*cmos_entry
= lookup_cmos_entry(option_table
, name
);
354 struct cb_cmos_enums
*cmos_enum
;
355 switch (cmos_entry
->config
) {
357 /* only works on little endian */
358 raw
= malloc(sizeof(u64
));
359 *(u64
*)raw
= strtoull(value
, NULL
, 0);
362 raw
= malloc(cmos_entry
->length
);
365 memset(raw
, 0x00, cmos_entry
->length
);
366 strncpy(raw
, value
, cmos_entry
->length
);
369 cmos_enum
= lookup_cmos_enum_by_label(option_table
, cmos_entry
->config_id
, value
);
370 raw
= malloc(sizeof(u32
));
371 *(u32
*)raw
= cmos_enum
->value
;
377 int ret
= set_option_with(nvram
, option_table
, raw
, name
);