diff options
author | 2015-08-28 09:58:54 +0800 | |
---|---|---|
committer | 2015-09-01 12:44:00 +0800 | |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/SLOF/rtas/flash/block_lists.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/SLOF/rtas/flash/block_lists.c')
-rw-r--r-- | qemu/roms/SLOF/rtas/flash/block_lists.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/rtas/flash/block_lists.c b/qemu/roms/SLOF/rtas/flash/block_lists.c new file mode 100644 index 000000000..e632fd0bd --- /dev/null +++ b/qemu/roms/SLOF/rtas/flash/block_lists.c @@ -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; +} |