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