Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / nvram.c
1 /*
2  * <nvram.c>
3  *
4  * Open Hack'Ware BIOS NVRAM management routines.
5  * 
6  * Copyright (c) 2004-2005 Jocelyn Mayer
7  * 
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
11  *
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.
16  *
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
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25
26 #define NVRAM_MAX_SIZE 0x2000
27 #define NVRAM_IO_BASE 0x0074
28
29 struct nvram_t {
30     uint16_t io_base;
31     uint16_t size;
32 };
33
34 /* NVRAM access */
35 static void NVRAM_set_byte (nvram_t *nvram, uint32_t addr, uint8_t value)
36 {
37     NVRAM_write(nvram, addr, value);
38 }
39
40 static uint8_t NVRAM_get_byte (nvram_t *nvram, uint16_t addr)
41 {
42     return NVRAM_read(nvram, addr);
43 }
44
45 static void NVRAM_set_word (nvram_t *nvram, uint16_t addr, uint16_t value)
46 {
47     NVRAM_write(nvram, addr, value >> 8);
48     NVRAM_write(nvram, addr + 1, value);
49 }
50
51 static uint16_t NVRAM_get_word (nvram_t *nvram, uint16_t addr)
52 {
53     uint16_t tmp;
54
55     tmp = NVRAM_read(nvram, addr) << 8;
56     tmp |= NVRAM_read(nvram, addr + 1);
57
58     return tmp;
59 }
60
61 static void NVRAM_set_lword (nvram_t *nvram, uint16_t addr, uint32_t value)
62 {
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);
67 }
68
69 static uint32_t NVRAM_get_lword (nvram_t *nvram, uint16_t addr)
70 {
71     uint32_t tmp;
72
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);
77
78     return tmp;
79 }
80
81 static void NVRAM_set_string (nvram_t *nvram, uint32_t addr,
82                               const unsigned char *str, uint32_t max)
83 {
84     uint32_t i;
85
86     for (i = 0; i < max && str[i] != '\0'; i++) {
87         NVRAM_write(nvram, addr + i, str[i]);
88     }
89     NVRAM_write(nvram, addr + i, '\0');
90 }
91
92 static int NVRAM_get_string (nvram_t *nvram, uint8_t *dst,
93                              uint16_t addr, int max)
94 {
95     int i;
96
97     memset(dst, 0, max);
98     for (i = 0; i < max; i++) {
99         dst[i] = NVRAM_get_byte(nvram, addr + i);
100         if (dst[i] == '\0')
101             break;
102     }
103
104     return i;
105 }
106
107 static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
108 {
109     uint16_t tmp;
110     uint16_t pd, pd1, pd2;
111
112     tmp = prev >> 8;
113     pd = prev ^ value;
114     pd1 = pd & 0x000F;
115     pd2 = ((pd >> 4) & 0x000F) ^ pd1;
116     tmp ^= (pd1 << 3) | (pd1 << 8);
117     tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
118
119     return tmp;
120 }
121
122 static uint16_t NVRAM_compute_crc (nvram_t *nvram,
123                                    uint32_t start, uint32_t count)
124 {
125     uint32_t i;
126     uint16_t crc = 0xFFFF;
127     int odd;
128
129     odd = count & 1;
130     count &= ~1;
131     for (i = 0; i != count; i++) {
132         crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
133     }
134     if (odd) {
135         crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
136     }
137
138     return crc;
139 }
140
141 /* Format NVRAM for PREP target */
142 static int NVRAM_prep_format (nvram_t *nvram)
143 {
144 #define NVRAM_PREP_OSAREA_SIZE 512
145 #define NVRAM_PREP_CONFSIZE    1024
146     uint16_t crc;
147     
148     /* NVRAM header */
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);
155     /* 0x08: last OS */
156     NVRAM_set_byte(nvram, 0x08, 0x00); /* Unknown */
157     /* 0x09: endian */
158     NVRAM_set_byte(nvram, 0x09, 'B');  /* Big-endian */
159     /* 0x0A: OSArea usage */
160     NVRAM_set_byte(nvram, 0x0A, 0x00); /* Empty */
161     /* 0x0B: PM mode */
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);
177
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);
194
195     /* Configuration area */
196
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);
205
206     return 0;
207 }
208
209 static uint8_t NVRAM_chrp_chksum (nvram_t *nvram, uint16_t pos)
210 {
211     uint16_t sum, end;
212
213     end = pos + 0x10;
214     sum = NVRAM_get_byte(nvram, pos);
215     for (pos += 2; pos < end; pos++) {
216         sum += NVRAM_get_byte(nvram, pos);
217     }
218     while (sum > 0xFF) {
219         sum = (sum & 0xFF) + (sum >> 8);
220     }
221
222     return sum;
223 }
224
225 static int NVRAM_chrp_format (unused nvram_t *nvram)
226 {
227     uint8_t chksum;
228
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);
236
237     return 0;
238 }
239
240 #if 0
241 static uint16_t NVRAM_mac99_chksum (nvram_t *nvram,
242                                    uint16_t start, uint16_t len)
243         int cnt;
244         u32 low, high;
245
246         buffer += CORE99_ADLER_START;
247         low = 1;
248         high = 0;
249         for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
250                 if ((cnt % 5000) == 0) {
251                         high  %= 65521UL;
252                         high %= 65521UL;
253                 }
254                 low += buffer[cnt];
255                 high += low;
256         }
257         low  %= 65521UL;
258         high %= 65521UL;
259
260         return (high << 16) | low;
261 {
262     uint16_t pos;
263     uint8_t tmp, sum;
264
265     sum = 0;
266     for (pos = start; pos < (start + len); pos++) {
267         tmp = sum + NVRAM_get_byte(nvram, pos);
268         if (tmp < sum)
269             tmp++;
270         sum = tmp;
271     }
272
273     return sum;
274 }
275 #endif
276
277 static int NVRAM_mac99_format (nvram_t *nvram)
278 {
279     uint8_t chksum;
280
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);
288
289     return 0;
290 }
291
292 static int NVRAM_pop_format (unused nvram_t *nvram)
293 {
294     /* TODO */
295     return -1;
296 }
297
298 /* Interface */
299 uint8_t NVRAM_read (nvram_t *nvram, uint32_t addr)
300 {
301     outb(nvram->io_base + 0x00, addr);
302     outb(nvram->io_base + 0x01, addr >> 8);
303
304     return inb(NVRAM_IO_BASE + 0x03);
305 }
306
307 void NVRAM_write (nvram_t *nvram, uint32_t addr, uint8_t value)
308 {
309     outb(nvram->io_base + 0x00, addr);
310     outb(nvram->io_base + 0x01, addr >> 8);
311     outb(nvram->io_base + 0x03, value);
312 }
313
314 uint16_t NVRAM_get_size (nvram_t *nvram)
315 {
316     return nvram->size;
317 }
318
319 int NVRAM_format (nvram_t *nvram)
320 {
321     int ret;
322
323     {
324         uint16_t pos;
325         
326         for (pos = 0; pos < nvram->size; pos += 4)
327             NVRAM_set_lword(nvram, pos, 0);
328     }
329     switch (arch) {
330     case ARCH_PREP:
331         ret = NVRAM_prep_format(nvram);
332         break;
333     case ARCH_CHRP:
334         ret = NVRAM_chrp_format(nvram);
335         break;
336     case ARCH_MAC99:
337     case ARCH_HEATHROW: /* XXX: may be incorrect */
338         ret = NVRAM_mac99_format(nvram);
339         break;
340     case ARCH_POP:
341         ret = NVRAM_pop_format(nvram);
342         break;
343     default:
344         ret = -1;
345         break;
346     }
347
348     return ret;
349 }
350
351 /* HACK... */
352 extern int vga_width, vga_height, vga_depth;
353
354 static nvram_t global_nvram;
355
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)
360 {
361     unsigned char sign[16];
362     nvram_t *nvram;
363     uint32_t lword;
364     uint16_t NVRAM_size, crc;
365     uint8_t byte;
366
367 #if 0
368     nvram = malloc(sizeof(nvram_t));
369     if (nvram == NULL)
370         return NULL;
371 #else
372     nvram = &global_nvram;
373 #endif
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);
379         return NULL;
380     }
381     /* Check structure version */
382     lword = NVRAM_get_lword(nvram, 0x10);
383     if (lword != 0x00000002) {
384         ERROR("Wrong NVRAM structure version: %0x\n", lword);
385         return NULL;
386     }
387     /* Check CRC */
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));
392         return NULL;
393     }
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);
398         return NULL;
399     }
400     nvram->size = NVRAM_size;
401     if (NVRAM_get_string(nvram, sign, 0x20, 0x10) < 0) {
402         ERROR("Unable to get architecture from NVRAM\n");
403         return NULL;
404     }
405     if (strcmp(sign, "PREP") == 0) {
406         arch = ARCH_PREP;
407     } else if (strcmp(sign, "CHRP") == 0) {
408         arch = ARCH_CHRP;
409     } else if (strcmp(sign, "MAC99") == 0) {
410         arch = ARCH_MAC99;
411     } else if (strcmp(sign, "POP") == 0) {
412         arch = ARCH_POP;
413     } else if (strcmp(sign, "HEATHROW") == 0) {
414         arch = ARCH_HEATHROW;
415     } else {
416         ERROR("Unknown PPC architecture: '%s'\n", sign);
417         return NULL;
418     }
419     lword = NVRAM_get_lword(nvram, 0x30);
420     *RAM_size = lword;
421     byte = NVRAM_get_byte(nvram, 0x34);
422     *boot_device = byte;
423     /* Preloaded boot image */
424     lword = NVRAM_get_lword(nvram, 0x38);
425     *boot_image = (void *)lword;
426     lword = NVRAM_get_lword(nvram, 0x3C);
427     *boot_size = lword;
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);
442     vga_width = lword;
443     lword = NVRAM_get_word(nvram, 0x56);
444     vga_height = lword;
445     lword = NVRAM_get_word(nvram, 0x58);
446     vga_depth = lword;
447     /* TODO: write it into NVRAM */
448
449     return nvram;
450 }