linux/arch/powerpc/platforms/powernv/opal-flash.c
<<
>>
Prefs
   1/*
   2 * PowerNV OPAL Firmware Update Interface
   3 *
   4 * Copyright 2013 IBM Corp.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#define DEBUG
  13
  14#include <linux/kernel.h>
  15#include <linux/reboot.h>
  16#include <linux/init.h>
  17#include <linux/kobject.h>
  18#include <linux/sysfs.h>
  19#include <linux/slab.h>
  20#include <linux/mm.h>
  21#include <linux/vmalloc.h>
  22#include <linux/pagemap.h>
  23#include <linux/delay.h>
  24
  25#include <asm/opal.h>
  26
  27/* FLASH status codes */
  28#define FLASH_NO_OP             -1099   /* No operation initiated by user */
  29#define FLASH_NO_AUTH           -9002   /* Not a service authority partition */
  30
  31/* Validate image status values */
  32#define VALIDATE_IMG_READY      -1001   /* Image ready for validation */
  33#define VALIDATE_IMG_INCOMPLETE -1002   /* User copied < VALIDATE_BUF_SIZE */
  34
  35/* Manage image status values */
  36#define MANAGE_ACTIVE_ERR       -9001   /* Cannot overwrite active img */
  37
  38/* Flash image status values */
  39#define FLASH_IMG_READY         0       /* Img ready for flash on reboot */
  40#define FLASH_INVALID_IMG       -1003   /* Flash image shorter than expected */
  41#define FLASH_IMG_NULL_DATA     -1004   /* Bad data in sg list entry */
  42#define FLASH_IMG_BAD_LEN       -1005   /* Bad length in sg list entry */
  43
  44/* Manage operation tokens */
  45#define FLASH_REJECT_TMP_SIDE   0       /* Reject temporary fw image */
  46#define FLASH_COMMIT_TMP_SIDE   1       /* Commit temporary fw image */
  47
  48/* Update tokens */
  49#define FLASH_UPDATE_CANCEL     0       /* Cancel update request */
  50#define FLASH_UPDATE_INIT       1       /* Initiate update */
  51
  52/* Validate image update result tokens */
  53#define VALIDATE_TMP_UPDATE     0     /* T side will be updated */
  54#define VALIDATE_FLASH_AUTH     1     /* Partition does not have authority */
  55#define VALIDATE_INVALID_IMG    2     /* Candidate image is not valid */
  56#define VALIDATE_CUR_UNKNOWN    3     /* Current fixpack level is unknown */
  57/*
  58 * Current T side will be committed to P side before being replace with new
  59 * image, and the new image is downlevel from current image
  60 */
  61#define VALIDATE_TMP_COMMIT_DL  4
  62/*
  63 * Current T side will be committed to P side before being replaced with new
  64 * image
  65 */
  66#define VALIDATE_TMP_COMMIT     5
  67/*
  68 * T side will be updated with a downlevel image
  69 */
  70#define VALIDATE_TMP_UPDATE_DL  6
  71/*
  72 * The candidate image's release date is later than the system's firmware
  73 * service entitlement date - service warranty period has expired
  74 */
  75#define VALIDATE_OUT_OF_WRNTY   7
  76
  77/* Validate buffer size */
  78#define VALIDATE_BUF_SIZE       4096
  79
  80/* XXX: Assume candidate image size is <= 1GB */
  81#define MAX_IMAGE_SIZE  0x40000000
  82
  83/* Image status */
  84enum {
  85        IMAGE_INVALID,
  86        IMAGE_LOADING,
  87        IMAGE_READY,
  88};
  89
  90/* Candidate image data */
  91struct image_data_t {
  92        int             status;
  93        void            *data;
  94        uint32_t        size;
  95};
  96
  97/* Candidate image header */
  98struct image_header_t {
  99        uint16_t        magic;
 100        uint16_t        version;
 101        uint32_t        size;
 102};
 103
 104struct validate_flash_t {
 105        int             status;         /* Return status */
 106        void            *buf;           /* Candidate image buffer */
 107        uint32_t        buf_size;       /* Image size */
 108        uint32_t        result;         /* Update results token */
 109};
 110
 111struct manage_flash_t {
 112        int status;             /* Return status */
 113};
 114
 115struct update_flash_t {
 116        int status;             /* Return status */
 117};
 118
 119static struct image_header_t    image_header;
 120static struct image_data_t      image_data;
 121static struct validate_flash_t  validate_flash_data;
 122static struct manage_flash_t    manage_flash_data;
 123
 124/* Initialize update_flash_data status to No Operation */
 125static struct update_flash_t    update_flash_data = {
 126        .status = FLASH_NO_OP,
 127};
 128
 129static DEFINE_MUTEX(image_data_mutex);
 130
 131/*
 132 * Validate candidate image
 133 */
 134static inline void opal_flash_validate(void)
 135{
 136        long ret;
 137        void *buf = validate_flash_data.buf;
 138        __be32 size = cpu_to_be32(validate_flash_data.buf_size);
 139        __be32 result;
 140
 141        ret = opal_validate_flash(__pa(buf), &size, &result);
 142
 143        validate_flash_data.status = ret;
 144        validate_flash_data.buf_size = be32_to_cpu(size);
 145        validate_flash_data.result = be32_to_cpu(result);
 146}
 147
 148/*
 149 * Validate output format:
 150 *     validate result token
 151 *     current image version details
 152 *     new image version details
 153 */
 154static ssize_t validate_show(struct kobject *kobj,
 155                             struct kobj_attribute *attr, char *buf)
 156{
 157        struct validate_flash_t *args_buf = &validate_flash_data;
 158        int len;
 159
 160        /* Candidate image is not validated */
 161        if (args_buf->status < VALIDATE_TMP_UPDATE) {
 162                len = sprintf(buf, "%d\n", args_buf->status);
 163                goto out;
 164        }
 165
 166        /* Result token */
 167        len = sprintf(buf, "%d\n", args_buf->result);
 168
 169        /* Current and candidate image version details */
 170        if ((args_buf->result != VALIDATE_TMP_UPDATE) &&
 171            (args_buf->result < VALIDATE_CUR_UNKNOWN))
 172                goto out;
 173
 174        if (args_buf->buf_size > (VALIDATE_BUF_SIZE - len)) {
 175                memcpy(buf + len, args_buf->buf, VALIDATE_BUF_SIZE - len);
 176                len = VALIDATE_BUF_SIZE;
 177        } else {
 178                memcpy(buf + len, args_buf->buf, args_buf->buf_size);
 179                len += args_buf->buf_size;
 180        }
 181out:
 182        /* Set status to default */
 183        args_buf->status = FLASH_NO_OP;
 184        return len;
 185}
 186
 187/*
 188 * Validate candidate firmware image
 189 *
 190 * Note:
 191 *   We are only interested in first 4K bytes of the
 192 *   candidate image.
 193 */
 194static ssize_t validate_store(struct kobject *kobj,
 195                              struct kobj_attribute *attr,
 196                              const char *buf, size_t count)
 197{
 198        struct validate_flash_t *args_buf = &validate_flash_data;
 199
 200        if (buf[0] != '1')
 201                return -EINVAL;
 202
 203        mutex_lock(&image_data_mutex);
 204
 205        if (image_data.status != IMAGE_READY ||
 206            image_data.size < VALIDATE_BUF_SIZE) {
 207                args_buf->result = VALIDATE_INVALID_IMG;
 208                args_buf->status = VALIDATE_IMG_INCOMPLETE;
 209                goto out;
 210        }
 211
 212        /* Copy first 4k bytes of candidate image */
 213        memcpy(args_buf->buf, image_data.data, VALIDATE_BUF_SIZE);
 214
 215        args_buf->status = VALIDATE_IMG_READY;
 216        args_buf->buf_size = VALIDATE_BUF_SIZE;
 217
 218        /* Validate candidate image */
 219        opal_flash_validate();
 220
 221out:
 222        mutex_unlock(&image_data_mutex);
 223        return count;
 224}
 225
 226/*
 227 * Manage flash routine
 228 */
 229static inline void opal_flash_manage(uint8_t op)
 230{
 231        struct manage_flash_t *const args_buf = &manage_flash_data;
 232
 233        args_buf->status = opal_manage_flash(op);
 234}
 235
 236/*
 237 * Show manage flash status
 238 */
 239static ssize_t manage_show(struct kobject *kobj,
 240                           struct kobj_attribute *attr, char *buf)
 241{
 242        struct manage_flash_t *const args_buf = &manage_flash_data;
 243        int rc;
 244
 245        rc = sprintf(buf, "%d\n", args_buf->status);
 246        /* Set status to default*/
 247        args_buf->status = FLASH_NO_OP;
 248        return rc;
 249}
 250
 251/*
 252 * Manage operations:
 253 *   0 - Reject
 254 *   1 - Commit
 255 */
 256static ssize_t manage_store(struct kobject *kobj,
 257                            struct kobj_attribute *attr,
 258                            const char *buf, size_t count)
 259{
 260        uint8_t op;
 261        switch (buf[0]) {
 262        case '0':
 263                op = FLASH_REJECT_TMP_SIDE;
 264                break;
 265        case '1':
 266                op = FLASH_COMMIT_TMP_SIDE;
 267                break;
 268        default:
 269                return -EINVAL;
 270        }
 271
 272        /* commit/reject temporary image */
 273        opal_flash_manage(op);
 274        return count;
 275}
 276
 277/*
 278 * OPAL update flash
 279 */
 280static int opal_flash_update(int op)
 281{
 282        struct opal_sg_list *list;
 283        unsigned long addr;
 284        int64_t rc = OPAL_PARAMETER;
 285
 286        if (op == FLASH_UPDATE_CANCEL) {
 287                pr_alert("FLASH: Image update cancelled\n");
 288                addr = '\0';
 289                goto flash;
 290        }
 291
 292        list = opal_vmalloc_to_sg_list(image_data.data, image_data.size);
 293        if (!list)
 294                goto invalid_img;
 295
 296        /* First entry address */
 297        addr = __pa(list);
 298
 299flash:
 300        rc = opal_update_flash(addr);
 301
 302invalid_img:
 303        return rc;
 304}
 305
 306/* This gets called just before system reboots */
 307void opal_flash_update_print_message(void)
 308{
 309        if (update_flash_data.status != FLASH_IMG_READY)
 310                return;
 311
 312        pr_alert("FLASH: Flashing new firmware\n");
 313        pr_alert("FLASH: Image is %u bytes\n", image_data.size);
 314        pr_alert("FLASH: Performing flash and reboot/shutdown\n");
 315        pr_alert("FLASH: This will take several minutes. Do not power off!\n");
 316
 317        /* Small delay to help getting the above message out */
 318        msleep(500);
 319}
 320
 321/*
 322 * Show candidate image status
 323 */
 324static ssize_t update_show(struct kobject *kobj,
 325                           struct kobj_attribute *attr, char *buf)
 326{
 327        struct update_flash_t *const args_buf = &update_flash_data;
 328        return sprintf(buf, "%d\n", args_buf->status);
 329}
 330
 331/*
 332 * Set update image flag
 333 *  1 - Flash new image
 334 *  0 - Cancel flash request
 335 */
 336static ssize_t update_store(struct kobject *kobj,
 337                            struct kobj_attribute *attr,
 338                            const char *buf, size_t count)
 339{
 340        struct update_flash_t *const args_buf = &update_flash_data;
 341        int rc = count;
 342
 343        mutex_lock(&image_data_mutex);
 344
 345        switch (buf[0]) {
 346        case '0':
 347                if (args_buf->status == FLASH_IMG_READY)
 348                        opal_flash_update(FLASH_UPDATE_CANCEL);
 349                args_buf->status = FLASH_NO_OP;
 350                break;
 351        case '1':
 352                /* Image is loaded? */
 353                if (image_data.status == IMAGE_READY)
 354                        args_buf->status =
 355                                opal_flash_update(FLASH_UPDATE_INIT);
 356                else
 357                        args_buf->status = FLASH_INVALID_IMG;
 358                break;
 359        default:
 360                rc = -EINVAL;
 361        }
 362
 363        mutex_unlock(&image_data_mutex);
 364        return rc;
 365}
 366
 367/*
 368 * Free image buffer
 369 */
 370static void free_image_buf(void)
 371{
 372        void *addr;
 373        int size;
 374
 375        addr = image_data.data;
 376        size = PAGE_ALIGN(image_data.size);
 377        while (size > 0) {
 378                ClearPageReserved(vmalloc_to_page(addr));
 379                addr += PAGE_SIZE;
 380                size -= PAGE_SIZE;
 381        }
 382        vfree(image_data.data);
 383        image_data.data = NULL;
 384        image_data.status = IMAGE_INVALID;
 385}
 386
 387/*
 388 * Allocate image buffer.
 389 */
 390static int alloc_image_buf(char *buffer, size_t count)
 391{
 392        void *addr;
 393        int size;
 394
 395        if (count < sizeof(image_header)) {
 396                pr_warn("FLASH: Invalid candidate image\n");
 397                return -EINVAL;
 398        }
 399
 400        memcpy(&image_header, (void *)buffer, sizeof(image_header));
 401        image_data.size = be32_to_cpu(image_header.size);
 402        pr_debug("FLASH: Candidate image size = %u\n", image_data.size);
 403
 404        if (image_data.size > MAX_IMAGE_SIZE) {
 405                pr_warn("FLASH: Too large image\n");
 406                return -EINVAL;
 407        }
 408        if (image_data.size < VALIDATE_BUF_SIZE) {
 409                pr_warn("FLASH: Image is shorter than expected\n");
 410                return -EINVAL;
 411        }
 412
 413        image_data.data = vzalloc(PAGE_ALIGN(image_data.size));
 414        if (!image_data.data) {
 415                pr_err("%s : Failed to allocate memory\n", __func__);
 416                return -ENOMEM;
 417        }
 418
 419        /* Pin memory */
 420        addr = image_data.data;
 421        size = PAGE_ALIGN(image_data.size);
 422        while (size > 0) {
 423                SetPageReserved(vmalloc_to_page(addr));
 424                addr += PAGE_SIZE;
 425                size -= PAGE_SIZE;
 426        }
 427
 428        image_data.status = IMAGE_LOADING;
 429        return 0;
 430}
 431
 432/*
 433 * Copy candidate image
 434 *
 435 * Parse candidate image header to get total image size
 436 * and pre-allocate required memory.
 437 */
 438static ssize_t image_data_write(struct file *filp, struct kobject *kobj,
 439                                struct bin_attribute *bin_attr,
 440                                char *buffer, loff_t pos, size_t count)
 441{
 442        int rc;
 443
 444        mutex_lock(&image_data_mutex);
 445
 446        /* New image ? */
 447        if (pos == 0) {
 448                /* Free memory, if already allocated */
 449                if (image_data.data)
 450                        free_image_buf();
 451
 452                /* Cancel outstanding image update request */
 453                if (update_flash_data.status == FLASH_IMG_READY)
 454                        opal_flash_update(FLASH_UPDATE_CANCEL);
 455
 456                /* Allocate memory */
 457                rc = alloc_image_buf(buffer, count);
 458                if (rc)
 459                        goto out;
 460        }
 461
 462        if (image_data.status != IMAGE_LOADING) {
 463                rc = -ENOMEM;
 464                goto out;
 465        }
 466
 467        if ((pos + count) > image_data.size) {
 468                rc = -EINVAL;
 469                goto out;
 470        }
 471
 472        memcpy(image_data.data + pos, (void *)buffer, count);
 473        rc = count;
 474
 475        /* Set image status */
 476        if ((pos + count) == image_data.size) {
 477                pr_debug("FLASH: Candidate image loaded....\n");
 478                image_data.status = IMAGE_READY;
 479        }
 480
 481out:
 482        mutex_unlock(&image_data_mutex);
 483        return rc;
 484}
 485
 486/*
 487 * sysfs interface :
 488 *  OPAL uses below sysfs files for code update.
 489 *  We create these files under /sys/firmware/opal.
 490 *
 491 *   image              : Interface to load candidate firmware image
 492 *   validate_flash     : Validate firmware image
 493 *   manage_flash       : Commit/Reject firmware image
 494 *   update_flash       : Flash new firmware image
 495 *
 496 */
 497static const struct bin_attribute image_data_attr = {
 498        .attr = {.name = "image", .mode = 0200},
 499        .size = MAX_IMAGE_SIZE, /* Limit image size */
 500        .write = image_data_write,
 501};
 502
 503static struct kobj_attribute validate_attribute =
 504        __ATTR(validate_flash, 0600, validate_show, validate_store);
 505
 506static struct kobj_attribute manage_attribute =
 507        __ATTR(manage_flash, 0600, manage_show, manage_store);
 508
 509static struct kobj_attribute update_attribute =
 510        __ATTR(update_flash, 0600, update_show, update_store);
 511
 512static struct attribute *image_op_attrs[] = {
 513        &validate_attribute.attr,
 514        &manage_attribute.attr,
 515        &update_attribute.attr,
 516        NULL    /* need to NULL terminate the list of attributes */
 517};
 518
 519static struct attribute_group image_op_attr_group = {
 520        .attrs = image_op_attrs,
 521};
 522
 523void __init opal_flash_update_init(void)
 524{
 525        int ret;
 526
 527        /* Allocate validate image buffer */
 528        validate_flash_data.buf = kzalloc(VALIDATE_BUF_SIZE, GFP_KERNEL);
 529        if (!validate_flash_data.buf) {
 530                pr_err("%s : Failed to allocate memory\n", __func__);
 531                return;
 532        }
 533
 534        /* Make sure /sys/firmware/opal directory is created */
 535        if (!opal_kobj) {
 536                pr_warn("FLASH: opal kobject is not available\n");
 537                goto nokobj;
 538        }
 539
 540        /* Create the sysfs files */
 541        ret = sysfs_create_group(opal_kobj, &image_op_attr_group);
 542        if (ret) {
 543                pr_warn("FLASH: Failed to create sysfs files\n");
 544                goto nokobj;
 545        }
 546
 547        ret = sysfs_create_bin_file(opal_kobj, &image_data_attr);
 548        if (ret) {
 549                pr_warn("FLASH: Failed to create sysfs files\n");
 550                goto nosysfs_file;
 551        }
 552
 553        /* Set default status */
 554        validate_flash_data.status = FLASH_NO_OP;
 555        manage_flash_data.status = FLASH_NO_OP;
 556        update_flash_data.status = FLASH_NO_OP;
 557        image_data.status = IMAGE_INVALID;
 558        return;
 559
 560nosysfs_file:
 561        sysfs_remove_group(opal_kobj, &image_op_attr_group);
 562
 563nokobj:
 564        kfree(validate_flash_data.buf);
 565        return;
 566}
 567