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