blob: 241dd19c6dcf602728ee50fef42b0ff76458f682 [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * layout.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003 *****************************************************************************
4 * Copyright (C) 2002-2005 The Regents of the University of California.
5 * Produced at the Lawrence Livermore National Laboratory.
6 * Written by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
7 * UCRL-CODE-2003-012
8 * All rights reserved.
9 *
Uwe Hermann6e565942008-03-01 19:06:32 +000010 * This file is part of nvramtool, a utility for reading/writing coreboot
Stefan Reinauerf527e702008-01-18 15:33:49 +000011 * parameters and displaying information from the coreboot table.
Uwe Hermann6e565942008-03-01 19:06:32 +000012 * For details, see http://coreboot.org/nvramtool.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000013 *
14 * Please also read the file DISCLAIMER which is included in this software
15 * distribution.
16 *
17 * This program is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License (as published by the
19 * Free Software Foundation) version 2, dated June 1991.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
24 * conditions of the GNU General Public License for more details.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000025\*****************************************************************************/
26
27#include "common.h"
28#include "layout.h"
29#include "cmos_lowlevel.h"
30
31typedef struct cmos_entry_item_t cmos_entry_item_t;
32
Stefan Reinauer90b96b62010-01-13 21:00:23 +000033struct cmos_entry_item_t {
34 cmos_entry_t item;
35 cmos_entry_item_t *next;
36};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000037
38typedef struct cmos_enum_item_t cmos_enum_item_t;
39
Stefan Reinauer90b96b62010-01-13 21:00:23 +000040struct cmos_enum_item_t {
41 cmos_enum_t item;
42 cmos_enum_item_t *next;
43};
Stefan Reinauer6540ae52007-07-12 16:35:42 +000044
Stefan Reinauer90b96b62010-01-13 21:00:23 +000045static void default_cmos_layout_get_fn(void);
46static int areas_overlap(unsigned area_0_start, unsigned area_0_length,
47 unsigned area_1_start, unsigned area_1_length);
48static int entries_overlap(const cmos_entry_t * p, const cmos_entry_t * q);
49static const cmos_enum_item_t *find_first_cmos_enum_id(unsigned config_id);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000050
51const char checksum_param_name[] = "check_sum";
52
Stefan Reinauerf527e702008-01-18 15:33:49 +000053/* Newer versions of coreboot store the 3 pieces of information below in the
54 * coreboot table so we don't have to rely on hardcoded values.
Stefan Reinauer6540ae52007-07-12 16:35:42 +000055 */
56
57/* This is the offset from the start of CMOS of the first byte that the
58 * checksum is calculated over.
59 */
60#define CMOS_CHECKSUM_START 49
61
62/* This is the offset from the start of CMOS of the last byte that the
63 * checksum is calculated over.
64 */
65#define CMOS_CHECKSUM_END 125
66
Stefan Reinauerf527e702008-01-18 15:33:49 +000067/* This is the offset from the start of CMOS where the coreboot checksum is
Stefan Reinauer6540ae52007-07-12 16:35:42 +000068 * stored.
69 */
70#define CMOS_CHECKSUM_INDEX 126
71
72/* index of first byte of checksummed area */
73unsigned cmos_checksum_start = CMOS_CHECKSUM_START;
74
75/* index of last byte of checksummed area */
76unsigned cmos_checksum_end = CMOS_CHECKSUM_END;
77
78/* index of first byte of CMOS checksum (a big-endian 16-bit value) */
79unsigned cmos_checksum_index = CMOS_CHECKSUM_INDEX;
80
81/* List is sorted in ascending order according to 'bit' field in
82 * cmos_entry_t.
83 */
84static cmos_entry_item_t *cmos_entry_list = NULL;
85
86/* List is sorted in ascending order: first by 'config_id' and then by
87 * 'value'.
88 */
89static cmos_enum_item_t *cmos_enum_list = NULL;
90
91static cmos_layout_get_fn_t cmos_layout_get_fn = default_cmos_layout_get_fn;
92
93/****************************************************************************
94 * entries_overlap
95 *
96 * Return 1 if cmos entries 'p' and 'q' overlap. Else return 0.
97 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000098static inline int entries_overlap(const cmos_entry_t * p,
99 const cmos_entry_t * q)
100{
101 return areas_overlap(p->bit, p->length, q->bit, q->length);
102}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000103
104/****************************************************************************
105 * cmos_entry_to_const_item
106 *
107 * Return a pointer to the cmos_entry_item_t that 'p' is embedded within.
108 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000109static inline const cmos_entry_item_t *cmos_entry_to_const_item
110 (const cmos_entry_t * p) {
111 static const cmos_entry_t *pos = &((cmos_entry_item_t *) 0)->item;
112 unsigned long offset, address;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000113
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000114 offset = (unsigned long)pos;
115 address = ((unsigned long)p) - offset;
116 return (const cmos_entry_item_t *)address;
117}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000118
119/****************************************************************************
120 * cmos_enum_to_const_item
121 *
122 * Return a pointer to the cmos_enum_item_t that 'p' is embedded within.
123 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000124static inline const cmos_enum_item_t *cmos_enum_to_const_item
125 (const cmos_enum_t * p) {
126 static const cmos_enum_t *pos = &((cmos_enum_item_t *) 0)->item;
127 unsigned long offset, address;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000128
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000129 offset = (unsigned long)pos;
130 address = ((unsigned long)p) - offset;
131 return (const cmos_enum_item_t *)address;
132}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000133
134/****************************************************************************
135 * register_cmos_layout_get_fn
136 *
137 * Set 'fn' as the function that will be called to retrieve CMOS layout
138 * information.
139 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000140void register_cmos_layout_get_fn(cmos_layout_get_fn_t fn)
141{
142 cmos_layout_get_fn = fn;
143}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000144
145/****************************************************************************
146 * get_cmos_layout
147 *
148 * Retrieve CMOS layout information and store it in our internal repository.
149 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000150void get_cmos_layout(void)
151{
152 cmos_layout_get_fn();
153}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000154
155/****************************************************************************
156 * add_cmos_entry
157 *
158 * Attempt to add CMOS entry 'e' to our internal repository of layout
159 * information. Return OK on success or an error code on failure. If
160 * operation fails because 'e' overlaps an existing CMOS entry, '*conflict'
161 * will be set to point to the overlapping entry.
162 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000163int add_cmos_entry(const cmos_entry_t * e, const cmos_entry_t ** conflict)
164{
165 cmos_entry_item_t *item, *prev, *new_entry;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000166
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000167 *conflict = NULL;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000168
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000169 if (e->length < 1)
170 return LAYOUT_ENTRY_BAD_LENGTH;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000171
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000172 if ((new_entry =
173 (cmos_entry_item_t *) malloc(sizeof(*new_entry))) == NULL)
174 out_of_memory();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000175
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000176 new_entry->item = *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000177
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000178 if (cmos_entry_list == NULL) {
179 new_entry->next = NULL;
180 cmos_entry_list = new_entry;
181 return OK;
182 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000183
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000184 /* Find place in list to insert new entry. List is sorted in ascending
185 * order.
186 */
187 for (item = cmos_entry_list, prev = NULL;
188 (item != NULL) && (item->item.bit < e->bit);
189 prev = item, item = item->next) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000190
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000191 if (prev == NULL) {
192 if (entries_overlap(e, &cmos_entry_list->item)) {
193 *conflict = &cmos_entry_list->item;
194 goto fail;
195 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000196
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000197 new_entry->next = cmos_entry_list;
198 cmos_entry_list = new_entry;
199 return OK;
200 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000201
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000202 if (entries_overlap(&prev->item, e)) {
203 *conflict = &prev->item;
204 goto fail;
205 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000206
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000207 if ((item != NULL) && entries_overlap(e, &item->item)) {
208 *conflict = &item->item;
209 goto fail;
210 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000211
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000212 new_entry->next = item;
213 prev->next = new_entry;
214 return OK;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000215
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000216 fail:
217 free(new_entry);
218 return LAYOUT_ENTRY_OVERLAP;
219}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000220
221/****************************************************************************
222 * find_cmos_entry
223 *
224 * Search for a CMOS entry whose name is 'name'. Return pointer to matching
225 * entry or NULL if entry not found.
226 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000227const cmos_entry_t *find_cmos_entry(const char name[])
228{
229 cmos_entry_item_t *item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000230
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000231 for (item = cmos_entry_list; item != NULL; item = item->next) {
232 if (!strcmp(item->item.name, name))
233 return &item->item;
234 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000235
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000236 return NULL;
237}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000238
239/****************************************************************************
240 * first_cmos_entry
241 *
242 * Return a pointer to the first CMOS entry in our list or NULL if list is
243 * empty.
244 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000245const cmos_entry_t *first_cmos_entry(void)
246{
247 return (cmos_entry_list == NULL) ? NULL : &cmos_entry_list->item;
248}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000249
250/****************************************************************************
251 * next_cmos_entry
252 *
253 * Return a pointer to next entry in list after 'last' or NULL if no more
254 * entries.
255 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000256const cmos_entry_t *next_cmos_entry(const cmos_entry_t * last)
257{
258 const cmos_entry_item_t *last_item, *next_item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000259
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000260 last_item = cmos_entry_to_const_item(last);
261 next_item = last_item->next;
262 return (next_item == NULL) ? NULL : &next_item->item;
263}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000264
265/****************************************************************************
266 * add_cmos_enum
267 *
268 * Attempt to add CMOS enum 'e' to our internal repository of layout
269 * information. Return OK on success or an error code on failure.
270 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000271int add_cmos_enum(const cmos_enum_t * e)
272{
273 cmos_enum_item_t *item, *prev, *new_enum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000274
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000275 if ((new_enum = (cmos_enum_item_t *) malloc(sizeof(*new_enum))) == NULL)
276 out_of_memory();
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000277
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000278 new_enum->item = *e;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000279
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000280 if (cmos_enum_list == NULL) {
281 new_enum->next = NULL;
282 cmos_enum_list = new_enum;
283 return OK;
284 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000285
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000286 /* The list of enums is sorted in ascending order, first by
287 * 'config_id' and then by 'value'. Look for the first enum
288 * whose 'config_id' field matches 'e'.
289 */
290 for (item = cmos_enum_list, prev = NULL;
291 (item != NULL) && (item->item.config_id < e->config_id);
292 prev = item, item = item->next) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000293
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000294 if (item == NULL) {
295 new_enum->next = NULL;
296 prev->next = new_enum;
297 return OK;
298 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000299
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000300 if (item->item.config_id > e->config_id) {
301 new_enum->next = item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000302
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000303 if (prev == NULL)
304 cmos_enum_list = new_enum;
305 else
306 prev->next = new_enum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000307
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000308 return OK;
309 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000310
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000311 /* List already contains at least one enum whose 'config_id'
312 * matches 'e'. Now find proper place to insert 'e' based on
313 * 'value'.
314 */
315 while (item->item.value < e->value) {
316 prev = item;
317 item = item->next;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000318
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000319 if ((item == NULL) || (item->item.config_id != e->config_id)) {
320 new_enum->next = item;
321 prev->next = new_enum;
322 return OK;
323 }
324 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000325
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000326 if (item->item.value == e->value) {
327 free(new_enum);
328 return LAYOUT_DUPLICATE_ENUM;
329 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000330
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000331 new_enum->next = item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000332
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000333 if (prev == NULL)
334 cmos_enum_list = new_enum;
335 else
336 prev->next = new_enum;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000337
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000338 return OK;
339}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000340
341/****************************************************************************
342 * find_cmos_enum
343 *
344 * Search for an enum that matches 'config_id' and 'value'. If found, return
345 * a pointer to the mathcing enum. Else return NULL.
346 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000347const cmos_enum_t *find_cmos_enum(unsigned config_id, unsigned long long value)
348{
349 const cmos_enum_item_t *item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000350
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000351 if ((item = find_first_cmos_enum_id(config_id)) == NULL)
352 return NULL;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000353
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000354 while (item->item.value < value) {
355 item = item->next;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000356
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000357 if ((item == NULL) || (item->item.config_id != config_id))
358 return NULL;
359 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000360
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000361 return (item->item.value == value) ? &item->item : NULL;
362}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000363
364/****************************************************************************
365 * first_cmos_enum
366 *
367 * Return a pointer to the first CMOS enum in our list or NULL if list is
368 * empty.
369 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000370const cmos_enum_t *first_cmos_enum(void)
371{
372 return (cmos_enum_list == NULL) ? NULL : &cmos_enum_list->item;
373}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000374
375/****************************************************************************
376 * next_cmos_enum
377 *
378 * Return a pointer to next enum in list after 'last' or NULL if no more
379 * enums.
380 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000381const cmos_enum_t *next_cmos_enum(const cmos_enum_t * last)
382{
383 const cmos_enum_item_t *last_item, *next_item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000384
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000385 last_item = cmos_enum_to_const_item(last);
386 next_item = last_item->next;
387 return (next_item == NULL) ? NULL : &next_item->item;
388}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000389
390/****************************************************************************
391 * first_cmos_enum_id
392 *
393 * Return a pointer to the first CMOS enum in our list that matches
394 * 'config_id' or NULL if there are no matching enums.
395 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000396const cmos_enum_t *first_cmos_enum_id(unsigned config_id)
397{
398 const cmos_enum_item_t *item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000399
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000400 item = find_first_cmos_enum_id(config_id);
401 return (item == NULL) ? NULL : &item->item;
402}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000403
404/****************************************************************************
405 * next_cmos_enum_id
406 *
407 * Return a pointer to next enum in list after 'last' that matches the
408 * 'config_id' field of 'last' or NULL if there are no more matching enums.
409 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000410const cmos_enum_t *next_cmos_enum_id(const cmos_enum_t * last)
411{
412 const cmos_enum_item_t *item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000413
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000414 item = cmos_enum_to_const_item(last)->next;
415 return ((item == NULL) || (item->item.config_id != last->config_id)) ?
416 NULL : &item->item;
417}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000418
419/****************************************************************************
420 * is_checksum_name
421 *
422 * Return 1 if 'name' matches the name of the parameter representing the CMOS
423 * checksum. Else return 0.
424 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000425int is_checksum_name(const char name[])
426{
427 return !strcmp(name, checksum_param_name);
428}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000429
430/****************************************************************************
431 * checksum_layout_to_bytes
432 *
433 * On entry, '*layout' contains checksum-related layout information expressed
434 * in bits. Perform sanity checking on the information and convert it from
435 * bit positions to byte positions. Return OK on success or an error code if
436 * a sanity check fails.
437 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000438int checksum_layout_to_bytes(cmos_checksum_layout_t * layout)
439{
440 unsigned start, end, index;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000441
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000442 start = layout->summed_area_start;
443 end = layout->summed_area_end;
444 index = layout->checksum_at;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000445
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000446 if (start % 8)
447 return LAYOUT_SUMMED_AREA_START_NOT_ALIGNED;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000448
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000449 if ((end % 8) != 7)
450 return LAYOUT_SUMMED_AREA_END_NOT_ALIGNED;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000451
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000452 if (index % 8)
453 return LAYOUT_CHECKSUM_LOCATION_NOT_ALIGNED;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000454
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000455 if (end <= start)
456 return LAYOUT_INVALID_SUMMED_AREA;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000457
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000458 /* Convert bit positions to byte positions. */
459 start /= 8;
460 end /= 8; /* equivalent to "end = ((end - 7) / 8)" */
461 index /= 8;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000462
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000463 if (verify_cmos_byte_index(start) || verify_cmos_byte_index(end))
464 return LAYOUT_SUMMED_AREA_OUT_OF_RANGE;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000465
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000466 if (verify_cmos_byte_index(index))
467 return LAYOUT_CHECKSUM_LOCATION_OUT_OF_RANGE;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000468
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000469 /* checksum occupies 16 bits */
470 if (areas_overlap(start, end - start + 1, index, index + 1))
471 return LAYOUT_CHECKSUM_OVERLAPS_SUMMED_AREA;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000472
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000473 layout->summed_area_start = start;
474 layout->summed_area_end = end;
475 layout->checksum_at = index;
476 return OK;
477}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000478
479/****************************************************************************
480 * checksum_layout_to_bits
481 *
482 * On entry, '*layout' contains checksum-related layout information expressed
483 * in bytes. Convert this information to bit positions.
484 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000485void checksum_layout_to_bits(cmos_checksum_layout_t * layout)
486{
487 layout->summed_area_start *= 8;
488 layout->summed_area_end = (layout->summed_area_end * 8) + 7;
489 layout->checksum_at *= 8;
490}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000491
492/****************************************************************************
493 * default_cmos_layout_get_fn
494 *
495 * If this function is ever called, it means that an appropriate callback for
496 * obtaining CMOS layout information was not set before attempting to
497 * retrieve layout information.
498 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000499static void default_cmos_layout_get_fn(void)
500{
501 BUG();
502}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000503
504/****************************************************************************
505 * areas_overlap
506 *
507 * Return 1 if the two given areas overlap. Else return 0.
508 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000509static int areas_overlap(unsigned area_0_start, unsigned area_0_length,
510 unsigned area_1_start, unsigned area_1_length)
511{
512 unsigned area_0_end, area_1_end;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000513
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000514 area_0_end = area_0_start + area_0_length - 1;
515 area_1_end = area_1_start + area_1_length - 1;
516 return ((area_1_start <= area_0_end) && (area_0_start <= area_1_end));
517}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000518
519/****************************************************************************
520 * find_first_cmos_enum_id
521 *
522 * Return a pointer to the first item in our list of enums that matches
523 * 'config_id'. Return NULL if there is no matching enum.
524 ****************************************************************************/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000525static const cmos_enum_item_t *find_first_cmos_enum_id(unsigned config_id)
526{
527 cmos_enum_item_t *item;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000528
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000529 for (item = cmos_enum_list;
530 (item != NULL) && (item->item.config_id < config_id);
531 item = item->next) ;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000532
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000533 return ((item == NULL) || (item->item.config_id > config_id)) ?
534 NULL : item;
535}