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