Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / rtas / flash / block_lists.c
diff --git a/qemu/roms/SLOF/rtas/flash/block_lists.c b/qemu/roms/SLOF/rtas/flash/block_lists.c
new file mode 100644 (file)
index 0000000..e632fd0
--- /dev/null
@@ -0,0 +1,275 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <product.h>
+#include <stdio.h>
+#include "block_lists.h"
+
+unsigned char sig_org[] = FLASHFS_PLATFORM_MAGIC;
+
+/* this function is part of the crc_lib assembler code */
+unsigned long check_flash_image(unsigned long, unsigned long, unsigned long);
+
+/* this functions needs to be implemented by the board specific flash code
+ * the functions always get 32 bytes and needs to deal with the data */
+void write_flash(unsigned long, unsigned short *);
+
+int progress = 0;
+
+int
+print_progress(void)
+{
+       static int i = 3;
+       switch (i--) {
+       case 3:
+               printf("\b|");
+               break;
+       case 2:
+               printf("\b/");
+               break;
+       case 1:
+               printf("\b-");
+               break;
+       case 0:
+               printf("\b\\");
+       default:
+               i = 3;
+       }
+       return 0;
+}
+
+void
+print_hash(void)
+{
+       printf("\b# ");
+}
+
+void
+print_writing(void)
+{
+       int counter = 42;
+       printf("\nWriting Flash: |");
+       while (counter--)
+               printf(" ");
+       printf("|");
+       counter = 41;
+       while (counter--)
+               printf("\b");
+
+}
+
+int
+get_block_list_version(unsigned char *data)
+{
+       if (data[0] == 0x01)
+               return 1;
+       return 0;
+}
+
+static long
+get_image_size(unsigned long *data, unsigned long length)
+{
+       long size = 0;
+       unsigned long i;
+       for (i = 0; i < length / 8; i += 2) {
+               size += data[1 + i];
+       }
+       return size;
+}
+
+static long
+get_image_size_v0(unsigned long *data)
+{
+       unsigned long bl_size = data[0];
+       return get_image_size(data + 1, bl_size - 8);
+}
+
+static long
+get_image_size_v1(unsigned long *data)
+{
+       unsigned long *bl_addr = data;
+       unsigned long bl_size;
+       unsigned long *next;
+       long size = 0;
+       while (bl_addr) {
+               bl_size = bl_addr[0];
+               next = (unsigned long *) bl_addr[1];
+               bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+               size += get_image_size(bl_addr + 2, bl_size - 0x10);
+               bl_addr = next;
+       }
+       return size;
+}
+
+long
+get_size(unsigned long *data, int version)
+{
+       if (version == 1)
+               return get_image_size_v1(data);
+       return get_image_size_v0(data);
+}
+
+static unsigned long
+write_one_block(unsigned long *block, unsigned long length,
+               unsigned long offset)
+{
+       unsigned long block_addr = (unsigned long) block;
+       unsigned long i = 0;
+       static unsigned int hash;
+       if (offset == 0)
+               hash = 0;
+
+       for (i = 0; i < length; i += 32, offset += 32, block_addr += 32) {
+               write_flash(offset, (unsigned short *) block_addr);
+               if (offset % 10 == 0) {
+                       print_progress();
+               }
+               if (offset > hash * progress) {
+                       print_hash();
+                       hash++;
+               }
+       }
+
+       return offset;
+}
+
+static unsigned long
+write_one_list(unsigned long *bl, unsigned long length, unsigned long offset)
+{
+       unsigned long i;
+       // 0x10: /8 for pointer /2 it has to be done in steps of 2
+       for (i = 0; i < length / 0x10; i++) {
+               offset =
+                   write_one_block((unsigned long *) *bl, *(bl + 1), offset);
+               bl += 2;
+       }
+       return offset;
+}
+
+void
+write_block_list(unsigned long *bl, int version)
+{
+       unsigned long offset = 0;
+       unsigned long *bl_addr = bl;
+       unsigned long bl_size;
+       unsigned long *next;
+
+       if (version == 0) {
+               // -8 = removed header length
+               write_one_list(bl + 1, *(bl) - 8, offset);
+               return;
+       }
+
+       while (bl_addr) {
+               bl_size = bl_addr[0];
+               next = (unsigned long *) bl_addr[1];
+               bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+               // -0x10 = removed header length
+               offset = write_one_list(bl_addr + 2, bl_size - 0x10, offset);
+               bl_addr = next;
+       }
+
+}
+
+static int
+check_one_list(unsigned long *bl, unsigned long length, unsigned long crc)
+{
+       unsigned long i;
+       // 0x10: /8 for pointer /2 it has to be done in steps of 2
+       for (i = 0; i < length / 0x10; i++) {
+               crc = check_flash_image((unsigned long) *bl, *(bl + 1), crc);
+               bl += 2;
+       }
+       return crc;
+}
+
+int
+image_check_crc(unsigned long *bl, int version)
+{
+       unsigned long *bl_addr = bl;
+       unsigned long bl_size;
+       unsigned long *next;
+       unsigned long crc = 0;
+
+       if (version == 0) {
+               // -8 = removed header length
+               return check_one_list(bl + 1, *(bl) - 8, crc);
+       }
+
+       while (bl_addr) {
+               bl_size = bl_addr[0];
+               next = (unsigned long *) bl_addr[1];
+               bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+               // -0x10 = removed header length
+               crc = check_one_list(bl_addr + 2, bl_size - 0x10, crc);
+               bl_addr = next;
+       }
+       return crc;
+}
+
+static int
+check_platform_one_list(unsigned long *bl, unsigned long bytesec)
+{
+       unsigned long pos = bytesec;
+       unsigned char *sig_tmp, *sig;
+       unsigned long size = 0;
+       sig = sig_org;
+
+       while (size < bytesec) {
+               size += bl[1];
+
+               while (size > pos) {    // 32 == FLASHFS_PLATFORM_MAGIC length
+                       sig_tmp = (unsigned char *) (bl[0] + pos);
+                       if (*sig++ != *sig_tmp)
+                               return -1;
+                       if (*sig_tmp == '\0' || (pos == bytesec + 32)) {
+                               pos = bytesec + 32;
+                               break;
+                       }
+                       pos++;
+               }
+               if (pos == (bytesec + 32))
+                       return 0;
+               bl += 2;
+       }
+       return 0;
+}
+
+int
+check_platform(unsigned long *bl, unsigned int bytesec, int version)
+{
+       unsigned long *bl_addr = bl;
+       unsigned long bl_size;
+       unsigned long *next;
+       unsigned long *ptr;
+       ptr = bl;
+
+       if (version == 0) {
+               ptr += 1;       // -8 = removed header length
+               return check_platform_one_list(ptr, bytesec);
+       }
+       while (bl_addr) {
+               ptr = bl_addr + 2;      // -0x10 = removed header length
+               bl_size = bl_addr[0];
+               next = (unsigned long *) bl_addr[1];
+               bl_size = bl_size & 0x00FFFFFFFFFFFFFFUL;
+               if ((bl_size - 0x10) == 0) {
+                       bl_addr = next;
+                       continue;
+               }
+               if (check_platform_one_list(ptr, bytesec) == 0)
+                       return 0;
+
+               bl_addr = next;
+       }
+       return -1;
+}