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