Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-js2x / rtas / rtas_flash.c
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 (file)
index 0000000..189878d
--- /dev/null
@@ -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);
+       }
+}