diff options
Diffstat (limited to 'qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c')
-rw-r--r-- | qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c | 614 |
1 files changed, 614 insertions, 0 deletions
diff --git a/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c new file mode 100644 index 000000000..189878da9 --- /dev/null +++ b/qemu/roms/SLOF/board-js2x/rtas/rtas_flash.c @@ -0,0 +1,614 @@ +/****************************************************************************** + * 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 <cpu.h> +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <hw.h> +#include <rtas.h> +#include "rtas_board.h" +#include <bmc.h> +#include "rtas_flash.h" +#include <flash/block_lists.h> +#include "product.h" +#include "calculatecrc.h" + +#undef DEBUG + +#ifdef DEBUG +#define dprintf(_x ...) printf(_x) +#else +#define dprintf(_x ...) +#endif + +static uint64_t size; +static uint64_t flashOffset; + +unsigned char manage_flash_buffer[BUFSIZE*2]; +unsigned long check_flash_image(unsigned long rombase, unsigned long length, + unsigned long start_crc); + +#ifdef DEBUG +static void +dump_blocklist(uint64_t *bl, int version) +{ + uint64_t bl_size; + uint8_t *addr = (uint8_t *)bl; + + if (version == 1) { + /* version 1 blocklist */ + bl_size = *bl & 0x00FFFFFFFFFFFFFFUL; + + } else { + bl_size = *bl; + } + + printf("\n\rblocklist_dump %lx", bl_size); + while (bl_size) { + unsigned int tmpCnt = bl_size; + unsigned char x; + if (tmpCnt > 8) + tmpCnt = 8; + printf("\n\r%08x: ", addr); + /* print hex */ + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + printf("%02x ", x); + } + tmpCnt = bl_size; + if (tmpCnt > 8) + tmpCnt = 8; + bl_size -= tmpCnt; + /* reset addr ptr to print ascii */ + addr = addr - tmpCnt; + /* print ascii */ + while (tmpCnt--) { + set_ci(); + x = *addr++; + clr_ci(); + if ((x < 32) || (x >= 127)) { + /* non-printable char */ + x = '.'; + } + printf("%c", x); + } + } + printf("\r\n"); +} +#endif + +void +rtas_dump_flash(rtas_args_t *rtas_args) +{ + int retVal = 0; + unsigned int size = rtas_args->args[0]; + unsigned int offset = rtas_args->args[1]; + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + printf("\n\rflash_dump %x %x", size, offset); + flash += offset; + while (size) { + unsigned int tmpCnt = size; + unsigned char x; + if (tmpCnt > 16) + tmpCnt = 16; + printf("\n\r%p: ", flash); + /* print hex */ + while (tmpCnt--) { + set_ci(); + x = *flash++; + clr_ci(); + printf("%02x ", x); + } + tmpCnt = size; + if (tmpCnt > 16) + tmpCnt = 16; + size -= tmpCnt; + /* reset flash ptr to print ascii */ + flash = flash - tmpCnt; + /* print ascii */ + while (tmpCnt--) { + set_ci(); + x = *flash++; + clr_ci(); + if ((x < 32) || (x >= 127)) { + /* non-printable char */ + x = '.'; + } + printf("%c", x); + } + } + printf("\r\n"); + rtas_args->args[rtas_args->nargs] = retVal; +} + + +static void +print_block(int i) +{ + int counter = 8; + + while (counter--) + printf("\b"); + printf("%08x", i); +} + + + +/* To enter data mode after flash has been in programming mode + * a 0xFF has to be written */ +static void +enter_data_mode(void) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + set_ci(); + *flash = 0xFF; + eieio(); + clr_ci(); +} + + +static void +erase_flash_block(unsigned long offset) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + flash += offset; + set_ci(); + *flash = 0x20; + eieio(); + *flash = 0xd0; + eieio(); + while (!(*flash & 0x80)) ; + clr_ci(); +} + + +void +write_flash(unsigned long offset, unsigned char *data) +{ + int cnt = 32; + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + + flash += (offset + flashOffset); + set_ci(); + while (cnt) { + if (!((uint64_t)flash & 0x1F)) { + while (cnt) { + uint64_t tmpcnt = cnt; + if (tmpcnt > 0x20) + tmpcnt = 0x20; + do { + *flash = 0xE8; + eieio(); + } while (!(*flash & 0x80)); + cnt -= tmpcnt; + *flash = tmpcnt - 1; + while (tmpcnt--) { + *flash++ = *data++; + } + *flash = 0xD0; + eieio(); + while (!(*flash & 0x80)) ; + } + break; + } + *flash = 0x40; + eieio(); + *flash++ = *data++; + eieio(); + while (!(*flash & 0x80)) ; + cnt--; + } + clr_ci(); +} + +static void +write_flash_page(unsigned long offset, unsigned short *data) +{ + int i = 0; + + for (i = 0; i < BUFSIZE; i += 32, offset += 32) { + write_flash(offset, ((unsigned char *)data + i)); + } +} + +/* + * 0 reject temporary image + * 1 commit temporary image + * */ +static int +copy_flash(short mode) +{ + volatile unsigned char *flash = (volatile unsigned char *)FLASH; + uint64_t blockCnt; + uint64_t hash = 0; + short notmode = mode ^ 0x1; + + if (bmc_set_flashside(notmode) != notmode) { + return -1; + } + printf("\r\nErasing Flash: 0x "); + + for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += FLASH_BLOCK_SIZE) { + print_block(blockCnt); + erase_flash_block(blockCnt); + } + enter_data_mode(); + progress = FLASHSIZE / 38; + print_writing(); + + for (blockCnt = 0; blockCnt <= FLASHSIZE; blockCnt += BUFSIZE) { + uint64_t *srcPtr = (uint64_t *)(flash + blockCnt); + uint64_t *destPtr = (uint64_t *)manage_flash_buffer; + uint64_t cnt = BUFSIZE / 8; + if (bmc_set_flashside(mode) != mode) { + return -1; + } + enter_data_mode(); + set_ci(); + while (cnt--) { + *destPtr++ = *srcPtr++; + } + clr_ci(); + + if (bmc_set_flashside(notmode) != notmode) { + return -1; + } + write_flash_page(blockCnt, + (unsigned short *)manage_flash_buffer); + + /* progress output... */ + print_progress(); + if (blockCnt > hash * progress) { + print_hash(); + hash++; + } + } + enter_data_mode(); + if (bmc_set_flashside(mode) != mode) { + return -1; + } + printf("\b#\n"); + return 0; +} + +/* + * Function: ibm_manage_flash_image + * Input: + * r3: rtas parm structure + * token: 46 + * in: 1 + * out: 1 + * parm0: 0 reject temporary image + * 1 commit temporary image + * Output: + * parm1: Status (hw -1, busy -2, parameter error -3 + * -9001 cannot overwrite the active firmware image) + * + */ + +void +rtas_ibm_manage_flash_image(rtas_args_t *rtas_args) +{ + int side; + int result = 0; + short mode = rtas_args->args[0]; + + if (mode < 0 || mode > 1) { + rtas_args->args[rtas_args->nargs] = -3; + return; + } + side = bmc_get_flashside(); + if (side == 0) { + /* we are on the permanent side */ + if (mode != 0) { + rtas_args->args[rtas_args->nargs] = -9001; + return; + } + } else if (side == 1) { + /* we are on the temporary side */ + if (mode != 1) { + rtas_args->args[rtas_args->nargs] = -9001; + return; + } + } else { + rtas_args->args[rtas_args->nargs] = -1; + return; + } + + result = copy_flash(mode); + bmc_set_flashside(mode); + enter_data_mode(); + rtas_args->args[rtas_args->nargs] = result; +} + +/** + * check, if we find the FLASHFS_MAGIC token in bl + **/ +static uint8_t +check_magic(uint64_t *bl, int version) +{ + struct stH *pHeader; + + if (version == 1) { + /* version 1 blocklist */ + /* if block list size <= 0x10, it is only block list header */ + /* and address of block list extension, so look at the extension... */ + while ((*bl & 0x00FFFFFFFFFFFFFFUL) <= 0x10) + bl = (uint64_t *)bl[1]; + + /* block list item 2 _should_ be the address of our flashfs image */ + pHeader = (struct stH *)(bl[2] + 0x28); + /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */ + return strncmp(pHeader->magic, FLASHFS_MAGIC, 8); + } else { + /* block list item 1 _should_ be the address of our flashfs image */ + pHeader = (struct stH *)(bl[1] + 0x28); + /* printf("FlashFS Magic: \"%#s\"\r\n", pHeader->magic); */ + return strncmp(pHeader->magic, FLASHFS_MAGIC, 8); + } +} + +static void +get_image_name(char *buffer, int maxsize) +{ + volatile struct stH *flash_header = (volatile struct stH *)(SB_FLASH_adr + 0x28); + /* since we cannot read the fh_magic directly from flash as a string, we need to copy it to memory */ + uint64_t magic_val = 0; + uint64_t addr; + + /* copy fh_magic to magic_val since, we cannot use it as a string from flash */ + magic_val = load64_ci((uint64_t)(flash_header->magic)); + if (strncmp((char *)&magic_val, FLASHFS_MAGIC, 8)) { + /* magic does not match */ + sprintf(buffer, "Unknown"); + buffer[maxsize - 1] = '\0'; + return; + } + addr = (uint64_t)flash_header->version; + while (--maxsize) { + *buffer = load8_ci(addr++); + if (!*buffer++) + return; + } + *buffer = '\0'; +} + +/** + * validate_flash_image + * this function checks if the flash will be updated with the given image + * @param args[0] - buffer with minimum 4K of the image to flash + * @param args[1] - size of the buffer + * @param args[2] - status: + * 0 success + * -1 hw + * -2 busy + * -3 parameter error + * @param args[3] - update result token + */ +void +rtas_ibm_validate_flash_image(rtas_args_t *rtas_args) +{ + dprintf("\nrtas_ibm_validate_flash_image\n"); + unsigned long new_image = rtas_args->args[0]; + char *ret_str = (char *)new_image; + struct stH *flash_header = (struct stH *)(new_image + 0x28); + char current_temp_version[16]; + char current_perm_version[16]; + char new_version[16]; + int side = bmc_get_flashside(); + + /* fill args[0] with the current values which is needed + * in an error case */ + + bmc_set_flashside(0); + get_image_name(current_perm_version, sizeof(current_perm_version)); + bmc_set_flashside(1); + get_image_name(current_temp_version, sizeof(current_temp_version)); + bmc_set_flashside(side); + + /* check if the candidate image if valid for this platform */ + if (strncmp(flash_header->magic, FLASHFS_MAGIC, 8)) { + /* magic does not match */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + + if (strncmp(flash_header->platform_name, (char *)sig_org, 32)) { + /* this image if for a different board */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + + /* check header crc */ + if (check_flash_image(rtas_args->args[0], 0x88, 0)) { + /* header crc failed */ + rtas_args->args[rtas_args->nargs] = 0; + /* No update done, the candidate image is + * not valid for this platform */ + rtas_args->args[rtas_args->nargs + 1] = 2; + sprintf(ret_str, "MI %s %s\xaMI %s %s", + current_temp_version, current_perm_version, + current_temp_version, current_perm_version); + return; + } + memcpy(new_version, flash_header->version, 16); + sprintf(ret_str, "MI %s %s\xaMI %s %s", current_temp_version, + current_perm_version, new_version, current_perm_version); + rtas_args->args[rtas_args->nargs] = 0; + + if (strncmp(new_version, current_temp_version, 16) >= 0) + rtas_args->args[rtas_args->nargs + 1] = 0; + else + rtas_args->args[rtas_args->nargs + 1] = 6; +} + +/* + * Function: ibm_update_flash_64 + * Input: + * r3: rtas parm structure + * token: 7 + * in: 1 + * out: 1 + * parm0: A real pointer to a block list + * Output: + * parm1: Status (hw -1, bad image -3, programming failed -4) + * + * Description: flash if addresses above 4GB have to be addressed + */ +void +rtas_update_flash(rtas_args_t *rtas_args) +{ + void *bl = (void *)(uint64_t)rtas_args->args[0]; + int version = get_block_list_version((unsigned char *)bl); + uint64_t erase_size; + unsigned int i; + int perm_check = 1; + +#ifdef DEBUG + dump_blocklist(bl, version); +#endif + + /* from SLOF we pass a second (unofficial) parameter, if this parameter is 1, we do not + * check wether we are on permanent side. Needed for update-flash -c to work! */ + if ((rtas_args->nargs > 1) && (rtas_args->args[1] == 1)) + perm_check = 0; + + /* check magic string */ + printf("\r\nChecking magic string : "); + if (check_magic(bl, version) != 0) { + printf("failed!\n"); + rtas_args->args[rtas_args->nargs] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* check platform */ + printf("Checking platform : "); + if (check_platform(bl, 0x48, version) == -1) { + printf("failed!\n"); + rtas_args->args[rtas_args->nargs] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* checkcrc */ + printf("Checking CRC : "); + /* the actual CRC is included at the end of the flash image, thus the resulting CRC must be 0! */ + if (image_check_crc(bl, version) != 0) { + printf("failed!\n"); + rtas_args->args[1] = -3; /* bad image */ + return; + } + printf("succeeded!\n"); + + /* check if we are running on P + * if so, let's switch to temp and flash temp */ + if (bmc_get_flashside() == 0 && perm_check) { + printf("Set flashside: "); + bmc_set_flashside(1); + printf("Temp!\n"); + } + +#ifdef DEBUG + rtas_args_t ra; + ra.args[0] = 0x100; /* size; */ + ra.args[1] = flashOffset; + ra.nargs = 2; + + rtas_dump_flash(&ra); + printf("\n"); +#endif + + size = get_size(bl, version); + erase_size = (size + (FLASH_BLOCK_SIZE - 1)) & ~(FLASH_BLOCK_SIZE - 1); + dprintf("Erasing: size: %#x, erase_size: %#x, FLASH_BLOCK_SIZE: %#x\n", + size, erase_size, FLASH_BLOCK_SIZE); + + progress = size / 39; + printf("Erasing : 0x%08x", 0); + for (i = 0; i < erase_size; i += FLASH_BLOCK_SIZE) { + print_block(i); + erase_flash_block(i); + } + + enter_data_mode(); +#ifdef DEBUG + rtas_dump_flash(&ra); + printf("\n"); +#endif + print_writing(); + write_block_list(bl, version); + printf("\b#\n"); + enter_data_mode(); + +#ifdef DEBUG + rtas_dump_flash(&ra); + printf("\n"); +#endif + + /* checkcrc */ + printf("Recheck CRC : "); + if (check_flash_image(FLASH + flashOffset, size, 0) != 0) { + /* failed */ + printf("failed!\n\r"); + dprintf("flash_addr: %#x, flashOffset: %#x, size: %#x\n", FLASH, + flashOffset, size); + dprintf("crc: %#x\n", + check_flash_image(FLASH + flashOffset, size, 0)); + rtas_args->args[rtas_args->nargs] = -4; /* programming failed */ + return; + } + printf("succeeded!\n"); + rtas_args->args[rtas_args->nargs] = 0; +} + +/* + * Function: ibm_update_flash_64_and_reboot + * Input: + * r3: rtas parm structure + * token: 27 + * in: 1 + * out: 1 + * parm0: A real pointer to a block list + * Output: + * parm1: Status (hw -1, bad image -3, programming failed -4) + * Currently -4 and -1 are not returned + * + * Description: flash and reboot if addresses above 4GB have to be addressed + */ +void +rtas_ibm_update_flash_64_and_reboot(rtas_args_t *rtas_args) +{ + rtas_update_flash(rtas_args); + dprintf("rc: %#d\n", rtas_args->args[rtas_args->nargs]); + if (rtas_args->args[rtas_args->nargs] == 0) { + rtas_system_reboot(rtas_args); + } +} |