Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / rtas / flash / block_lists.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 <product.h>
14 #include <stdio.h>
15 #include "block_lists.h"
16
17 unsigned char sig_org[] = FLASHFS_PLATFORM_MAGIC;
18
19 /* this function is part of the crc_lib assembler code */
20 unsigned long check_flash_image(unsigned long, unsigned long, unsigned long);
21
22 /* this functions needs to be implemented by the board specific flash code
23  * the functions always get 32 bytes and needs to deal with the data */
24 void write_flash(unsigned long, unsigned short *);
25
26 int progress = 0;
27
28 int
29 print_progress(void)
30 {
31         static int i = 3;
32         switch (i--) {
33         case 3:
34                 printf("\b|");
35                 break;
36         case 2:
37                 printf("\b/");
38                 break;
39         case 1:
40                 printf("\b-");
41                 break;
42         case 0:
43                 printf("\b\\");
44         default:
45                 i = 3;
46         }
47         return 0;
48 }
49
50 void
51 print_hash(void)
52 {
53         printf("\b# ");
54 }
55
56 void
57 print_writing(void)
58 {
59         int counter = 42;
60         printf("\nWriting Flash: |");
61         while (counter--)
62                 printf(" ");
63         printf("|");
64         counter = 41;
65         while (counter--)
66                 printf("\b");
67
68 }
69
70 int
71 get_block_list_version(unsigned char *data)
72 {
73         if (data[0] == 0x01)
74                 return 1;
75         return 0;
76 }
77
78 static long
79 get_image_size(unsigned long *data, unsigned long length)
80 {
81         long size = 0;
82         unsigned long i;
83         for (i = 0; i < length / 8; i += 2) {
84                 size += data[1 + i];
85         }
86         return size;
87 }
88
89 static long
90 get_image_size_v0(unsigned long *data)
91 {
92         unsigned long bl_size = data[0];
93         return get_image_size(data + 1, bl_size - 8);
94 }
95
96 static long
97 get_image_size_v1(unsigned long *data)
98 {
99         unsigned long *bl_addr = data;
100         unsigned long bl_size;
101         unsigned long *next;
102         long size = 0;
103         while (bl_addr) {
104                 bl_size = bl_addr[0];
105                 next = (unsigned long *) bl_addr[1];
106                 bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
107                 size += get_image_size(bl_addr + 2, bl_size - 0x10);
108                 bl_addr = next;
109         }
110         return size;
111 }
112
113 long
114 get_size(unsigned long *data, int version)
115 {
116         if (version == 1)
117                 return get_image_size_v1(data);
118         return get_image_size_v0(data);
119 }
120
121 static unsigned long
122 write_one_block(unsigned long *block, unsigned long length,
123                 unsigned long offset)
124 {
125         unsigned long block_addr = (unsigned long) block;
126         unsigned long i = 0;
127         static unsigned int hash;
128         if (offset == 0)
129                 hash = 0;
130
131         for (i = 0; i < length; i += 32, offset += 32, block_addr += 32) {
132                 write_flash(offset, (unsigned short *) block_addr);
133                 if (offset % 10 == 0) {
134                         print_progress();
135                 }
136                 if (offset > hash * progress) {
137                         print_hash();
138                         hash++;
139                 }
140         }
141
142         return offset;
143 }
144
145 static unsigned long
146 write_one_list(unsigned long *bl, unsigned long length, unsigned long offset)
147 {
148         unsigned long i;
149         // 0x10: /8 for pointer /2 it has to be done in steps of 2
150         for (i = 0; i < length / 0x10; i++) {
151                 offset =
152                     write_one_block((unsigned long *) *bl, *(bl + 1), offset);
153                 bl += 2;
154         }
155         return offset;
156 }
157
158 void
159 write_block_list(unsigned long *bl, int version)
160 {
161         unsigned long offset = 0;
162         unsigned long *bl_addr = bl;
163         unsigned long bl_size;
164         unsigned long *next;
165
166         if (version == 0) {
167                 // -8 = removed header length
168                 write_one_list(bl + 1, *(bl) - 8, offset);
169                 return;
170         }
171
172         while (bl_addr) {
173                 bl_size = bl_addr[0];
174                 next = (unsigned long *) bl_addr[1];
175                 bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
176                 // -0x10 = removed header length
177                 offset = write_one_list(bl_addr + 2, bl_size - 0x10, offset);
178                 bl_addr = next;
179         }
180
181 }
182
183 static int
184 check_one_list(unsigned long *bl, unsigned long length, unsigned long crc)
185 {
186         unsigned long i;
187         // 0x10: /8 for pointer /2 it has to be done in steps of 2
188         for (i = 0; i < length / 0x10; i++) {
189                 crc = check_flash_image((unsigned long) *bl, *(bl + 1), crc);
190                 bl += 2;
191         }
192         return crc;
193 }
194
195 int
196 image_check_crc(unsigned long *bl, int version)
197 {
198         unsigned long *bl_addr = bl;
199         unsigned long bl_size;
200         unsigned long *next;
201         unsigned long crc = 0;
202
203         if (version == 0) {
204                 // -8 = removed header length
205                 return check_one_list(bl + 1, *(bl) - 8, crc);
206         }
207
208         while (bl_addr) {
209                 bl_size = bl_addr[0];
210                 next = (unsigned long *) bl_addr[1];
211                 bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
212                 // -0x10 = removed header length
213                 crc = check_one_list(bl_addr + 2, bl_size - 0x10, crc);
214                 bl_addr = next;
215         }
216         return crc;
217 }
218
219 static int
220 check_platform_one_list(unsigned long *bl, unsigned long bytesec)
221 {
222         unsigned long pos = bytesec;
223         unsigned char *sig_tmp, *sig;
224         unsigned long size = 0;
225         sig = sig_org;
226
227         while (size < bytesec) {
228                 size += bl[1];
229
230                 while (size > pos) {    // 32 == FLASHFS_PLATFORM_MAGIC length
231                         sig_tmp = (unsigned char *) (bl[0] + pos);
232                         if (*sig++ != *sig_tmp)
233                                 return -1;
234                         if (*sig_tmp == '\0' || (pos == bytesec + 32)) {
235                                 pos = bytesec + 32;
236                                 break;
237                         }
238                         pos++;
239                 }
240                 if (pos == (bytesec + 32))
241                         return 0;
242                 bl += 2;
243         }
244         return 0;
245 }
246
247 int
248 check_platform(unsigned long *bl, unsigned int bytesec, int version)
249 {
250         unsigned long *bl_addr = bl;
251         unsigned long bl_size;
252         unsigned long *next;
253         unsigned long *ptr;
254         ptr = bl;
255
256         if (version == 0) {
257                 ptr += 1;       // -8 = removed header length
258                 return check_platform_one_list(ptr, bytesec);
259         }
260         while (bl_addr) {
261                 ptr = bl_addr + 2;      // -0x10 = removed header length
262                 bl_size = bl_addr[0];
263                 next = (unsigned long *) bl_addr[1];
264                 bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
265                 if ((bl_size - 0x10) == 0) {
266                         bl_addr = next;
267                         continue;
268                 }
269                 if (check_platform_one_list(ptr, bytesec) == 0)
270                         return 0;
271
272                 bl_addr = next;
273         }
274         return -1;
275 }