Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libnvram / nvram.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include "cache.h"
14 #include "nvram.h"
15 #include "../libhvcall/libhvcall.h"
16
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <southbridge.h>
21 #include <nvramlog.h>
22 #include <byteorder.h>
23
24 #ifdef RTAS_NVRAM
25 static uint32_t fetch_token;
26 static uint32_t store_token;
27 static uint32_t NVRAM_LENGTH;
28 static char *nvram_buffer; /* use buffer allocated by SLOF code */
29 #else
30 #ifndef NVRAM_LENGTH
31 #define NVRAM_LENGTH    0x10000
32 #endif
33 /*
34  * This is extremely ugly, but still better than implementing 
35  * another sbrk() around it.
36  */
37 static char nvram_buffer[NVRAM_LENGTH];
38 #endif
39
40 static uint8_t nvram_buffer_locked=0x00;
41
42 void nvram_init(uint32_t _fetch_token, uint32_t _store_token, 
43                 long _nvram_length, void* nvram_addr)
44 {
45 #ifdef RTAS_NVRAM
46         fetch_token = _fetch_token;
47         store_token = _store_token;
48         NVRAM_LENGTH = _nvram_length;
49         nvram_buffer = nvram_addr;
50
51         DEBUG("\nNVRAM: size=%d, fetch=%x, store=%x\n",
52                 NVRAM_LENGTH, fetch_token, store_token);
53 #endif
54 }
55
56
57 void asm_cout(long Character,long UART,long NVRAM);
58
59 #if defined(DISABLE_NVRAM)
60
61 static volatile uint8_t nvram[NVRAM_LENGTH]; /* FAKE */
62
63 #define nvram_access(type,size,name)                            \
64         type nvram_read_##name(unsigned int offset)             \
65         {                                                       \
66                 type *pos;                                      \
67                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
68                         return 0;                               \
69                 pos = (type *)(nvram+offset);                   \
70                 return *pos;                                    \
71         }                                                       \
72         void nvram_write_##name(unsigned int offset, type data) \
73         {                                                       \
74                 type *pos;                                      \
75                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
76                         return;                                 \
77                 pos = (type *)(nvram+offset);                   \
78                 *pos = data;                                    \
79         }
80
81 #elif defined(RTAS_NVRAM)
82
83 static inline void nvram_fetch(unsigned int offset, void *buf, unsigned int len)
84 {
85         struct hv_rtas_call rtas = {
86                 .token = fetch_token,
87                 .nargs = 3,
88                 .nrets = 2,
89                 .argret = { offset, (uint32_t)(unsigned long)buf, len },
90         };
91         h_rtas(&rtas);
92 }
93
94 static inline void nvram_store(unsigned int offset, void *buf, unsigned int len)
95 {
96         struct hv_rtas_call rtas = {
97                 .token = store_token,
98                 .nargs = 3,
99                 .nrets = 2,
100                 .argret = { offset, (uint32_t)(unsigned long)buf, len },
101         };
102         h_rtas(&rtas);
103 }
104
105 #define nvram_access(type,size,name)                            \
106         type nvram_read_##name(unsigned int offset)             \
107         {                                                       \
108                 type val;                                       \
109                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
110                         return 0;                               \
111                 nvram_fetch(offset, &val, size / 8);            \
112                 return val;                                     \
113         }                                                       \
114         void nvram_write_##name(unsigned int offset, type data) \
115         {                                                       \
116                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
117                         return;                                 \
118                 nvram_store(offset, &data, size / 8);           \
119         }
120
121 #else   /* DISABLE_NVRAM */
122
123 static volatile uint8_t *nvram = (volatile uint8_t *)SB_NVRAM_adr;
124
125 #define nvram_access(type,size,name)                            \
126         type nvram_read_##name(unsigned int offset)             \
127         {                                                       \
128                 type *pos;                                      \
129                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
130                         return 0;                               \
131                 pos = (type *)(nvram+offset);                   \
132                 return ci_read_##size(pos);                     \
133         }                                                       \
134         void nvram_write_##name(unsigned int offset, type data) \
135         {                                                       \
136                 type *pos;                                      \
137                 if (offset > (NVRAM_LENGTH - sizeof(type)))     \
138                         return;                                 \
139                 pos = (type *)(nvram+offset);                   \
140                 ci_write_##size(pos, data);                     \
141         }
142
143 #endif
144
145 /*
146  * producer for nvram access functions. Since these functions are
147  * basically all the same except for the used data types, produce 
148  * them via the nvram_access macro to keep the code from bloating.
149  */
150
151 nvram_access(uint8_t,   8, byte)
152 nvram_access(uint16_t, 16, word)
153 nvram_access(uint32_t, 32, dword)
154 nvram_access(uint64_t, 64, qword)
155
156
157
158 /**
159  * This function is a minimal abstraction for our temporary
160  * buffer. It should have been malloced, but since there is no
161  * usable malloc, we go this route.
162  *
163  * @return pointer to temporary buffer
164  */
165
166 char *get_nvram_buffer(int len)
167 {
168         if(len>NVRAM_LENGTH)
169                 return NULL;
170
171         if(nvram_buffer_locked)
172                 return NULL;
173
174         nvram_buffer_locked = 0xff;
175
176         return nvram_buffer;
177 }
178
179 /**
180  * @param buffer pointer to the allocated buffer. This
181  * is unused, but nice in case we ever get a real malloc
182  */
183
184 void free_nvram_buffer(char *buffer __attribute__((unused)))
185 {
186         nvram_buffer_locked = 0x00;
187 }
188
189 /**
190  * @param fmt format string, like in printf
191  * @param ... variable number of arguments
192  */
193
194 int nvramlog_printf(const char* fmt, ...)
195 {
196         char buff[256];
197         int count, i;
198         va_list ap;
199
200         va_start(ap, fmt);
201         count = vsprintf(buff, fmt, ap);
202         va_end(ap);
203
204         for (i=0; i<count; i++)
205                 asm_cout(buff[i], 0, 1);
206
207         return count;
208 }
209
210 /**
211  * @param offset start offset of the partition header
212  */
213
214 static uint8_t get_partition_type(int offset)
215 {
216         return nvram_read_byte(offset);
217 }
218
219 /**
220  * @param offset start offset of the partition header
221  */
222
223 static uint8_t get_partition_header_checksum(int offset)
224 {
225         return nvram_read_byte(offset+1);
226 }
227
228 /**
229  * @param offset start offset of the partition header
230  */
231
232 static uint16_t get_partition_len(int offset)
233 {
234         return nvram_read_word(offset+2);
235 }
236
237 /**
238  * @param offset start offset of the partition header
239  * @return static char array containing the partition name
240  *
241  * NOTE: If the partition name needs to be non-temporary, strdup 
242  * and use the copy instead.
243  */
244
245 static char * get_partition_name(int offset)
246 {
247         static char name[12];
248         int i;
249         for (i=0; i<12; i++)
250                 name[i]=nvram_read_byte(offset+4+i);
251
252         DEBUG("name: \"%s\"\n", name);
253         return name;
254 }
255
256 static uint8_t calc_partition_header_checksum(int offset)
257 {
258         uint16_t plainsum;
259         uint8_t checksum;
260         int i;
261
262         plainsum = nvram_read_byte(offset);
263
264         for (i=2; i<PARTITION_HEADER_SIZE; i++)
265                 plainsum+=nvram_read_byte(offset+i);
266
267         checksum=(plainsum>>8)+(plainsum&0xff);
268
269         return checksum;
270 }
271
272 static int calc_used_nvram_space(void)
273 {
274         int walk, len;
275
276         for (walk=0; walk<NVRAM_LENGTH;) {
277                 if(nvram_read_byte(walk) == 0 
278                    || get_partition_header_checksum(walk) != 
279                                 calc_partition_header_checksum(walk)) {
280                         /* If there's no valid entry, bail out */
281                         break;
282                 }
283
284                 len=get_partition_len(walk);
285                 DEBUG("... part len=%x, %x\n", len, len*16);
286
287                 if(!len) {
288                         /* If there's a partition type but no len, bail out.
289                          * Don't bail out if type is 0. This can be used to
290                          * find the offset of the first free byte.
291                          */
292                         break;
293                 }
294
295                 walk += len * 16;
296         }
297         DEBUG("used nvram space: %d\n", walk);
298
299         return walk;
300 }
301
302 /**
303  *
304  * @param type partition type. Set this to the partition type you are looking
305  *             for. If there are several partitions with the same type, only
306  *             the first partition with that type will be found.
307  *             Set to -1 to ignore. Set to 0 to find free unpartitioned space.
308  *
309  * @param name partition name. Set this to the name of the partition you are
310  *             looking for. If there are several partitions with the same name,
311  *             only the first partition with that name will be found.
312  *             Set to NULL to ignore.
313  *
314  * To disambiguate the partitions you should have a unique name if you plan to
315  * have several partitions of the same type.
316  *
317  */
318
319 partition_t get_partition(unsigned int type, char *name)
320 {
321         partition_t ret={0,-1};
322         int walk, len;
323
324         DEBUG("get_partition(%i, '%s')\n", type, name);
325
326         for (walk=0; walk<NVRAM_LENGTH;) {
327                 // DEBUG("get_partition: walk=%x\n", walk);
328                 if(get_partition_header_checksum(walk) != 
329                                 calc_partition_header_checksum(walk)) {
330                         /* If there's no valid entry, bail out */
331                         break;
332                 }
333
334                 len=get_partition_len(walk);
335                 if(type && !len) {
336                         /* If there's a partition type but no len, bail out.
337                          * Don't bail out if type is 0. This can be used to
338                          * find the offset of the first free byte.
339                          */
340                         break;
341                 }
342
343                 /* Check if either type or name or both do not match. */
344                 if ( (type!=(unsigned int)-1 && type != get_partition_type(walk)) ||
345                         (name && strncmp(get_partition_name(walk), name, 12)) ) {
346                         /* We hit another partition. Continue
347                          * at the end of this partition
348                          */
349                         walk += len*16;
350                         continue;
351                 }
352
353                 ret.addr=walk+PARTITION_HEADER_SIZE;
354                 ret.len=(len*16)-PARTITION_HEADER_SIZE;
355                 break;
356         }
357
358         return ret;
359 }
360
361 void erase_nvram(int offset, int len)
362 {
363         int i;
364
365         for (i=offset; i<offset+len; i++)
366                 nvram_write_byte(i, 0);
367 }
368
369 void wipe_nvram(void)
370 {
371         erase_nvram(0, NVRAM_LENGTH);
372 }
373
374 /**
375  * @param partition   partition structure pointing to the partition to wipe.
376  * @param header_only if header_only is != 0 only the partition header is
377  *                    nulled out, not the whole partition.
378  */
379
380 int wipe_partition(partition_t partition, int header_only)
381 {
382         int pstart, len;
383
384         pstart=partition.addr-PARTITION_HEADER_SIZE;
385         
386         len=PARTITION_HEADER_SIZE;
387
388         if(!header_only)
389                 len += partition.len;
390
391         erase_nvram(pstart, len);
392
393         return 0;
394 }
395
396
397 static partition_t create_nvram_partition(int type, const char *name, int len)
398 {
399         partition_t ret = { 0, 0 };
400         int offset, plen;
401         unsigned int i;
402
403         plen = ALIGN(len+PARTITION_HEADER_SIZE, 16);
404
405         DEBUG("Creating partition type=%x, name=%s, len=%d plen=%d\n",
406                         type, name, len, plen);
407
408         offset = calc_used_nvram_space();
409
410         if (NVRAM_LENGTH-(calc_used_nvram_space())<plen) {
411                 DEBUG("Not enough free space.\n");
412                 return ret;
413         }
414
415         DEBUG("Writing header.");
416
417         nvram_write_byte(offset, type);
418         nvram_write_word(offset+2, plen/16);
419
420         for (i=0; i<strlen(name); i++)
421                 nvram_write_byte(offset+4+i, name[i]);
422
423         nvram_write_byte(offset+1, calc_partition_header_checksum(offset));
424
425         ret.addr = offset+PARTITION_HEADER_SIZE;
426         ret.len = len;
427
428         DEBUG("partition created: addr=%lx len=%lx\n", ret.addr, ret.len);
429
430         return ret;
431 }
432
433 static int create_free_partition(void)
434 {
435         int free_space;
436         partition_t free_part;
437
438         free_space = NVRAM_LENGTH - calc_used_nvram_space() - PARTITION_HEADER_SIZE;
439         free_part = create_nvram_partition(0x7f, "free space", free_space);
440
441         return (free_part.addr != 0);
442 }
443
444 partition_t new_nvram_partition(int type, char *name, int len)
445 {
446         partition_t free_part, new_part = { 0, 0 };
447
448         /* NOTE: Assume all free space is consumed by the "free space"
449          * partition. This means a partition can not be increased in the middle
450          * of reset_nvram, which is obviously not a big loss.
451          */
452
453         free_part=get_partition(0x7f, NULL);
454         if( free_part.len && free_part.len != -1)
455                 wipe_partition(free_part, 1);
456
457         new_part = create_nvram_partition(type, name, len);
458
459         if(new_part.len != len) {
460                 new_part.len = 0;
461                 new_part.addr = 0;
462         }
463
464         create_free_partition();
465
466         return new_part;
467 }
468
469 /**
470  * @param partition   partition structure pointing to the partition to wipe.
471  */
472
473 int delete_nvram_partition(partition_t partition)
474 {
475         int i;
476         partition_t free_part;
477
478         if(!partition.len || partition.len == -1)
479                 return 0;
480
481         for (i=partition.addr+partition.len; i< NVRAM_LENGTH; i++) 
482                 nvram_write_byte(i - partition.len - PARTITION_HEADER_SIZE, nvram_read_byte(i));
483
484         erase_nvram(NVRAM_LENGTH-partition.len-PARTITION_HEADER_SIZE, 
485                         partition.len-PARTITION_HEADER_SIZE);
486
487         free_part=get_partition(0x7f, NULL);
488         wipe_partition(free_part, 0);
489         create_free_partition();
490
491         return 1;
492 }
493
494 int clear_nvram_partition(partition_t part)
495 {
496         if(!part.addr)
497                 return 0;
498
499         erase_nvram(part.addr, part.len);
500
501         return 1;
502 }
503
504
505 int increase_nvram_partition_size(partition_t partition, int newsize)
506 {
507         partition_t free_part;
508         int free_offset, end_offset, i;
509
510         /* We don't support shrinking partitions (yet) */
511         if (newsize < partition.len) {
512                 return 0;
513         }
514
515         /* NOTE: Assume all free space is consumed by the "free space"
516          * partition. This means a partition can not be increased in the middle
517          * of reset_nvram, which is obviously not a big loss.
518          */
519
520         free_part=get_partition(0x7f, NULL);
521
522         // FIXME: It could be 16 byte more. Also handle empty "free" partition.
523         if (free_part.len == -1 || free_part.len < newsize - partition.len ) {
524                 return 0;
525         }
526         
527         free_offset=free_part.addr - PARTITION_HEADER_SIZE; // first unused byte
528         end_offset=partition.addr + partition.len; // last used byte of partition + 1
529
530         if(free_offset > end_offset) {
531                 int j, bufferlen;
532                 char *overlap_buffer;
533
534                 bufferlen=free_offset - end_offset;
535
536                 overlap_buffer=get_nvram_buffer(bufferlen);
537                 if(!overlap_buffer) {
538                         return 0;
539                 }
540
541                 for (i=end_offset, j=0; i<free_offset; i++, j++)
542                         overlap_buffer[j]=nvram_read_byte(i);
543
544                 /* Only wipe the header. The free space partition is empty per
545                  * definition
546                  */
547
548                 wipe_partition(free_part, 1);
549
550                 for (i=partition.addr+newsize, j=0; i<(int)(partition.addr+newsize+bufferlen); i++, j++)
551                         nvram_write_byte(i, overlap_buffer[j]);
552
553                 free_nvram_buffer(overlap_buffer);
554         } else {
555                 /* Only wipe the header. */
556                 wipe_partition(free_part, 1);
557         }
558
559         /* Clear the new partition space */
560         erase_nvram(partition.addr+partition.len, newsize-partition.len);
561
562         nvram_write_word(partition.addr - 16 + 2, newsize);
563
564         create_free_partition();
565
566         return 1;
567 }
568
569 static void init_cpulog_partition(partition_t cpulog)
570 {
571         unsigned int offset=cpulog.addr;
572
573         /* see board-xxx/include/nvramlog.h for information */
574         nvram_write_word(offset+0, 0x40);  // offset
575         nvram_write_word(offset+2, 0x00);  // flags
576         nvram_write_dword(offset+4, 0x01); // pointer
577
578 }
579
580 void reset_nvram(void)
581 {
582         partition_t cpulog0, cpulog1;
583         struct {
584                 uint32_t prefix;
585                 uint64_t name;
586         } __attribute__((packed)) header;
587
588         DEBUG("Erasing NVRAM\n");
589         erase_nvram(0, NVRAM_LENGTH);
590
591         DEBUG("Creating CPU log partitions\n");
592         header.prefix = be32_to_cpu(LLFW_LOG_BE0_NAME_PREFIX);
593         header.name   = be64_to_cpu(LLFW_LOG_BE0_NAME);
594         cpulog0=create_nvram_partition(LLFW_LOG_BE0_SIGNATURE, (char *)&header, 
595                         (LLFW_LOG_BE0_LENGTH*16)-PARTITION_HEADER_SIZE);
596
597         header.prefix = be32_to_cpu(LLFW_LOG_BE1_NAME_PREFIX);
598         header.name   = be64_to_cpu(LLFW_LOG_BE1_NAME);
599         cpulog1=create_nvram_partition(LLFW_LOG_BE1_SIGNATURE, (char *)&header, 
600                         (LLFW_LOG_BE1_LENGTH*16)-PARTITION_HEADER_SIZE);
601
602         DEBUG("Initializing CPU log partitions\n");
603         init_cpulog_partition(cpulog0);
604         init_cpulog_partition(cpulog1);
605
606         nvramlog_printf("Creating common NVRAM partition\r\n");
607         create_nvram_partition(0x70, "common", 0x01000-PARTITION_HEADER_SIZE);
608
609         create_free_partition();
610 }
611
612 void nvram_debug(void)
613 {
614 #ifndef RTAS_NVRAM
615         printf("\nNVRAM_BASE: %p\n", nvram);
616         printf("NVRAM_LEN: 0x%x\n", NVRAM_LENGTH);
617 #endif
618 }
619
620 unsigned int get_nvram_size(void)
621 {
622         return NVRAM_LENGTH;
623 }