4 * Open Hack'Ware BIOS NVRAM management routines.
6 * Copyright (c) 2004-2005 Jocelyn Mayer
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #define NVRAM_MAX_SIZE 0x2000
27 #define NVRAM_IO_BASE 0x0074
35 static void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
37 NVRAM_write(nvram, addr, value);
40 static uint8_t NVRAM_get_byte (nvram_t *nvram, uint16_t addr)
42 return NVRAM_read(nvram, addr);
45 static void NVRAM_set_word (nvram_t *nvram, uint16_t addr, uint16_t value)
47 NVRAM_write(nvram, addr, value >> 8);
48 NVRAM_write(nvram, addr + 1, value);
51 static uint16_t NVRAM_get_word (nvram_t *nvram, uint16_t addr)
55 tmp = NVRAM_read(nvram, addr) << 8;
56 tmp |= NVRAM_read(nvram, addr + 1);
61 static void NVRAM_set_lword (nvram_t *nvram, uint16_t addr, uint32_t value)
63 NVRAM_write(nvram, addr, value >> 24);
64 NVRAM_write(nvram, addr + 1, value >> 16);
65 NVRAM_write(nvram, addr + 2, value >> 8);
66 NVRAM_write(nvram, addr + 3, value);
69 static uint32_t NVRAM_get_lword (nvram_t *nvram, uint16_t addr)
73 tmp = NVRAM_read(nvram, addr) << 24;
74 tmp |= NVRAM_read(nvram, addr + 1) << 16;
75 tmp |= NVRAM_read(nvram, addr + 2) << 8;
76 tmp |= NVRAM_read(nvram, addr + 3);
81 static void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
82 const unsigned char *str, uint32_t max)
86 for (i = 0; i < max && str[i] != '\0'; i++) {
87 NVRAM_write(nvram, addr + i, str[i]);
89 NVRAM_write(nvram, addr + i, '\0');
92 static int NVRAM_get_string (nvram_t *nvram, uint8_t *dst,
93 uint16_t addr, int max)
98 for (i = 0; i < max; i++) {
99 dst[i] = NVRAM_get_byte(nvram, addr + i);
107 static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
110 uint16_t pd, pd1, pd2;
115 pd2 = ((pd >> 4) & 0x000F) ^ pd1;
116 tmp ^= (pd1 << 3) | (pd1 << 8);
117 tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
122 static uint16_t NVRAM_compute_crc (nvram_t *nvram,
123 uint32_t start, uint32_t count)
126 uint16_t crc = 0xFFFF;
131 for (i = 0; i != count; i++) {
132 crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
135 crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
141 /* Format NVRAM for PREP target */
142 static int NVRAM_prep_format (nvram_t *nvram)
144 #define NVRAM_PREP_OSAREA_SIZE 512
145 #define NVRAM_PREP_CONFSIZE 1024
149 /* 0x00: NVRAM size in kB */
150 NVRAM_set_word(nvram, 0x00, nvram->size >> 10);
151 /* 0x02: NVRAM version */
152 NVRAM_set_byte(nvram, 0x02, 0x01);
153 /* 0x03: NVRAM revision */
154 NVRAM_set_byte(nvram, 0x03, 0x01);
156 NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */
158 NVRAM_set_byte(nvram, 0x09, 'B'); /* Big-endian */
159 /* 0x0A: OSArea usage */
160 NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */
162 NVRAM_set_byte(nvram, 0x0B, 0x00); /* Normal */
163 /* Restart block description record */
164 /* 0x0C: restart block version */
165 NVRAM_set_word(nvram, 0x0C, 0x01);
166 /* 0x0E: restart block revision */
167 NVRAM_set_word(nvram, 0x0E, 0x01);
168 /* 0x20: restart address */
169 NVRAM_set_lword(nvram, 0x20, 0x00);
170 /* 0x24: save area address */
171 NVRAM_set_lword(nvram, 0x24, 0x00);
172 /* 0x28: save area length */
173 NVRAM_set_lword(nvram, 0x28, 0x00);
174 /* 0x1C: checksum of restart block */
175 crc = NVRAM_compute_crc(nvram, 0x0C, 32);
176 NVRAM_set_word(nvram, 0x1C, crc);
178 /* Security section */
179 /* Set all to zero */
180 /* 0xC4: pointer to global environment area */
181 NVRAM_set_lword(nvram, 0xC4, 0x0100);
182 /* 0xC8: size of global environment area */
183 NVRAM_set_lword(nvram, 0xC8, nvram->size - NVRAM_PREP_OSAREA_SIZE -
184 NVRAM_PREP_CONFSIZE - 0x0100);
185 /* 0xD4: pointer to configuration area */
186 NVRAM_set_lword(nvram, 0xD4, nvram->size - NVRAM_PREP_CONFSIZE);
187 /* 0xD8: size of configuration area */
188 NVRAM_set_lword(nvram, 0xD8, NVRAM_PREP_CONFSIZE);
189 /* 0xE8: pointer to OS specific area */
190 NVRAM_set_lword(nvram, 0xE8, nvram->size - NVRAM_PREP_CONFSIZE
191 - NVRAM_PREP_OSAREA_SIZE);
192 /* 0xD8: size of OS specific area */
193 NVRAM_set_lword(nvram, 0xEC, NVRAM_PREP_OSAREA_SIZE);
195 /* Configuration area */
197 /* 0x04: checksum 0 => OS area */
198 crc = NVRAM_compute_crc(nvram, 0x00, nvram->size - NVRAM_PREP_CONFSIZE -
199 NVRAM_PREP_OSAREA_SIZE);
200 NVRAM_set_word(nvram, 0x04, crc);
201 /* 0x06: checksum of config area */
202 crc = NVRAM_compute_crc(nvram, nvram->size - NVRAM_PREP_CONFSIZE,
203 NVRAM_PREP_CONFSIZE);
204 NVRAM_set_word(nvram, 0x06, crc);
209 static uint8_t NVRAM_chrp_chksum (nvram_t *nvram, uint16_t pos)
214 sum = NVRAM_get_byte(nvram, pos);
215 for (pos += 2; pos < end; pos++) {
216 sum += NVRAM_get_byte(nvram, pos);
219 sum = (sum & 0xFF) + (sum >> 8);
225 static int NVRAM_chrp_format (unused nvram_t *nvram)
229 /* Mark NVRAM as free */
230 NVRAM_set_byte(nvram, 0x00, 0x5A);
231 NVRAM_set_byte(nvram, 0x01, 0x00);
232 NVRAM_set_word(nvram, 0x02, 0x2000);
233 NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12);
234 chksum = NVRAM_chrp_chksum(nvram, 0x00);
235 NVRAM_set_byte(nvram, 0x01, chksum);
241 static uint16_t NVRAM_mac99_chksum (nvram_t *nvram,
242 uint16_t start, uint16_t len)
246 buffer += CORE99_ADLER_START;
249 for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
250 if ((cnt % 5000) == 0) {
260 return (high << 16) | low;
266 for (pos = start; pos < (start + len); pos++) {
267 tmp = sum + NVRAM_get_byte(nvram, pos);
277 static int NVRAM_mac99_format (nvram_t *nvram)
281 /* Mark NVRAM as free */
282 NVRAM_set_byte(nvram, 0x00, 0x5A);
283 NVRAM_set_byte(nvram, 0x01, 0x00);
284 NVRAM_set_word(nvram, 0x02, 0x2000);
285 NVRAM_set_string(nvram, 0x04, "wwwwwwwwwwww", 12);
286 chksum = NVRAM_chrp_chksum(nvram, 0x00);
287 NVRAM_set_byte(nvram, 0x01, chksum);
292 static int NVRAM_pop_format (unused nvram_t *nvram)
299 uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr)
301 outb(nvram->io_base + 0x00, addr);
302 outb(nvram->io_base + 0x01, addr >> 8);
304 return inb(NVRAM_IO_BASE + 0x03);
307 void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value)
309 outb(nvram->io_base + 0x00, addr);
310 outb(nvram->io_base + 0x01, addr >> 8);
311 outb(nvram->io_base + 0x03, value);
314 uint16_t NVRAM_get_size (nvram_t *nvram)
319 int NVRAM_format (nvram_t *nvram)
326 for (pos = 0; pos < nvram->size; pos += 4)
327 NVRAM_set_lword(nvram, pos, 0);
331 ret = NVRAM_prep_format(nvram);
334 ret = NVRAM_chrp_format(nvram);
337 case ARCH_HEATHROW: /* XXX: may be incorrect */
338 ret = NVRAM_mac99_format(nvram);
341 ret = NVRAM_pop_format(nvram);
352 extern int vga_width, vga_height, vga_depth;
354 static nvram_t global_nvram;
356 nvram_t *NVRAM_get_config (uint32_t *RAM_size, int *boot_device,
357 void **boot_image, uint32_t *boot_size,
358 void **cmdline, uint32_t *cmdline_size,
359 void **ramdisk, uint32_t *ramdisk_size)
361 unsigned char sign[16];
364 uint16_t NVRAM_size, crc;
368 nvram = malloc(sizeof(nvram_t));
372 nvram = &global_nvram;
374 nvram->io_base = NVRAM_IO_BASE;
375 /* Pre-initialised NVRAM is not supported any more */
376 if (NVRAM_get_string(nvram, sign, 0x00, 0x10) <= 0 ||
377 strcmp(sign, "QEMU_BIOS") != 0) {
378 ERROR("Wrong NVRAM signature %s\n", sign);
381 /* Check structure version */
382 lword = NVRAM_get_lword(nvram, 0x10);
383 if (lword != 0x00000002) {
384 ERROR("Wrong NVRAM structure version: %0x\n", lword);
388 crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
389 if (NVRAM_get_word(nvram, 0xFC) != crc) {
390 ERROR("Invalid NVRAM structure CRC: %0x <=> %0x\n", crc,
391 NVRAM_get_word(nvram, 0xFC));
394 NVRAM_size = NVRAM_get_word(nvram, 0x14);
395 if ((NVRAM_size & 0x100) != 0x00 || NVRAM_size < 0x400 ||
396 NVRAM_size > 0x2000) {
397 ERROR("Invalid NVRAM size: %d\n", NVRAM_size);
400 nvram->size = NVRAM_size;
401 if (NVRAM_get_string(nvram, sign, 0x20, 0x10) < 0) {
402 ERROR("Unable to get architecture from NVRAM\n");
405 if (strcmp(sign, "PREP") == 0) {
407 } else if (strcmp(sign, "CHRP") == 0) {
409 } else if (strcmp(sign, "MAC99") == 0) {
411 } else if (strcmp(sign, "POP") == 0) {
413 } else if (strcmp(sign, "HEATHROW") == 0) {
414 arch = ARCH_HEATHROW;
416 ERROR("Unknown PPC architecture: '%s'\n", sign);
419 lword = NVRAM_get_lword(nvram, 0x30);
421 byte = NVRAM_get_byte(nvram, 0x34);
423 /* Preloaded boot image */
424 lword = NVRAM_get_lword(nvram, 0x38);
425 *boot_image = (void *)lword;
426 lword = NVRAM_get_lword(nvram, 0x3C);
428 /* Preloaded cmdline */
429 lword = NVRAM_get_lword(nvram, 0x40);
430 *cmdline = (void *)lword;
431 lword = NVRAM_get_lword(nvram, 0x44);
432 *cmdline_size = lword;
433 /* Preloaded RAM disk */
434 lword = NVRAM_get_lword(nvram, 0x48);
435 *ramdisk = (void *)lword;
436 lword = NVRAM_get_lword(nvram, 0x4C);
437 *ramdisk_size = lword;
438 /* Preloaded NVRAM image */
439 lword = NVRAM_get_lword(nvram, 0x50);
440 /* Display init geometry */
441 lword = NVRAM_get_word(nvram, 0x54);
443 lword = NVRAM_get_word(nvram, 0x56);
445 lword = NVRAM_get_word(nvram, 0x58);
447 /* TODO: write it into NVRAM */