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