1 /* 2 * PS3 flash memory os area. 3 * 4 * Copyright (C) 2006 Sony Computer Entertainment Inc. 5 * Copyright 2006 Sony Corp. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #include <linux/kernel.h> 22 #include <linux/io.h> 23 #include <linux/workqueue.h> 24 #include <linux/fs.h> 25 #include <linux/syscalls.h> 26 27 #include <asm/lmb.h> 28 29 #include "platform.h" 30 31 enum { 32 OS_AREA_SEGMENT_SIZE = 0X200, 33 }; 34 35 enum os_area_ldr_format { 36 HEADER_LDR_FORMAT_RAW = 0, 37 HEADER_LDR_FORMAT_GZIP = 1, 38 }; 39 40 /** 41 * struct os_area_header - os area header segment. 42 * @magic_num: Always 'cell_ext_os_area'. 43 * @hdr_version: Header format version number. 44 * @db_area_offset: Starting segment number of other os database area. 45 * @ldr_area_offset: Starting segment number of bootloader image area. 46 * @ldr_format: HEADER_LDR_FORMAT flag. 47 * @ldr_size: Size of bootloader image in bytes. 48 * 49 * Note that the docs refer to area offsets. These are offsets in units of 50 * segments from the start of the os area (top of the header). These are 51 * better thought of as segment numbers. The os area of the os area is 52 * reserved for the os image. 53 */ 54 55 struct os_area_header { 56 u8 magic_num[16]; 57 u32 hdr_version; 58 u32 db_area_offset; 59 u32 ldr_area_offset; 60 u32 _reserved_1; 61 u32 ldr_format; 62 u32 ldr_size; 63 u32 _reserved_2[6]; 64 }; 65 66 enum os_area_boot_flag { 67 PARAM_BOOT_FLAG_GAME_OS = 0, 68 PARAM_BOOT_FLAG_OTHER_OS = 1, 69 }; 70 71 enum os_area_ctrl_button { 72 PARAM_CTRL_BUTTON_O_IS_YES = 0, 73 PARAM_CTRL_BUTTON_X_IS_YES = 1, 74 }; 75 76 /** 77 * struct os_area_params - os area params segment. 78 * @boot_flag: User preference of operating system, PARAM_BOOT_FLAG flag. 79 * @num_params: Number of params in this (params) segment. 80 * @rtc_diff: Difference in seconds between 1970 and the ps3 rtc value. 81 * @av_multi_out: User preference of AV output, PARAM_AV_MULTI_OUT flag. 82 * @ctrl_button: User preference of controller button config, PARAM_CTRL_BUTTON 83 * flag. 84 * @static_ip_addr: User preference of static IP address. 85 * @network_mask: User preference of static network mask. 86 * @default_gateway: User preference of static default gateway. 87 * @dns_primary: User preference of static primary dns server. 88 * @dns_secondary: User preference of static secondary dns server. 89 * 90 * The ps3 rtc maintains a read-only value that approximates seconds since 91 * 2000-01-01 00:00:00 UTC. 92 * 93 * User preference of zero for static_ip_addr means use dhcp. 94 */ 95 96 struct os_area_params { 97 u32 boot_flag; 98 u32 _reserved_1[3]; 99 u32 num_params; 100 u32 _reserved_2[3]; 101 /* param 0 */ 102 s64 rtc_diff; 103 u8 av_multi_out; 104 u8 ctrl_button; 105 u8 _reserved_3[6]; 106 /* param 1 */ 107 u8 static_ip_addr[4]; 108 u8 network_mask[4]; 109 u8 default_gateway[4]; 110 u8 _reserved_4[4]; 111 /* param 2 */ 112 u8 dns_primary[4]; 113 u8 dns_secondary[4]; 114 u8 _reserved_5[8]; 115 }; 116 117 enum { 118 OS_AREA_DB_MAGIC_NUM = 0x2d64622dU, 119 }; 120 121 /** 122 * struct os_area_db - Shared flash memory database. 123 * @magic_num: Always '-db-' = 0x2d64622d. 124 * @version: os_area_db format version number. 125 * @index_64: byte offset of the database id index for 64 bit variables. 126 * @count_64: number of usable 64 bit index entries 127 * @index_32: byte offset of the database id index for 32 bit variables. 128 * @count_32: number of usable 32 bit index entries 129 * @index_16: byte offset of the database id index for 16 bit variables. 130 * @count_16: number of usable 16 bit index entries 131 * 132 * Flash rom storage for exclusive use by guests running in the other os lpar. 133 * The current system configuration allocates 1K (two segments) for other os 134 * use. 135 */ 136 137 struct os_area_db { 138 u32 magic_num; 139 u16 version; 140 u16 _reserved_1; 141 u16 index_64; 142 u16 count_64; 143 u16 index_32; 144 u16 count_32; 145 u16 index_16; 146 u16 count_16; 147 u32 _reserved_2; 148 u8 _db_data[1000]; 149 }; 150 151 /** 152 * enum os_area_db_owner - Data owners. 153 */ 154 155 enum os_area_db_owner { 156 OS_AREA_DB_OWNER_ANY = -1, 157 OS_AREA_DB_OWNER_NONE = 0, 158 OS_AREA_DB_OWNER_PROTOTYPE = 1, 159 OS_AREA_DB_OWNER_LINUX = 2, 160 OS_AREA_DB_OWNER_PETITBOOT = 3, 161 OS_AREA_DB_OWNER_MAX = 32, 162 }; 163 164 enum os_area_db_key { 165 OS_AREA_DB_KEY_ANY = -1, 166 OS_AREA_DB_KEY_NONE = 0, 167 OS_AREA_DB_KEY_RTC_DIFF = 1, 168 OS_AREA_DB_KEY_VIDEO_MODE = 2, 169 OS_AREA_DB_KEY_MAX = 8, 170 }; 171 172 struct os_area_db_id { 173 int owner; 174 int key; 175 }; 176 177 static const struct os_area_db_id os_area_db_id_empty = { 178 .owner = OS_AREA_DB_OWNER_NONE, 179 .key = OS_AREA_DB_KEY_NONE 180 }; 181 182 static const struct os_area_db_id os_area_db_id_any = { 183 .owner = OS_AREA_DB_OWNER_ANY, 184 .key = OS_AREA_DB_KEY_ANY 185 }; 186 187 static const struct os_area_db_id os_area_db_id_rtc_diff = { 188 .owner = OS_AREA_DB_OWNER_LINUX, 189 .key = OS_AREA_DB_KEY_RTC_DIFF 190 }; 191 192 static const struct os_area_db_id os_area_db_id_video_mode = { 193 .owner = OS_AREA_DB_OWNER_LINUX, 194 .key = OS_AREA_DB_KEY_VIDEO_MODE 195 }; 196 197 #define SECONDS_FROM_1970_TO_2000 946684800LL 198 199 /** 200 * struct saved_params - Static working copies of data from the PS3 'os area'. 201 * 202 * The order of preference we use for the rtc_diff source: 203 * 1) The database value. 204 * 2) The game os value. 205 * 3) The number of seconds from 1970 to 2000. 206 */ 207 208 struct saved_params { 209 unsigned int valid; 210 s64 rtc_diff; 211 unsigned int av_multi_out; 212 } static saved_params; 213 214 static struct property property_rtc_diff = { 215 .name = "linux,rtc_diff", 216 .length = sizeof(saved_params.rtc_diff), 217 .value = &saved_params.rtc_diff, 218 }; 219 220 static struct property property_av_multi_out = { 221 .name = "linux,av_multi_out", 222 .length = sizeof(saved_params.av_multi_out), 223 .value = &saved_params.av_multi_out, 224 }; 225 226 /** 227 * os_area_set_property - Add or overwrite a saved_params value to the device tree. 228 * 229 * Overwrites an existing property. 230 */ 231 232 static void os_area_set_property(struct device_node *node, 233 struct property *prop) 234 { 235 int result; 236 struct property *tmp = of_find_property(node, prop->name, NULL); 237 238 if (tmp) { 239 pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name); 240 prom_remove_property(node, tmp); 241 } 242 243 result = prom_add_property(node, prop); 244 245 if (result) 246 pr_debug("%s:%d prom_set_property failed\n", __func__, 247 __LINE__); 248 } 249 250 /** 251 * os_area_get_property - Get a saved_params value from the device tree. 252 * 253 */ 254 255 static void __init os_area_get_property(struct device_node *node, 256 struct property *prop) 257 { 258 const struct property *tmp = of_find_property(node, prop->name, NULL); 259 260 if (tmp) { 261 BUG_ON(prop->length != tmp->length); 262 memcpy(prop->value, tmp->value, prop->length); 263 } else 264 pr_debug("%s:%d not found %s\n", __func__, __LINE__, 265 prop->name); 266 } 267 268 #define dump_header(_a) _dump_header(_a, __func__, __LINE__) 269 static void _dump_header(const struct os_area_header *h, const char *func, 270 int line) 271 { 272 pr_debug("%s:%d: h.magic_num: '%s'\n", func, line, 273 h->magic_num); 274 pr_debug("%s:%d: h.hdr_version: %u\n", func, line, 275 h->hdr_version); 276 pr_debug("%s:%d: h.db_area_offset: %u\n", func, line, 277 h->db_area_offset); 278 pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line, 279 h->ldr_area_offset); 280 pr_debug("%s:%d: h.ldr_format: %u\n", func, line, 281 h->ldr_format); 282 pr_debug("%s:%d: h.ldr_size: %xh\n", func, line, 283 h->ldr_size); 284 } 285 286 #define dump_params(_a) _dump_params(_a, __func__, __LINE__) 287 static void _dump_params(const struct os_area_params *p, const char *func, 288 int line) 289 { 290 pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag); 291 pr_debug("%s:%d: p.num_params: %u\n", func, line, p->num_params); 292 pr_debug("%s:%d: p.rtc_diff %ld\n", func, line, p->rtc_diff); 293 pr_debug("%s:%d: p.av_multi_out %u\n", func, line, p->av_multi_out); 294 pr_debug("%s:%d: p.ctrl_button: %u\n", func, line, p->ctrl_button); 295 pr_debug("%s:%d: p.static_ip_addr: %u.%u.%u.%u\n", func, line, 296 p->static_ip_addr[0], p->static_ip_addr[1], 297 p->static_ip_addr[2], p->static_ip_addr[3]); 298 pr_debug("%s:%d: p.network_mask: %u.%u.%u.%u\n", func, line, 299 p->network_mask[0], p->network_mask[1], 300 p->network_mask[2], p->network_mask[3]); 301 pr_debug("%s:%d: p.default_gateway: %u.%u.%u.%u\n", func, line, 302 p->default_gateway[0], p->default_gateway[1], 303 p->default_gateway[2], p->default_gateway[3]); 304 pr_debug("%s:%d: p.dns_primary: %u.%u.%u.%u\n", func, line, 305 p->dns_primary[0], p->dns_primary[1], 306 p->dns_primary[2], p->dns_primary[3]); 307 pr_debug("%s:%d: p.dns_secondary: %u.%u.%u.%u\n", func, line, 308 p->dns_secondary[0], p->dns_secondary[1], 309 p->dns_secondary[2], p->dns_secondary[3]); 310 } 311 312 static int verify_header(const struct os_area_header *header) 313 { 314 if (memcmp(header->magic_num, "cell_ext_os_area", 16)) { 315 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); 316 return -1; 317 } 318 319 if (header->hdr_version < 1) { 320 pr_debug("%s:%d hdr_version failed\n", __func__, __LINE__); 321 return -1; 322 } 323 324 if (header->db_area_offset > header->ldr_area_offset) { 325 pr_debug("%s:%d offsets failed\n", __func__, __LINE__); 326 return -1; 327 } 328 329 return 0; 330 } 331 332 static int db_verify(const struct os_area_db *db) 333 { 334 if (db->magic_num != OS_AREA_DB_MAGIC_NUM) { 335 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); 336 return -1; 337 } 338 339 if (db->version != 1) { 340 pr_debug("%s:%d version failed\n", __func__, __LINE__); 341 return -1; 342 } 343 344 return 0; 345 } 346 347 struct db_index { 348 uint8_t owner:5; 349 uint8_t key:3; 350 }; 351 352 struct db_iterator { 353 const struct os_area_db *db; 354 struct os_area_db_id match_id; 355 struct db_index *idx; 356 struct db_index *last_idx; 357 union { 358 uint64_t *value_64; 359 uint32_t *value_32; 360 uint16_t *value_16; 361 }; 362 }; 363 364 static unsigned int db_align_up(unsigned int val, unsigned int size) 365 { 366 return (val + (size - 1)) & (~(size - 1)); 367 } 368 369 /** 370 * db_for_each_64 - Iterator for 64 bit entries. 371 * 372 * A NULL value for id can be used to match all entries. 373 * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all. 374 */ 375 376 static int db_for_each_64(const struct os_area_db *db, 377 const struct os_area_db_id *match_id, struct db_iterator *i) 378 { 379 next: 380 if (!i->db) { 381 i->db = db; 382 i->match_id = match_id ? *match_id : os_area_db_id_any; 383 i->idx = (void *)db + db->index_64; 384 i->last_idx = i->idx + db->count_64; 385 i->value_64 = (void *)db + db->index_64 386 + db_align_up(db->count_64, 8); 387 } else { 388 i->idx++; 389 i->value_64++; 390 } 391 392 if (i->idx >= i->last_idx) { 393 pr_debug("%s:%d: reached end\n", __func__, __LINE__); 394 return 0; 395 } 396 397 if (i->match_id.owner != OS_AREA_DB_OWNER_ANY 398 && i->match_id.owner != (int)i->idx->owner) 399 goto next; 400 if (i->match_id.key != OS_AREA_DB_KEY_ANY 401 && i->match_id.key != (int)i->idx->key) 402 goto next; 403 404 return 1; 405 } 406 407 static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id) 408 { 409 struct db_iterator i; 410 411 for (i.db = NULL; db_for_each_64(db, id, &i); ) { 412 413 pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, 414 i.idx->owner, i.idx->key, 415 (unsigned long long)*i.value_64); 416 417 i.idx->owner = 0; 418 i.idx->key = 0; 419 *i.value_64 = 0; 420 } 421 return 0; 422 } 423 424 static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id, 425 uint64_t value) 426 { 427 struct db_iterator i; 428 429 pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__, 430 id->owner, id->key, (unsigned long long)value); 431 432 if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY 433 || id->key == OS_AREA_DB_KEY_ANY) { 434 pr_debug("%s:%d: bad id: (%d:%d)\n", __func__, 435 __LINE__, id->owner, id->key); 436 return -1; 437 } 438 439 db_delete_64(db, id); 440 441 i.db = NULL; 442 if (db_for_each_64(db, &os_area_db_id_empty, &i)) { 443 444 pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__, 445 i.idx->owner, i.idx->key, 446 (unsigned long long)*i.value_64); 447 448 i.idx->owner = id->owner; 449 i.idx->key = id->key; 450 *i.value_64 = value; 451 452 pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__, 453 i.idx->owner, i.idx->key, 454 (unsigned long long)*i.value_64); 455 return 0; 456 } 457 pr_debug("%s:%d: database full.\n", 458 __func__, __LINE__); 459 return -1; 460 } 461 462 static int db_get_64(const struct os_area_db *db, 463 const struct os_area_db_id *id, uint64_t *value) 464 { 465 struct db_iterator i; 466 467 i.db = NULL; 468 if (db_for_each_64(db, id, &i)) { 469 *value = *i.value_64; 470 pr_debug("%s:%d: found %lld\n", __func__, __LINE__, 471 (long long int)*i.value_64); 472 return 0; 473 } 474 pr_debug("%s:%d: not found\n", __func__, __LINE__); 475 return -1; 476 } 477 478 static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff) 479 { 480 return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff); 481 } 482 483 #define dump_db(a) _dump_db(a, __func__, __LINE__) 484 static void _dump_db(const struct os_area_db *db, const char *func, 485 int line) 486 { 487 pr_debug("%s:%d: db.magic_num: '%s'\n", func, line, 488 (const char*)&db->magic_num); 489 pr_debug("%s:%d: db.version: %u\n", func, line, 490 db->version); 491 pr_debug("%s:%d: db.index_64: %u\n", func, line, 492 db->index_64); 493 pr_debug("%s:%d: db.count_64: %u\n", func, line, 494 db->count_64); 495 pr_debug("%s:%d: db.index_32: %u\n", func, line, 496 db->index_32); 497 pr_debug("%s:%d: db.count_32: %u\n", func, line, 498 db->count_32); 499 pr_debug("%s:%d: db.index_16: %u\n", func, line, 500 db->index_16); 501 pr_debug("%s:%d: db.count_16: %u\n", func, line, 502 db->count_16); 503 } 504 505 static void os_area_db_init(struct os_area_db *db) 506 { 507 enum { 508 HEADER_SIZE = offsetof(struct os_area_db, _db_data), 509 INDEX_64_COUNT = 64, 510 VALUES_64_COUNT = 57, 511 INDEX_32_COUNT = 64, 512 VALUES_32_COUNT = 57, 513 INDEX_16_COUNT = 64, 514 VALUES_16_COUNT = 57, 515 }; 516 517 memset(db, 0, sizeof(struct os_area_db)); 518 519 db->magic_num = OS_AREA_DB_MAGIC_NUM; 520 db->version = 1; 521 db->index_64 = HEADER_SIZE; 522 db->count_64 = VALUES_64_COUNT; 523 db->index_32 = HEADER_SIZE 524 + INDEX_64_COUNT * sizeof(struct db_index) 525 + VALUES_64_COUNT * sizeof(u64); 526 db->count_32 = VALUES_32_COUNT; 527 db->index_16 = HEADER_SIZE 528 + INDEX_64_COUNT * sizeof(struct db_index) 529 + VALUES_64_COUNT * sizeof(u64) 530 + INDEX_32_COUNT * sizeof(struct db_index) 531 + VALUES_32_COUNT * sizeof(u32); 532 db->count_16 = VALUES_16_COUNT; 533 534 /* Rules to check db layout. */ 535 536 BUILD_BUG_ON(sizeof(struct db_index) != 1); 537 BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE); 538 BUILD_BUG_ON(INDEX_64_COUNT & 0x7); 539 BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT); 540 BUILD_BUG_ON(INDEX_32_COUNT & 0x7); 541 BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT); 542 BUILD_BUG_ON(INDEX_16_COUNT & 0x7); 543 BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT); 544 BUILD_BUG_ON(HEADER_SIZE 545 + INDEX_64_COUNT * sizeof(struct db_index) 546 + VALUES_64_COUNT * sizeof(u64) 547 + INDEX_32_COUNT * sizeof(struct db_index) 548 + VALUES_32_COUNT * sizeof(u32) 549 + INDEX_16_COUNT * sizeof(struct db_index) 550 + VALUES_16_COUNT * sizeof(u16) 551 > sizeof(struct os_area_db)); 552 } 553 554 /** 555 * update_flash_db - Helper for os_area_queue_work_handler. 556 * 557 */ 558 559 static void update_flash_db(void) 560 { 561 int result; 562 int file; 563 off_t offset; 564 ssize_t count; 565 static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; 566 const struct os_area_header *header; 567 struct os_area_db* db; 568 569 /* Read in header and db from flash. */ 570 571 file = sys_open("/dev/ps3flash", O_RDWR, 0); 572 573 if (file < 0) { 574 pr_debug("%s:%d sys_open failed\n", __func__, __LINE__); 575 goto fail_open; 576 } 577 578 header = kmalloc(buf_len, GFP_KERNEL); 579 580 if (!header) { 581 pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); 582 goto fail_malloc; 583 } 584 585 offset = sys_lseek(file, 0, SEEK_SET); 586 587 if (offset != 0) { 588 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); 589 goto fail_header_seek; 590 } 591 592 count = sys_read(file, (char __user *)header, buf_len); 593 594 result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) 595 || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; 596 597 if (result) { 598 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); 599 dump_header(header); 600 goto fail_header; 601 } 602 603 /* Now got a good db offset and some maybe good db data. */ 604 605 db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; 606 607 result = db_verify(db); 608 609 if (result) { 610 printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " 611 "formatting.\n", __func__, __LINE__); 612 dump_db(db); 613 os_area_db_init(db); 614 } 615 616 /* Now got good db data. */ 617 618 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); 619 620 offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, 621 SEEK_SET); 622 623 if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) { 624 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); 625 goto fail_db_seek; 626 } 627 628 count = sys_write(file, (const char __user *)db, 629 sizeof(struct os_area_db)); 630 631 if (count < sizeof(struct os_area_db)) { 632 pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); 633 } 634 635 fail_db_seek: 636 fail_header: 637 fail_header_seek: 638 kfree(header); 639 fail_malloc: 640 sys_close(file); 641 fail_open: 642 return; 643 } 644 645 /** 646 * os_area_queue_work_handler - Asynchronous write handler. 647 * 648 * An asynchronous write for flash memory and the device tree. Do not 649 * call directly, use os_area_queue_work(). 650 */ 651 652 static void os_area_queue_work_handler(struct work_struct *work) 653 { 654 struct device_node *node; 655 656 pr_debug(" -> %s:%d\n", __func__, __LINE__); 657 658 node = of_find_node_by_path("/"); 659 660 if (node) { 661 os_area_set_property(node, &property_rtc_diff); 662 of_node_put(node); 663 } else 664 pr_debug("%s:%d of_find_node_by_path failed\n", 665 __func__, __LINE__); 666 667 #if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) 668 update_flash_db(); 669 #else 670 printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", 671 __func__, __LINE__); 672 #endif 673 pr_debug(" <- %s:%d\n", __func__, __LINE__); 674 } 675 676 static void os_area_queue_work(void) 677 { 678 static DECLARE_WORK(q, os_area_queue_work_handler); 679 680 wmb(); 681 schedule_work(&q); 682 } 683 684 /** 685 * ps3_os_area_save_params - Copy data from os area mirror to @saved_params. 686 * 687 * For the convenience of the guest the HV makes a copy of the os area in 688 * flash to a high address in the boot memory region and then puts that RAM 689 * address and the byte count into the repository for retrieval by the guest. 690 * We copy the data we want into a static variable and allow the memory setup 691 * by the HV to be claimed by the lmb manager. 692 * 693 * The os area mirror will not be available to a second stage kernel, and 694 * the header verify will fail. In this case, the saved_params values will 695 * be set from flash memory or the passed in device tree in ps3_os_area_init(). 696 */ 697 698 void __init ps3_os_area_save_params(void) 699 { 700 int result; 701 u64 lpar_addr; 702 unsigned int size; 703 struct os_area_header *header; 704 struct os_area_params *params; 705 struct os_area_db *db; 706 707 pr_debug(" -> %s:%d\n", __func__, __LINE__); 708 709 result = ps3_repository_read_boot_dat_info(&lpar_addr, &size); 710 711 if (result) { 712 pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n", 713 __func__, __LINE__); 714 return; 715 } 716 717 header = (struct os_area_header *)__va(lpar_addr); 718 params = (struct os_area_params *)__va(lpar_addr 719 + OS_AREA_SEGMENT_SIZE); 720 721 result = verify_header(header); 722 723 if (result) { 724 /* Second stage kernels exit here. */ 725 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__); 726 dump_header(header); 727 return; 728 } 729 730 db = (struct os_area_db *)__va(lpar_addr 731 + header->db_area_offset * OS_AREA_SEGMENT_SIZE); 732 733 dump_header(header); 734 dump_params(params); 735 dump_db(db); 736 737 result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff); 738 if (result) 739 saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff 740 : SECONDS_FROM_1970_TO_2000; 741 saved_params.av_multi_out = params->av_multi_out; 742 saved_params.valid = 1; 743 744 memset(header, 0, sizeof(*header)); 745 746 pr_debug(" <- %s:%d\n", __func__, __LINE__); 747 } 748 749 /** 750 * ps3_os_area_init - Setup os area device tree properties as needed. 751 */ 752 753 void __init ps3_os_area_init(void) 754 { 755 struct device_node *node; 756 757 pr_debug(" -> %s:%d\n", __func__, __LINE__); 758 759 node = of_find_node_by_path("/"); 760 761 if (!saved_params.valid && node) { 762 /* Second stage kernels should have a dt entry. */ 763 os_area_get_property(node, &property_rtc_diff); 764 os_area_get_property(node, &property_av_multi_out); 765 } 766 767 if(!saved_params.rtc_diff) 768 saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000; 769 770 if (node) { 771 os_area_set_property(node, &property_rtc_diff); 772 os_area_set_property(node, &property_av_multi_out); 773 of_node_put(node); 774 } else 775 pr_debug("%s:%d of_find_node_by_path failed\n", 776 __func__, __LINE__); 777 778 pr_debug(" <- %s:%d\n", __func__, __LINE__); 779 } 780 781 /** 782 * ps3_os_area_get_rtc_diff - Returns the rtc diff value. 783 */ 784 785 u64 ps3_os_area_get_rtc_diff(void) 786 { 787 return saved_params.rtc_diff; 788 } 789 790 /** 791 * ps3_os_area_set_rtc_diff - Set the rtc diff value. 792 * 793 * An asynchronous write is needed to support writing updates from 794 * the timer interrupt context. 795 */ 796 797 void ps3_os_area_set_rtc_diff(u64 rtc_diff) 798 { 799 if (saved_params.rtc_diff != rtc_diff) { 800 saved_params.rtc_diff = rtc_diff; 801 os_area_queue_work(); 802 } 803 } 804 805 /** 806 * ps3_os_area_get_av_multi_out - Returns the default video mode. 807 */ 808 809 enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void) 810 { 811 return saved_params.av_multi_out; 812 } 813 EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out); 814