Rename lxbios to nvramtool, step 3 (rename directory).
[coreboot.git] / util / nvramtool / cmos_lowlevel.c
1 /*****************************************************************************\
2  * cmos_lowlevel.c
3  * $Id$
4  *****************************************************************************
5  *  Copyright (C) 2002-2005 The Regents of the University of California.
6  *  Produced at the Lawrence Livermore National Laboratory.
7  *  Written by David S. Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>.
8  *  UCRL-CODE-2003-012
9  *  All rights reserved.
10  *
11  *  This file is part of nvramtool, a utility for reading/writing coreboot
12  *  parameters and displaying information from the coreboot table.
13  *  For details, see http://coreboot.org/nvramtool.
14  *
15  *  Please also read the file DISCLAIMER which is included in this software
16  *  distribution.
17  *
18  *  This program is free software; you can redistribute it and/or modify it
19  *  under the terms of the GNU General Public License (as published by the
20  *  Free Software Foundation) version 2, dated June 1991.
21  *
22  *  This program is distributed in the hope that it will be useful, but
23  *  WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
24  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the terms and
25  *  conditions of the GNU General Public License for more details.
26  *
27  *  You should have received a copy of the GNU General Public License along
28  *  with this program; if not, write to the Free Software Foundation, Inc.,
29  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
30 \*****************************************************************************/
31
32 #include <sys/io.h>
33 #include "common.h"
34 #include "cmos_lowlevel.h"
35
36 typedef struct
37  { unsigned byte_index;
38    unsigned bit_offset;
39  }
40 cmos_bit_op_location_t;
41
42 static unsigned cmos_bit_op_strategy (unsigned bit, unsigned bits_left,
43                                       cmos_bit_op_location_t *where);
44 static unsigned char cmos_read_bits (const cmos_bit_op_location_t *where,
45                                      unsigned nr_bits);
46 static void cmos_write_bits (const cmos_bit_op_location_t *where,
47                              unsigned nr_bits, unsigned char value);
48 static unsigned char get_bits (unsigned long long value, unsigned bit,
49                                unsigned nr_bits);
50 static void put_bits (unsigned char value, unsigned bit, unsigned nr_bits,
51                       unsigned long long *result);
52
53 /****************************************************************************
54  * get_bits
55  *
56  * Extract a value 'nr_bits' bits wide starting at bit position 'bit' from
57  * 'value' and return the result.  It is assumed that 'nr_bits' is at most 8.
58  ****************************************************************************/
59 static inline unsigned char get_bits (unsigned long long value, unsigned bit,
60                                       unsigned nr_bits)
61  { return (value >> bit) & ((unsigned char) ((1 << nr_bits) - 1)); }
62
63 /****************************************************************************
64  * put_bits
65  *
66  * Extract the low order 'nr_bits' bits from 'value' and store them in the
67  * value pointed to by 'result' starting at bit position 'bit'.  The bit
68  * positions in 'result' where the result is stored are assumed to be
69  * initially zero.
70  ****************************************************************************/
71 static inline void put_bits (unsigned char value, unsigned bit,
72                              unsigned nr_bits, unsigned long long *result)
73  { *result += (value & ((unsigned char) ((1 << nr_bits) - 1))) << bit; }
74
75 /****************************************************************************
76  * cmos_read
77  *
78  * Read value from nonvolatile RAM at position given by 'bit' and 'length'
79  * and return this value.  The I/O privilege level of the currently executing
80  * process must be set appropriately.
81  ****************************************************************************/
82 unsigned long long cmos_read (unsigned bit, unsigned length)
83  { cmos_bit_op_location_t where;
84    unsigned next_bit, bits_left, nr_bits;
85    unsigned long long result;
86    unsigned char value;
87
88    assert(!verify_cmos_op(bit, length));
89    result = 0;
90
91    for (next_bit = 0, bits_left = length;
92         bits_left;
93         next_bit += nr_bits, bits_left -= nr_bits)
94     { nr_bits = cmos_bit_op_strategy(bit + next_bit, bits_left, &where);
95       value = cmos_read_bits(&where, nr_bits);
96       put_bits(value, next_bit, nr_bits, &result);
97     }
98
99    return result;
100  }
101
102 /****************************************************************************
103  * cmos_write
104  *
105  * Write 'data' to nonvolatile RAM at position given by 'bit' and 'length'.
106  * The I/O privilege level of the currently executing process must be set
107  * appropriately.
108  ****************************************************************************/
109 void cmos_write (unsigned bit, unsigned length, unsigned long long value)
110  { cmos_bit_op_location_t where;
111    unsigned next_bit, bits_left, nr_bits;
112
113    assert(!verify_cmos_op(bit, length));
114
115    for (next_bit = 0, bits_left = length;
116         bits_left;
117         next_bit += nr_bits, bits_left -= nr_bits)
118     { nr_bits = cmos_bit_op_strategy(bit + next_bit, bits_left, &where);
119       cmos_write_bits(&where, nr_bits, get_bits(value, next_bit, nr_bits));
120     }
121  }
122
123 /****************************************************************************
124  * cmos_read_byte
125  *
126  * Read a byte from nonvolatile RAM at a position given by 'index' and return
127  * the result.  An 'index' value of 0 represents the first byte of
128  * nonvolatile RAM.
129  *
130  * Note: the first 14 bytes of nonvolatile RAM provide an interface to the
131  *       real time clock.
132  ****************************************************************************/
133 unsigned char cmos_read_byte (unsigned index)
134  { unsigned short port_0, port_1;
135
136    assert(!verify_cmos_byte_index(index));
137
138    if (index < 128)
139     { port_0 = 0x70;
140       port_1 = 0x71;
141     }
142    else
143     { port_0 = 0x72;
144       port_1 = 0x73;
145     }
146
147    outb(index, port_0);
148    return inb(port_1);
149  }
150
151 /****************************************************************************
152  * cmos_write_byte
153  *
154  * Write 'value' to nonvolatile RAM at a position given by 'index'.  An
155  * 'index' of 0 represents the first byte of nonvolatile RAM.
156  *
157  * Note: the first 14 bytes of nonvolatile RAM provide an interface to the
158  *       real time clock.  Writing to any of these bytes will therefore
159  *       affect its functioning.
160  ****************************************************************************/
161 void cmos_write_byte (unsigned index, unsigned char value)
162  { unsigned short port_0, port_1;
163
164    assert(!verify_cmos_byte_index(index));
165
166    if (index < 128)
167     { port_0 = 0x70;
168       port_1 = 0x71;
169     }
170    else
171     { port_0 = 0x72;
172       port_1 = 0x73;
173     }
174
175    outb(index, port_0);
176    outb(value, port_1);
177  }
178
179 /****************************************************************************
180  * cmos_read_all
181  *
182  * Read all contents of CMOS memory into array 'data'.  The first 14 bytes of
183  * 'data' are set to zero since this corresponds to the real time clock area.
184  ****************************************************************************/
185 void cmos_read_all (unsigned char data[])
186  { unsigned i;
187
188    for (i = 0; i < CMOS_RTC_AREA_SIZE; i++)
189       data[i] = 0;
190
191    for (; i < CMOS_SIZE; i++)
192       data[i] = cmos_read_byte(i);
193  }
194
195 /****************************************************************************
196  * cmos_write_all
197  *
198  * Update all of CMOS memory with the contents of array 'data'.  The first 14
199  * bytes of 'data' are ignored since this corresponds to the real time clock
200  * area.
201  ****************************************************************************/
202 void cmos_write_all (unsigned char data[])
203  { unsigned i;
204
205    for (i = CMOS_RTC_AREA_SIZE; i < CMOS_SIZE; i++)
206       cmos_write_byte(i, data[i]);
207  }
208
209 /****************************************************************************
210  * set_iopl
211  *
212  * Set the I/O privilege level of the executing process.  Root privileges are
213  * required for performing this action.  A sufficient I/O privilege level
214  * allows the process to access x86 I/O address space and to disable/reenable
215  * interrupts while executing in user space.  Messing with the I/O privilege
216  * level is therefore somewhat dangerous.
217  ****************************************************************************/
218 void set_iopl (int level)
219  { assert((level >= 0) && (level <= 3));
220
221    if (iopl(level))
222     { fprintf(stderr,
223               "%s: iopl() system call failed.  You must be root to do "
224               "this.\n",
225               prog_name);
226       exit(1);
227     }
228  }
229
230 /****************************************************************************
231  * verify_cmos_op
232  *
233  * 'bit' represents a bit position in the nonvolatile RAM.  The first bit
234  * (i.e. the lowest order bit of the first byte) of nonvolatile RAM is
235  * labeled as bit 0.  'length' represents the width in bits of a value we
236  * wish to read or write.  Perform sanity checking on 'bit' and 'length'.  If
237  * no problems were encountered, return OK.  Else return an error code.
238  ****************************************************************************/
239 int verify_cmos_op (unsigned bit, unsigned length)
240  { if ((bit >= (8 * CMOS_SIZE)) || ((bit + length) > (8 * CMOS_SIZE)))
241       return CMOS_AREA_OUT_OF_RANGE;
242
243    if (bit < (8 * CMOS_RTC_AREA_SIZE))
244       return CMOS_AREA_OVERLAPS_RTC;
245
246    if (length > (8 * sizeof(unsigned long long)))
247       return CMOS_AREA_TOO_WIDE;
248
249    return OK;
250  }
251
252 /****************************************************************************
253  * cmos_bit_op_strategy
254  *
255  * Helper function used by cmos_read() and cmos_write() to determine which
256  * bits to read or write next.
257  ****************************************************************************/
258 static unsigned cmos_bit_op_strategy (unsigned bit, unsigned bits_left,
259                                       cmos_bit_op_location_t *where)
260  { unsigned max_bits;
261
262    where->byte_index = bit >> 3;
263    where->bit_offset = bit & 0x07;
264    max_bits = 8 - where->bit_offset;
265    return (bits_left > max_bits) ? max_bits : bits_left;
266  }
267
268 /****************************************************************************
269  * cmos_read_bits
270  *
271  * Read a chunk of bits from a byte location within CMOS memory.  Return the
272  * value represented by the chunk of bits.
273  ****************************************************************************/
274 static unsigned char cmos_read_bits (const cmos_bit_op_location_t *where,
275                                      unsigned nr_bits)
276  { return (cmos_read_byte(where->byte_index) >> where->bit_offset) &
277           ((unsigned char) ((1 << nr_bits) - 1));
278  }
279
280 /****************************************************************************
281  * cmos_write_bits
282  *
283  * Write a chunk of bits (the low order 'nr_bits' bits of 'value') to an area
284  * within a particular byte of CMOS memory.
285  ****************************************************************************/
286 static void cmos_write_bits (const cmos_bit_op_location_t *where,
287                              unsigned nr_bits, unsigned char value)
288  { unsigned char n, mask;
289
290    if (nr_bits == 8)
291     { cmos_write_byte(where->byte_index, value);
292       return;
293     }
294
295    n = cmos_read_byte(where->byte_index);
296    mask = ((unsigned char) ((1 << nr_bits) - 1)) << where->bit_offset;
297    n = (n & ~mask) + ((value << where->bit_offset) & mask);
298    cmos_write_byte(where->byte_index, n);
299  }