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