[patch 0/6] PS3 os area patches for 2.6.24

STALE6912d

24 messages, 4 authors, 2007-10-09 · open the first message on its own page

[patch 0/6] PS3 os area patches for 2.6.24

From: <hidden>
Date: 2007-10-06 21:38:17

Paul,

This is a small set of patches that reworks and improves
the 'other os' area of the PS3's flash rom.

Please apply for 2.6.24.

-Geoff


-- 

[patch 5/6] PS3: Save os-area params to device tree

From: <hidden>
Date: 2007-10-06 21:38:17

Add the PS3 os-area startup params to the device tree.  This allows
a second stage kernel loaded with kexec to use these values.

Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c  |  104 +++++++++++++++++++++++++++++++++-
 arch/powerpc/platforms/ps3/platform.h |    1 
 arch/powerpc/platforms/ps3/setup.c    |    1 
 3 files changed, 104 insertions(+), 2 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -119,10 +119,65 @@ struct os_area_params {
  */
 
 struct saved_params {
+	unsigned int valid;
 	s64 rtc_diff;
 	unsigned int av_multi_out;
 } static saved_params;
 
+static struct property property_rtc_diff = {
+	.name = "linux,rtc_diff",
+	.length = sizeof(saved_params.rtc_diff),
+	.value = &saved_params.rtc_diff,
+};
+
+static struct property property_av_multi_out = {
+	.name = "linux,av_multi_out",
+	.length = sizeof(saved_params.av_multi_out),
+	.value = &saved_params.av_multi_out,
+};
+
+/**
+ * os_area_set_property - Add or overwrite a saved_params value to the device tree.
+ *
+ * Overwrites an existing property.
+ */
+
+static void os_area_set_property(struct device_node *node,
+	struct property *prop)
+{
+	int result;
+	struct property *tmp = of_find_property(node, prop->name, NULL);
+
+	if (tmp) {
+		pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name);
+		prom_remove_property(node, tmp);
+	}
+
+	result = prom_add_property(node, prop);
+
+	if (result)
+		pr_debug("%s:%d prom_set_property failed\n", __func__,
+			__LINE__);
+}
+
+/**
+ * os_area_get_property - Get a saved_params value from the device tree.
+ *
+ */
+
+static void __init os_area_get_property(struct device_node *node,
+	struct property *prop)
+{
+	const struct property *tmp = of_find_property(node, prop->name, NULL);
+
+	if (tmp) {
+		BUG_ON(prop->length != tmp->length);
+		memcpy(prop->value, tmp->value, prop->length);
+	} else
+		pr_debug("%s:%d not found %s\n", __func__, __LINE__,
+			prop->name);
+}
+
 #define dump_header(_a) _dump_header(_a, __func__, __LINE__)
 static void _dump_header(const struct os_area_header *h, const char *func,
 	int line)
@@ -196,8 +251,19 @@ static int __init verify_header(const st
 
 static void os_area_queue_work_handler(struct work_struct *work)
 {
+	struct device_node *node;
+
 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
 
+	node = of_find_node_by_path("/");
+
+	if (node) {
+		os_area_set_property(node, &property_rtc_diff);
+		of_node_put(node);
+	} else
+		pr_debug("%s:%d of_find_node_by_path failed\n",
+			__func__, __LINE__);
+
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
@@ -244,6 +310,8 @@ void __init ps3_os_area_save_params(void
 	result = verify_header(header);
 
 	if (result) {
+		/* Second stage kernels exit here. */
+
 		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
 		dump_header(header);
 		return;
@@ -254,6 +322,7 @@ void __init ps3_os_area_save_params(void
 
 	saved_params.rtc_diff = params->rtc_diff;
 	saved_params.av_multi_out = params->av_multi_out;
+	saved_params.valid = 1;
 
 	memset(header, 0, sizeof(*header));
 
@@ -261,13 +330,44 @@ void __init ps3_os_area_save_params(void
 }
 
 /**
+ * ps3_os_area_init - Setup os area device tree properties as needed.
+ */
+
+void __init ps3_os_area_init(void)
+{
+	struct device_node *node;
+
+	pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+	node = of_find_node_by_path("/");
+
+	if (!saved_params.valid && node) {
+		/* Second stage kernels should have a dt entry. */
+		os_area_get_property(node, &property_rtc_diff);
+		os_area_get_property(node, &property_av_multi_out);
+	}
+
+	if(!saved_params.rtc_diff)
+		saved_params.rtc_diff = SECONDS_FROM_1970_TO_2000;
+
+	if (node) {
+		os_area_set_property(node, &property_rtc_diff);
+		os_area_set_property(node, &property_av_multi_out);
+		of_node_put(node);
+	} else
+		pr_debug("%s:%d of_find_node_by_path failed\n",
+			__func__, __LINE__);
+
+	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+}
+
+/**
  * ps3_os_area_get_rtc_diff - Returns the rtc diff value.
  */
 
 u64 ps3_os_area_get_rtc_diff(void)
 {
-	return saved_params.rtc_diff ? saved_params.rtc_diff
-		: SECONDS_FROM_1970_TO_2000;
+	return saved_params.rtc_diff;
 }
 
 /**
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -63,6 +63,7 @@ int ps3_set_rtc_time(struct rtc_time *ti
 /* os area */
 
 void __init ps3_os_area_save_params(void);
+void __init ps3_os_area_init(void);
 u64 ps3_os_area_get_rtc_diff(void);
 void ps3_os_area_set_rtc_diff(u64 rtc_diff);
 
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -206,6 +206,7 @@ static void __init ps3_setup_arch(void)
 	prealloc_ps3flash_bounce_buffer();
 
 	ppc_md.power_save = ps3_power_save;
+	ps3_os_area_init();
 
 	DBG(" <- %s:%d\n", __func__, __LINE__);
 }
-- 

[patch 1/6] PS3: Cleanup of os-area.c

From: <hidden>
Date: 2007-10-06 21:38:17

Minor cleanup of the PS3 file os-area.c:
 o Correct file text header.
 o Add type names enum os_area_ldr_format, enum os_area_boot_flag,
   enum os_area_ctrl_button.
 o Change struct os_area_header.magic_num type to u8.
 o Add preprocessor macro SECONDS_FROM_1970_TO_2000.

Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c |   27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -1,5 +1,5 @@
 /*
- *  PS3 'Other OS' area data.
+ *  PS3 flash memory os area.
  *
  *  Copyright (C) 2006 Sony Computer Entertainment Inc.
  *  Copyright 2006 Sony Corp.
@@ -29,7 +29,7 @@ enum {
 	OS_AREA_SEGMENT_SIZE = 0X200,
 };
 
-enum {
+enum os_area_ldr_format {
 	HEADER_LDR_FORMAT_RAW = 0,
 	HEADER_LDR_FORMAT_GZIP = 1,
 };
@@ -50,7 +50,7 @@ enum {
  */
 
 struct os_area_header {
-	s8 magic_num[16];
+	u8 magic_num[16];
 	u32 hdr_version;
 	u32 os_area_offset;
 	u32 ldr_area_offset;
@@ -60,12 +60,12 @@ struct os_area_header {
 	u32 _reserved_2[6];
 };
 
-enum {
+enum os_area_boot_flag {
 	PARAM_BOOT_FLAG_GAME_OS = 0,
 	PARAM_BOOT_FLAG_OTHER_OS = 1,
 };
 
-enum {
+enum os_area_ctrl_button {
 	PARAM_CTRL_BUTTON_O_IS_YES = 0,
 	PARAM_CTRL_BUTTON_X_IS_YES = 1,
 };
@@ -84,6 +84,9 @@ enum {
  * @dns_primary: User preference of static primary dns server.
  * @dns_secondary: User preference of static secondary dns server.
  *
+ * The ps3 rtc maintains a read-only value that approximates seconds since
+ * 2000-01-01 00:00:00 UTC.
+ *
  * User preference of zero for static_ip_addr means use dhcp.
  */
 
@@ -108,6 +111,8 @@ struct os_area_params {
 	u8 _reserved_5[8];
 };
 
+#define SECONDS_FROM_1970_TO_2000 946684800LL
+
 /**
  * struct saved_params - Static working copies of data from the 'Other OS' area.
  *
@@ -213,7 +218,8 @@ int __init ps3_os_area_init(void)
 	}
 
 	header = (struct os_area_header *)__va(lpar_addr);
-	params = (struct os_area_params *)__va(lpar_addr + OS_AREA_SEGMENT_SIZE);
+	params = (struct os_area_params *)__va(lpar_addr
+		+ OS_AREA_SEGMENT_SIZE);
 
 	result = verify_header(header);
 
@@ -238,16 +244,13 @@ int __init ps3_os_area_init(void)
 }
 
 /**
- * ps3_os_area_rtc_diff - Returns the ps3 rtc diff value.
- *
- * The ps3 rtc maintains a value that approximates seconds since
- * 2000-01-01 00:00:00 UTC.  Returns the exact number of seconds from 1970 to
- * 2000 when saved_params.rtc_diff has not been properly set up.
+ * ps3_os_area_rtc_diff - Returns the rtc diff value.
  */
 
 u64 ps3_os_area_rtc_diff(void)
 {
-	return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
+	return saved_params.rtc_diff ? saved_params.rtc_diff
+		: SECONDS_FROM_1970_TO_2000;
 }
 
 /**
-- 

[patch 2/6] PS3: Remove unused os-area params

From: <hidden>
Date: 2007-10-06 21:38:17

Updates for PS3 os-area startup params
o Remove some unused PS3 os-area startup params from struct saved_params.
o Rename ps3_os_area_init() to ps3_os_area_save_params().
o Zero mirrored header after saving params.

Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c  |   44 ++++++++++++++--------------------
 arch/powerpc/platforms/ps3/platform.h |    2 -
 arch/powerpc/platforms/ps3/setup.c    |    2 -
 3 files changed, 21 insertions(+), 27 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -114,27 +114,12 @@ struct os_area_params {
 #define SECONDS_FROM_1970_TO_2000 946684800LL
 
 /**
- * struct saved_params - Static working copies of data from the 'Other OS' area.
- *
- * For the convinience of the guest, the HV makes a copy of the 'Other OS' area
- * in flash to a high address in the boot memory region and then puts that RAM
- * address and the byte count into the repository for retreval by the guest.
- * We copy the data we want into a static variable and allow the memory setup
- * by the HV to be claimed by the lmb manager.
+ * struct saved_params - Static working copies of data from the PS3 'os area'.
  */
 
 struct saved_params {
-	/* param 0 */
 	s64 rtc_diff;
 	unsigned int av_multi_out;
-	unsigned int ctrl_button;
-	/* param 1 */
-	u8 static_ip_addr[4];
-	u8 network_mask[4];
-	u8 default_gateway[4];
-	/* param 2 */
-	u8 dns_primary[4];
-	u8 dns_secondary[4];
 } static saved_params;
 
 #define dump_header(_a) _dump_header(_a, __func__, __LINE__)
@@ -201,7 +186,17 @@ static int __init verify_header(const st
 	return 0;
 }
 
-int __init ps3_os_area_init(void)
+/**
+ * ps3_os_area_save_params - Copy data from os area mirror to @saved_params.
+ *
+ * For the convenience of the guest, the HV makes a copy of the os area in
+ * flash to a high address in the boot memory region and then puts that RAM
+ * address and the byte count into the repository for retreval by the guest.
+ * We copy the data we want into a static variable and allow the memory setup
+ * by the HV to be claimed by the lmb manager.
+ */
+
+void __init ps3_os_area_save_params(void)
 {
 	int result;
 	u64 lpar_addr;
@@ -209,12 +204,14 @@ int __init ps3_os_area_init(void)
 	struct os_area_header *header;
 	struct os_area_params *params;
 
+	pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
 	result = ps3_repository_read_boot_dat_info(&lpar_addr, &size);
 
 	if (result) {
 		pr_debug("%s:%d ps3_repository_read_boot_dat_info failed\n",
 			__func__, __LINE__);
-		return result;
+		return;
 	}
 
 	header = (struct os_area_header *)__va(lpar_addr);
@@ -226,7 +223,7 @@ int __init ps3_os_area_init(void)
 	if (result) {
 		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
 		dump_header(header);
-		return -EIO;
+		return;
 	}
 
 	dump_header(header);
@@ -234,13 +231,10 @@ int __init ps3_os_area_init(void)
 
 	saved_params.rtc_diff = params->rtc_diff;
 	saved_params.av_multi_out = params->av_multi_out;
-	saved_params.ctrl_button = params->ctrl_button;
-	memcpy(saved_params.static_ip_addr, params->static_ip_addr, 4);
-	memcpy(saved_params.network_mask, params->network_mask, 4);
-	memcpy(saved_params.default_gateway, params->default_gateway, 4);
-	memcpy(saved_params.dns_secondary, params->dns_secondary, 4);
 
-	return result;
+	memset(header, 0, sizeof(*header));
+
+	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
 /**
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -62,7 +62,7 @@ int ps3_set_rtc_time(struct rtc_time *ti
 
 /* os area */
 
-int __init ps3_os_area_init(void);
+void __init ps3_os_area_save_params(void);
 u64 ps3_os_area_rtc_diff(void);
 
 /* spu */
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -228,7 +228,7 @@ static int __init ps3_probe(void)
 
 	powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE;
 
-	ps3_os_area_init();
+	ps3_os_area_save_params();
 	ps3_mm_init();
 	ps3_mm_vas_create(&htab_size);
 	ps3_hpte_init(htab_size);
-- 

[patch 3/6] PS3: os-area workqueue processing

From: <hidden>
Date: 2007-10-06 21:38:17

Add a workqueue to the PS3 os-area support.  This is needed to
support writing updates to flash memory and to update the /proc
device tree entries from the timer tick interrupt context.

Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/io.h>
+#include <linux/workqueue.h>
 
 #include <asm/lmb.h>
 
@@ -187,6 +188,28 @@ static int __init verify_header(const st
 }
 
 /**
+ * os_area_queue_work_handler - Asynchronous write handler.
+ *
+ * An asynchronous write for flash memory and the device tree.  Do not
+ * call directly, use os_area_queue_work().
+ */
+
+static void os_area_queue_work_handler(struct work_struct *work)
+{
+	pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+}
+
+static void os_area_queue_work(void)
+{
+	static DECLARE_WORK(q, os_area_queue_work_handler);
+
+	wmb();
+	schedule_work(&q);
+}
+
+/**
  * ps3_os_area_save_params - Copy data from os area mirror to @saved_params.
  *
  * For the convenience of the guest, the HV makes a copy of the os area in
-- 

[patch 6/6] PS3: Add os-area database routines

From: <hidden>
Date: 2007-10-06 21:38:20

Add support for a simple tagged database in the PS3 flash rom
os-area.  The database allows the flash rom os-area to be shared
between a bootloder and installed operating systems.   The
application ps3-flash-util or the library libps3-utils from the
ps3-utils package can be used for userspace database operations.

The latest ps3-utils package is available here:

  git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-utils.git


Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c |  422 +++++++++++++++++++++++++++++++++--
 1 file changed, 408 insertions(+), 14 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -21,6 +21,8 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
 
 #include <asm/lmb.h>
 
@@ -39,7 +41,7 @@ enum os_area_ldr_format {
  * struct os_area_header - os area header segment.
  * @magic_num: Always 'cell_ext_os_area'.
  * @hdr_version: Header format version number.
- * @os_area_offset: Starting segment number of os image area.
+ * @db_area_offset: Starting segment number of other os database area.
  * @ldr_area_offset: Starting segment number of bootloader image area.
  * @ldr_format: HEADER_LDR_FORMAT flag.
  * @ldr_size: Size of bootloader image in bytes.
@@ -53,7 +55,7 @@ enum os_area_ldr_format {
 struct os_area_header {
 	u8 magic_num[16];
 	u32 hdr_version;
-	u32 os_area_offset;
+	u32 db_area_offset;
 	u32 ldr_area_offset;
 	u32 _reserved_1;
 	u32 ldr_format;
@@ -112,10 +114,91 @@ struct os_area_params {
 	u8 _reserved_5[8];
 };
 
+/**
+ * struct os_area_db - Shared flash memory database.
+ * @magic_num: Always '-db-' = 0x2d64622d.
+ * @version: os_area_db format version number.
+ * @index_64: byte offset of the database id index for 64 bit variables.
+ * @count_64: number of usable 64 bit index entries
+ * @index_32: byte offset of the database id index for 32 bit variables.
+ * @count_32: number of usable 32 bit index entries
+ * @index_16: byte offset of the database id index for 16 bit variables.
+ * @count_16: number of usable 16 bit index entries
+ *
+ * Flash rom storage for exclusive use by guests running in the other os lpar.
+ * The current system configuration allocates 1K (two segments) for other os
+ * use.
+ */
+
+struct os_area_db {
+	u32 magic_num;
+	u16 version;
+	u16 _reserved_1;
+	u16 index_64;
+	u16 count_64;
+	u16 index_32;
+	u16 count_32;
+	u16 index_16;
+	u16 count_16;
+	u32 _reserved_2;
+	u8 _reserved_3[1000];
+};
+
+/**
+ * enum os_area_db_owner - Data owners.
+ */
+
+enum os_area_db_owner {
+	OS_AREA_DB_OWNER_ANY = -1,
+	OS_AREA_DB_OWNER_NONE = 0,
+	OS_AREA_DB_OWNER_PROTOTYPE = 1,
+	OS_AREA_DB_OWNER_LINUX = 2,
+	OS_AREA_DB_OWNER_PETITBOOT = 3,
+	OS_AREA_DB_OWNER_MAX = 32,
+};
+
+enum os_area_db_key {
+	OS_AREA_DB_KEY_ANY = -1,
+	OS_AREA_DB_KEY_NONE = 0,
+	OS_AREA_DB_KEY_RTC_DIFF = 1,
+	OS_AREA_DB_KEY_VIDEO_MODE = 2,
+	OS_AREA_DB_KEY_MAX = 8,
+};
+
+struct os_area_db_id {
+	int owner;
+	int key;
+};
+
+static const struct os_area_db_id os_area_db_id_empty = {
+	.owner = OS_AREA_DB_OWNER_NONE,
+	.key = OS_AREA_DB_KEY_NONE
+};
+
+static const struct os_area_db_id os_area_db_id_any = {
+	.owner = OS_AREA_DB_OWNER_ANY,
+	.key = OS_AREA_DB_KEY_ANY
+};
+
+static const struct os_area_db_id os_area_db_id_rtc_diff = {
+	.owner = OS_AREA_DB_OWNER_LINUX,
+	.key = OS_AREA_DB_KEY_RTC_DIFF
+};
+
+static const struct os_area_db_id os_area_db_id_video_mode = {
+	.owner = OS_AREA_DB_OWNER_LINUX,
+	.key = OS_AREA_DB_KEY_VIDEO_MODE
+};
+
 #define SECONDS_FROM_1970_TO_2000 946684800LL
 
 /**
  * struct saved_params - Static working copies of data from the PS3 'os area'.
+ *
+ * The order of preference we use for the rtc_diff source:
+ *  1) The database value.
+ *  2) The game os value.
+ *  3) The number of seconds from 1970 to 2000.
  */
 
 struct saved_params {
@@ -182,17 +265,17 @@ static void __init os_area_get_property(
 static void _dump_header(const struct os_area_header *h, const char *func,
 	int line)
 {
-	pr_debug("%s:%d: h.magic_num:         '%s'\n", func, line,
+	pr_debug("%s:%d: h.magic_num:       '%s'\n", func, line,
 		h->magic_num);
-	pr_debug("%s:%d: h.hdr_version:       %u\n", func, line,
+	pr_debug("%s:%d: h.hdr_version:     %u\n", func, line,
 		h->hdr_version);
-	pr_debug("%s:%d: h.os_area_offset:   %u\n", func, line,
-		h->os_area_offset);
+	pr_debug("%s:%d: h.db_area_offset:  %u\n", func, line,
+		h->db_area_offset);
 	pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line,
 		h->ldr_area_offset);
-	pr_debug("%s:%d: h.ldr_format:        %u\n", func, line,
+	pr_debug("%s:%d: h.ldr_format:      %u\n", func, line,
 		h->ldr_format);
-	pr_debug("%s:%d: h.ldr_size:          %xh\n", func, line,
+	pr_debug("%s:%d: h.ldr_size:        %xh\n", func, line,
 		h->ldr_size);
 }
 
@@ -222,7 +305,7 @@ static void _dump_params(const struct os
 		p->dns_secondary[2], p->dns_secondary[3]);
 }
 
-static int __init verify_header(const struct os_area_header *header)
+static int verify_header(const struct os_area_header *header)
 {
 	if (memcmp(header->magic_num, "cell_ext_os_area", 16)) {
 		pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
@@ -234,7 +317,7 @@ static int __init verify_header(const st
 		return -1;
 	}
 
-	if (header->os_area_offset > header->ldr_area_offset) {
+	if (header->db_area_offset > header->ldr_area_offset) {
 		pr_debug("%s:%d offsets failed\n", __func__, __LINE__);
 		return -1;
 	}
@@ -242,6 +325,303 @@ static int __init verify_header(const st
 	return 0;
 }
 
+static int db_verify(const struct os_area_db *db)
+{
+	if (db->magic_num != 0x2d64622dU) {
+		pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
+		return -1;
+	}
+
+	if (db->version != 1) {
+		pr_debug("%s:%d version failed\n", __func__, __LINE__);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct db_index {
+       uint8_t owner:5;
+       uint8_t key:3;
+};
+
+struct db_iterator {
+	const struct os_area_db *db;
+	struct os_area_db_id match_id;
+	struct db_index *idx;
+	struct db_index *last_idx;
+	union {
+		uint64_t *value_64;
+		uint32_t *value_32;
+		uint16_t *value_16;
+	};
+};
+
+static unsigned int db_align_up(unsigned int val, unsigned int size)
+{
+	return (val + (size - 1)) & (~(size - 1));
+}
+
+/**
+ * db_for_each_64 - Iterator for 64 bit entries.
+ *
+ * A NULL value for id can be used to match all entries.
+ * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all.
+ */
+
+static int db_for_each_64(const struct os_area_db *db,
+	const struct os_area_db_id *match_id, struct db_iterator *i)
+{
+next:
+	if (!i->db) {
+		i->db = db;
+		i->match_id = match_id ? *match_id : os_area_db_id_any;
+		i->idx = (void *)db + db->index_64;
+		i->last_idx = i->idx + db->count_64;
+		i->value_64 = (void *)db + db->index_64
+			+ db_align_up(db->count_64, 8);
+	} else {
+		i->idx++;
+		i->value_64++;
+	}
+
+	if (i->idx >= i->last_idx) {
+		pr_debug("%s:%d: reached end\n", __func__, __LINE__);
+		return 0;
+	}
+
+	if (i->match_id.owner != OS_AREA_DB_OWNER_ANY
+		&& i->match_id.owner != (int)i->idx->owner)
+		goto next;
+	if (i->match_id.key != OS_AREA_DB_KEY_ANY
+		&& i->match_id.key != (int)i->idx->key)
+		goto next;
+
+	return 1;
+}
+
+static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id)
+{
+	struct db_iterator i;
+
+	for (i.db = NULL; db_for_each_64(db, id, &i); ) {
+
+		pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+
+		i.idx->owner = 0;
+		i.idx->key = 0;
+		*i.value_64 = 0;
+	}
+	return 0;
+}
+
+static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id,
+	uint64_t value)
+{
+	struct db_iterator i;
+
+	pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__,
+		id->owner, id->key, (unsigned long long)value);
+
+	if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY
+		|| id->key == OS_AREA_DB_KEY_ANY) {
+		pr_debug("%s:%d: bad id: (%d:%d)\n", __func__,
+			__LINE__, id->owner, id->key);
+		return -1;
+	}
+
+	db_delete_64(db, id);
+
+	i.db = NULL;
+	if (db_for_each_64(db, &os_area_db_id_empty, &i)) {
+
+		pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+
+		i.idx->owner = id->owner;
+		i.idx->key = id->key;
+		*i.value_64 = value;
+
+		pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+		return 0;
+	}
+	pr_debug("%s:%d: database full.\n",
+		__func__, __LINE__);
+	return -1;
+}
+
+static int db_get_64(const struct os_area_db *db,
+	const struct os_area_db_id *id, uint64_t *value)
+{
+	struct db_iterator i;
+
+	i.db = NULL;
+	if (db_for_each_64(db, id, &i)) {
+		*value = *i.value_64;
+		pr_debug("%s:%d: found %lld\n", __func__, __LINE__,
+				(long long int)*i.value_64);
+		return 0;
+	}
+	pr_debug("%s:%d: not found\n", __func__, __LINE__);
+	return -1;
+}
+
+static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff)
+{
+	return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff);
+}
+
+static int db_get_video_mode(const struct os_area_db *db,
+	unsigned int *video_mode)
+{
+	return db_get_64(db, &os_area_db_id_video_mode, (uint64_t*)video_mode);
+}
+
+#define dump_db(a) _dump_db(a, __func__, __LINE__)
+static void _dump_db(const struct os_area_db *db, const char *func,
+	int line)
+{
+	pr_debug("%s:%d: db.magic_num:      '%s'\n", func, line,
+		(const char*)&db->magic_num);
+	pr_debug("%s:%d: db.version:         %u\n", func, line,
+		db->version);
+	pr_debug("%s:%d: db.index_64:        %u\n", func, line,
+		db->index_64);
+	pr_debug("%s:%d: db.count_64:        %u\n", func, line,
+		db->count_64);
+	pr_debug("%s:%d: db.index_32:        %u\n", func, line,
+		db->index_32);
+	pr_debug("%s:%d: db.count_32:        %u\n", func, line,
+		db->count_32);
+	pr_debug("%s:%d: db.index_16:        %u\n", func, line,
+		db->index_16);
+	pr_debug("%s:%d: db.count_16:        %u\n", func, line,
+		db->count_16);
+}
+
+static void os_area_db_init(struct os_area_db *db)
+{
+	/*
+	 * item      | start | size
+	 * ----------+-------+-------
+	 * header    | 0     | 24
+	 * index_64  | 24    | 64
+	 * values_64 | 88    | 57*8 = 456
+	 * index_32  | 544   | 64
+	 * values_32 | 609   | 57*4 = 228
+	 * index_16  | 836   | 64
+	 * values_16 | 900   | 57*2 = 114
+	 * end       | 1014  | -
+	 */
+
+	memset(db, 0, sizeof(struct os_area_db));
+
+	db->magic_num = 0x2d64622dU;
+	db->version = 1;
+	db->index_64 = 24;
+	db->count_64 = 57;
+	db->index_32 = 544;
+	db->count_32 = 57;
+	db->index_16 = 836;
+	db->count_16 = 57;
+}
+
+/**
+ * update_flash_db - Helper for os_area_queue_work_handler.
+ *
+ */
+
+static void update_flash_db(void)
+{
+	int result;
+	int file;
+	off_t offset;
+	ssize_t count;
+	static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+	const struct os_area_header *header;
+	struct os_area_db* db;
+
+	/* Read in header and db from flash. */
+
+	file = sys_open("/dev/ps3flash", O_RDWR, 0);
+
+	if (file < 0) {
+		pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
+		goto fail_open;
+	}
+
+	header = kmalloc(buf_len, GFP_KERNEL);
+
+	if (!header) {
+		pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
+		goto fail_malloc;
+	}
+
+	offset = sys_lseek(file, 0, SEEK_SET);
+
+	if (offset != 0) {
+		pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
+		goto fail_header_seek;
+	}
+
+	count = sys_read(file, (char __user *)header, buf_len);
+
+	result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
+		|| count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+
+	if (result) {
+		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
+		dump_header(header);
+		goto fail_header;
+	}
+
+	/* Now got a good db offset and some maybe good db data. */
+
+	db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+
+	result = db_verify(db);
+
+	if (result) {
+		printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
+			"formatting.\n", __func__, __LINE__);
+		dump_db(db);
+		os_area_db_init(db);
+	}
+
+	/* Now got good db data. */
+
+	db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
+
+	offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
+		SEEK_SET);
+
+	if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
+		pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
+		goto fail_db_seek;
+	}
+
+	count = sys_write(file, (const char __user *)db,
+		sizeof(struct os_area_db));
+
+	if (count < sizeof(struct os_area_db)) {
+		pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
+	}
+
+fail_db_seek:
+fail_header:
+fail_header_seek:
+	kfree(header);
+fail_malloc:
+	sys_close(file);
+fail_open:
+	return;
+}
+
 /**
  * os_area_queue_work_handler - Asynchronous write handler.
  *
@@ -264,6 +644,9 @@ static void os_area_queue_work_handler(s
 		pr_debug("%s:%d of_find_node_by_path failed\n",
 			__func__, __LINE__);
 
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+	update_flash_db();
+#endif
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
@@ -278,11 +661,15 @@ static void os_area_queue_work(void)
 /**
  * ps3_os_area_save_params - Copy data from os area mirror to @saved_params.
  *
- * For the convenience of the guest, the HV makes a copy of the os area in
+ * For the convenience of the guest the HV makes a copy of the os area in
  * flash to a high address in the boot memory region and then puts that RAM
- * address and the byte count into the repository for retreval by the guest.
+ * address and the byte count into the repository for retrieval by the guest.
  * We copy the data we want into a static variable and allow the memory setup
  * by the HV to be claimed by the lmb manager.
+ *
+ * The os area mirror will not be available to a second stage kernel, and
+ * the header verify will fail.  In this case, the saved_params values will
+ * be set from flash memory or the passed in device tree in ps3_os_area_init().
  */
 
 void __init ps3_os_area_save_params(void)
@@ -292,6 +679,7 @@ void __init ps3_os_area_save_params(void
 	unsigned int size;
 	struct os_area_header *header;
 	struct os_area_params *params;
+	struct os_area_db *db;
 
 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
 
@@ -311,16 +699,22 @@ void __init ps3_os_area_save_params(void
 
 	if (result) {
 		/* Second stage kernels exit here. */
-
 		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
 		dump_header(header);
 		return;
 	}
 
+	db = (struct os_area_db *)__va(lpar_addr
+		+ header->db_area_offset * OS_AREA_SEGMENT_SIZE);
+
 	dump_header(header);
 	dump_params(params);
+	dump_db(db);
 
-	saved_params.rtc_diff = params->rtc_diff;
+	result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff);
+	if (result)
+		saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff
+			: SECONDS_FROM_1970_TO_2000;
 	saved_params.av_multi_out = params->av_multi_out;
 	saved_params.valid = 1;
 
-- 

[patch 4/6] PS3: Add os-area rtc_diff set/get routines

From: <hidden>
Date: 2007-10-06 21:38:22

Updates for PS3 os-area rtc_diff set/get routines
o Add a new routine ps3_os_area_set_rtc_diff().
o Rename ps3_os_area_rtc_diff() to ps3_os_area_get_rtc_diff().
o Remove static variable rtc_shift with calls to ps3_os_area_get_rtc_diff().

Signed-off-by: Geoff Levand <redacted>
---
 arch/powerpc/platforms/ps3/os-area.c  |   19 +++++++++++++++++--
 arch/powerpc/platforms/ps3/platform.h |    3 ++-
 arch/powerpc/platforms/ps3/time.c     |   14 +++-----------
 3 files changed, 22 insertions(+), 14 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -261,16 +261,31 @@ void __init ps3_os_area_save_params(void
 }
 
 /**
- * ps3_os_area_rtc_diff - Returns the rtc diff value.
+ * ps3_os_area_get_rtc_diff - Returns the rtc diff value.
  */
 
-u64 ps3_os_area_rtc_diff(void)
+u64 ps3_os_area_get_rtc_diff(void)
 {
 	return saved_params.rtc_diff ? saved_params.rtc_diff
 		: SECONDS_FROM_1970_TO_2000;
 }
 
 /**
+ * ps3_os_area_set_rtc_diff - Set the rtc diff value.
+ *
+ * An asynchronous write is needed to support writing updates from
+ * the timer interrupt context.
+ */
+
+void ps3_os_area_set_rtc_diff(u64 rtc_diff)
+{
+	if (saved_params.rtc_diff != rtc_diff) {
+		saved_params.rtc_diff = rtc_diff;
+		os_area_queue_work();
+	}
+}
+
+/**
  * ps3_os_area_get_av_multi_out - Returns the default video mode.
  */
 
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -63,7 +63,8 @@ int ps3_set_rtc_time(struct rtc_time *ti
 /* os area */
 
 void __init ps3_os_area_save_params(void);
-u64 ps3_os_area_rtc_diff(void);
+u64 ps3_os_area_get_rtc_diff(void);
+void ps3_os_area_set_rtc_diff(u64 rtc_diff);
 
 /* spu */
 
--- a/arch/powerpc/platforms/ps3/time.c
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -50,12 +50,6 @@ static void __maybe_unused _dump_time(in
 	_dump_tm(&tm, func, line);
 }
 
-/**
- * rtc_shift - Difference in seconds between 1970 and the ps3 rtc value.
- */
-
-static s64 rtc_shift;
-
 void __init ps3_calibrate_decr(void)
 {
 	int result;
@@ -66,8 +60,6 @@ void __init ps3_calibrate_decr(void)
 
 	ppc_tb_freq = tmp;
 	ppc_proc_freq = ppc_tb_freq * 40;
-
-	rtc_shift = ps3_os_area_rtc_diff();
 }
 
 static u64 read_rtc(void)
@@ -87,18 +79,18 @@ int ps3_set_rtc_time(struct rtc_time *tm
 	u64 now = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
 		tm->tm_hour, tm->tm_min, tm->tm_sec);
 
-	rtc_shift = now - read_rtc();
+	ps3_os_area_set_rtc_diff(now - read_rtc());
 	return 0;
 }
 
 void ps3_get_rtc_time(struct rtc_time *tm)
 {
-	to_tm(read_rtc() + rtc_shift, tm);
+	to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm);
 	tm->tm_year -= 1900;
 	tm->tm_mon -= 1;
 }
 
 unsigned long __init ps3_get_boot_time(void)
 {
-	return read_rtc() + rtc_shift;
+	return read_rtc() + ps3_os_area_get_rtc_diff();
 }
-- 

Re: [patch 6/6] PS3: Add os-area database routines

From: Geert Uytterhoeven <hidden>
Date: 2007-10-08 08:27:28

On Sat, 6 Oct 2007 geoffrey.levand@am.sony.com wrote:
quoted hunk
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -112,10 +114,91 @@ struct os_area_params {
 	u8 _reserved_5[8];
 };
 
+/**
+ * struct os_area_db - Shared flash memory database.
+ * @magic_num: Always '-db-' = 0x2d64622d.
                                  ^^^^^^^^^^
#define?
quoted hunk
@@ -242,6 +325,303 @@ static int __init verify_header(const st
 	return 0;
 }
 
+static int db_verify(const struct os_area_db *db)
+{
+	if (db->magic_num != 0x2d64622dU) {
                             ^^^^^^^^^^^
#define?
+static void os_area_db_init(struct os_area_db *db)
+{
+	/*
+	 * item      | start | size
+	 * ----------+-------+-------
+	 * header    | 0     | 24
+	 * index_64  | 24    | 64
+	 * values_64 | 88    | 57*8 = 456
+	 * index_32  | 544   | 64
+	 * values_32 | 609   | 57*4 = 228
+	 * index_16  | 836   | 64
+	 * values_16 | 900   | 57*2 = 114
+	 * end       | 1014  | -
+	 */
Lots of #defines and calculations?
+
+	memset(db, 0, sizeof(struct os_area_db));
+
+	db->magic_num = 0x2d64622dU;
                        ^^^^^^^^^^^
#define?
+	db->version = 1;
+	db->index_64 = 24;
                       ^^
+	db->count_64 = 57;
                       ^^
+	db->index_32 = 544;
                       ^^^
+	db->count_32 = 57;
                       ^^
+	db->index_16 = 836;
                       ^^^
+	db->count_16 = 57;
                       ^^
#defines?
+static void update_flash_db(void)
+{
+	int result;
+	int file;
+	off_t offset;
+	ssize_t count;
+	static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+	const struct os_area_header *header;
+	struct os_area_db* db;
+
+	/* Read in header and db from flash. */
+
+	file = sys_open("/dev/ps3flash", O_RDWR, 0);
Ah, file operations from kernel space...
quoted hunk
@@ -264,6 +644,9 @@ static void os_area_queue_work_handler(s
 		pr_debug("%s:%d of_find_node_by_path failed\n",
 			__func__, __LINE__);
 
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+	update_flash_db();
+#endif
Is this #ifdef needed? You don't reference ps3flash symbols directly, only by
opening /dev/ps3flash. If you always call update_flash_db(), you can print an
error message and the user will notice things haven't been written to flash.

With kind regards,
 
Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
 
Phone:    +32 (0)2 700 8453	
Fax:      +32 (0)2 700 8622	
E-mail:   Geert.Uytterhoeven@sonycom.com	
Internet: http://www.sony-europe.com/
 	
Sony Network and Software Technology Center Europe	
A division of Sony Service Centre (Europe) N.V.	
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium	
VAT BE 0413.825.160 · RPR Brussels	
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

Re: [patch 6/6] PS3: Add os-area database routines

From: Geert Uytterhoeven <hidden>
Date: 2007-10-08 12:16:26

On Sat, 6 Oct 2007 geoffrey.levand@am.sony.com wrote:
quoted hunk
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
+static int db_get_video_mode(const struct os_area_db *db,
+	unsigned int *video_mode)
        ^^^^^^^^^^^^^^
+{
+	return db_get_64(db, &os_area_db_id_video_mode, (uint64_t*)video_mode);
                                                        ^^^^^^^^^^^
+}
Woops, memory corruption, when writing a 64-bit value to a 32-bit variable.

With kind regards,
 
Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
 
Phone:    +32 (0)2 700 8453	
Fax:      +32 (0)2 700 8622	
E-mail:   Geert.Uytterhoeven@sonycom.com	
Internet: http://www.sony-europe.com/
 	
Sony Network and Software Technology Center Europe	
A division of Sony Service Centre (Europe) N.V.	
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium	
VAT BE 0413.825.160 · RPR Brussels	
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

Re: [patch 6/6] PS3: Add os-area database routines

From: Ranulf Doswell <hidden>
Date: 2007-10-08 13:48:20

On 06/10/2007, geoffrey.levand@am.sony.com [off-list ref]
wrote:
enum os_area_db_owner {
	OS_AREA_DB_OWNER_ANY = -1,
	OS_AREA_DB_OWNER_NONE = 0,
OS_AREA_DB_OWNER_PROTOTYPE = 1,
OS_AREA_DB_OWNER_LINUX = 2,
OS_AREA_DB_OWNER_PETITBOOT = 3,
OS_AREA_DB_OWNER_MAX = 32,
};

enum os_area_db_key {
OS_AREA_DB_KEY_ANY = -1,
OS_AREA_DB_KEY_NONE = 0,
OS_AREA_DB_KEY_RTC_DIFF = 1,
OS_AREA_DB_KEY_VIDEO_MODE = 2,
OS_AREA_DB_KEY_MAX = 8,
};
How do we go about claiming one of these OS_AREA_DB_OWNER_ keys? I'd very
much like to use this functionality in my python-ps3 games library.

My requirement is to be able to persist various options such as player names
and rankings. I had already been thinking about generating a unique token
and storing it somewhere at the end of the flash area so that when my game
connects to a game server, it can identify itself and be provided with all
the previous settings. Obviously, just claiming a random area of flash isn't
ideal, so your standardised solution would be perfect for this.

I would like, therefore, to reserve a single key to hold a 64-bit sized
token in order to identify the machine across reboots. I don't mind
particularly whether it's private to my application or a generally available
field, but certainly having an identifier I can rely on would be very
useful.

Cheers,
    Ralf.

Re: [patch 2/6] PS3: Remove unused os-area params

From: Ranulf Doswell <hidden>
Date: 2007-10-08 14:00:44

On 06/10/2007, geoffrey.levand@am.sony.com [off-list ref]
wrote:
struct saved_params {
-	/* param 0 */
	s64 rtc_diff;
	unsigned int av_multi_out;
-	unsigned int ctrl_button;
-	/* param 1 */
-	u8 static_ip_addr[4];
-	u8 network_mask[4];
-	u8 default_gateway[4];
-	/* param 2 */
-	u8 dns_primary[4];
-	u8 dns_secondary[4];
} static saved_params;
As these values are correctly populated by the hypervisor from the
preferences on the standard PS3 OS, it is incredibly useful to have this
information available.

Whilst none of the current 'popular' distributions use these fields, I am
currently in the process of making a bootable CD image that does use them in
order to initialise the network. Not having this information available means
that the only sensible option is to use DHCP, which may well not be
available in every case.

Please can we have these fields back? They don't actually take up all that
much room, yet they are incredibly useful.

-- 
Ranulf Doswell

One of the major reasons for the downfall of the Roman Empire was, lacking
zero, they had no way to indicate termination of their C strings.

Re: [patch 2/6] PS3: Remove unused os-area params

From: Geoff Levand <hidden>
Date: 2007-10-08 17:53:37

Ranulf Doswell wrote:
On 06/10/2007, *geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>* <geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>> wrote:
quoted
struct saved_params {
-	/* param 0 */
	s64 rtc_diff;
	unsigned int av_multi_out;
-	unsigned int ctrl_button;
-	/* param 1 */
-	u8 static_ip_addr[4];
-	u8 network_mask[4];
quoted
-	u8 default_gateway[4];
-	/* param 2 */
-	u8 dns_primary[4];
-	u8 dns_secondary[4];
} static saved_params;
As these values are correctly populated by the hypervisor from the
preferences on the standard PS3 OS, it is incredibly useful to have this
information available.

No, it is not used, and I never used it.

Whilst none of the current 'popular' distributions use these fields, I
am currently in the process of making a bootable CD image that does use
them in order to initialise the network. Not having this information
available means that the only sensible option is to use DHCP, which may
well not be available in every case.

Please can we have these fields back? They don't actually take up all
that much room, yet they are incredibly useful.

As a general rule we don't put unused code into the kernel, and I have no
plan to provide the support you mention.  Please submit a patch to the ML
with your feature for review.

-Geoff

Re: [patch 6/6] PS3: Add os-area database routines

From: Geoff Levand <hidden>
Date: 2007-10-08 17:54:56

Ranulf Doswell wrote:
On 06/10/2007, *geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>* <geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>> wrote:
quoted
enum os_area_db_owner {
quoted
	OS_AREA_DB_OWNER_ANY = -1,
	OS_AREA_DB_OWNER_NONE = 0,
OS_AREA_DB_OWNER_PROTOTYPE = 1,
OS_AREA_DB_OWNER_LINUX = 2,
quoted
OS_AREA_DB_OWNER_PETITBOOT = 3,
OS_AREA_DB_OWNER_MAX = 32,
};

enum os_area_db_key {
OS_AREA_DB_KEY_ANY = -1,
OS_AREA_DB_KEY_NONE = 0,
OS_AREA_DB_KEY_RTC_DIFF = 1,
quoted
OS_AREA_DB_KEY_VIDEO_MODE = 2,
OS_AREA_DB_KEY_MAX = 8,
};
How do we go about claiming one of these OS_AREA_DB_OWNER_ keys? I'd
very much like to use this functionality in my python-ps3 games library.

It sounds like you should be storing your info in the file system like
all other applications do.

Re: [patch 2/6] PS3: Remove unused os-area params

From: Ranulf Doswell <hidden>
Date: 2007-10-08 22:38:47

On 08/10/2007, Geoff Levand [off-list ref] wrote:
Ranulf Doswell wrote:
quoted
As these values are correctly populated by the hypervisor from the
preferences on the standard PS3 OS, it is incredibly useful to have this
information available.
No, it is not used, and I never used it.

Maybe I've mistaken how these are used. Having just looked at the source
again, I see that the saved_params field isn't exported.

Am I correct in assuming that this information will still be available in
/dev/ps3flash starting at offset 0x200? That's actually where I'm expecting
to find the information anyway. I believed your patch was changing that
behaviour, although I probably didn't study it enough.

Cheers,
    Ralf.

Re: [patch 2/6] PS3: Remove unused os-area params

From: Geoff Levand <hidden>
Date: 2007-10-08 22:50:35

Ranulf Doswell wrote:
On 08/10/2007, *Geoff Levand* <geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>> wrote:

    Ranulf Doswell wrote:
    >
    > As these values are correctly populated by the hypervisor from the
    > preferences on the standard PS3 OS, it is incredibly useful to
    have this
    > information available.

    No, it is not used, and I never used it.


Maybe I've mistaken how these are used. Having just looked at the source
again, I see that the saved_params field isn't exported.

Am I correct in assuming that this information will still be available
in /dev/ps3flash starting at offset 0x200? That's actually where I'm
expecting to find the information anyway. I believed your patch was
changing that behaviour, although I probably didn't study it enough.
Yes, and you can use libps3-utils to get it:

  http://git.kernel.org/?p=linux/kernel/git/geoff/ps3-utils.git

-Geoff

Re: [patch 6/6] PS3: Add os-area database routines

From: Ranulf Doswell <hidden>
Date: 2007-10-08 22:59:15

On 08/10/2007, Geoff Levand [off-list ref] wrote:
quoted
How do we go about claiming one of these OS_AREA_DB_OWNER_ keys? I'd
very much like to use this functionality in my python-ps3 games library.
It sounds like you should be storing your info in the file system like
all other applications do.

I'd agree that for large amounts of application specific data, the
filesystem is the correct approach.

However, in this case the only data required is a single identifier used to
identify one PS3 from another, and in fact this single 64-bit token can be
shared amongst many other applications that require the same function -
certainly I intend to expose it in a common way in my games library's API
for all users of the library.

In my particular case, my bootable CD image does not have any other use for
a filesystem on disk beyond the initrd image on the CD-ROM; this is
important because some PS3s may be formatted as 100% GameOS. All that is
needed is to write the standard kboot image to flash so that it is able to
bootstrap the CD image.

As the PS3 has flash available and you are adding a mechanism for storing
very small bits of data in the flash, it seems silly not to use it and
attempt instead to write my own incompatible database format to store this
in the flash memory. Your database also has the added protection of not
being overwritten when the loader is re-flashed, as it is protected by the
kernel.

If you agree in principle that one of these identifiers can be allocated to
this purpose, I'm happy to write and submit a patch that exposes the get/set
system ID functionality to userland, whilst internally using your database.
This could also allow for some of the bits to be used as check bits to
ensure data validity.

Possibly there already exists a way to obtain a hash of the serial number or
some other unique identifying token via one of the undocumented hypervisor
calls, but as I'm not privvy to that kind of information I need to roll my
own mechanism for doing this.

Ralf.

Re: [patch 6/6] PS3: Add os-area database routines

From: Geoff Levand <hidden>
Date: 2007-10-08 23:36:48

Ranulf Doswell wrote:
On 08/10/2007, *Geoff Levand* <geoffrey.levand@am.sony.com
<mailto:geoffrey.levand@am.sony.com>> wrote:

    > How do we go about claiming one of these OS_AREA_DB_OWNER_ keys? I'd
    > very much like to use this functionality in my python-ps3 games
    library.

    It sounds like you should be storing your info in the file system like
    all other applications do.


I'd agree that for large amounts of application specific data, the
filesystem is the correct approach.

However, in this case the only data required is a single identifier used
to identify one PS3 from another, and in fact this single 64-bit token
can be shared amongst many other applications that require the same
function - certainly I intend to expose it in a common way in my games
library's API for all users of the library.

In my particular case, my bootable CD image does not have any other use
for a filesystem on disk beyond the initrd image on the CD-ROM; this is
important because some PS3s may be formatted as 100% GameOS. All that is
needed is to write the standard kboot image to flash so that it is able
to bootstrap the CD image.

As the PS3 has flash available and you are adding a mechanism for
storing very small bits of data in the flash, it seems silly not to use
it and attempt instead to write my own incompatible database format to
store this in the flash memory. Your database also has the added
protection of not being overwritten when the loader is re-flashed, as it
is protected by the kernel.

If you agree in principle that one of these identifiers can be allocated
to this purpose, I'm happy to write and submit a patch that exposes the
get/set system ID functionality to userland, whilst internally using
your database. This could also allow for some of the bits to be used as
check bits to ensure data validity.

This feature is not intended for general application use.  If the user
wants to store data, then they should setup the system with a writable
filesystem.

-Geoff

[patch v2] PS3: Add os-area database routines

From: Geoff Levand <hidden>
Date: 2007-10-09 01:08:04

Subject: PS3: Add os-area database routines

Add support for a simple tagged database in the PS3 flash rom
os-area.  The database allows the flash rom os-area to be shared
between a bootloader and installed operating systems.   The
application ps3-flash-util or the library libps3-utils from the
ps3-utils package can be used for userspace database operations.

The latest ps3-utils package is available here:

  git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-utils.git


Signed-off-by: Geoff Levand <redacted>
---

v2: Address Geert's comments:
  o Replace numeric initializers with symbols, calculations and
    BUILD_BUG_ON() checks.
  o Add a KERN_WARNING message when flash driver is not available.
  o Remove the unused (and incorrect) routine db_get_video_mode().

 arch/powerpc/platforms/ps3/os-area.c |  445 +++++++++++++++++++++++++++++++++--
 1 file changed, 431 insertions(+), 14 deletions(-)
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -21,6 +21,8 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
 
 #include <asm/lmb.h>
 
@@ -39,7 +41,7 @@ enum os_area_ldr_format {
  * struct os_area_header - os area header segment.
  * @magic_num: Always 'cell_ext_os_area'.
  * @hdr_version: Header format version number.
- * @os_area_offset: Starting segment number of os image area.
+ * @db_area_offset: Starting segment number of other os database area.
  * @ldr_area_offset: Starting segment number of bootloader image area.
  * @ldr_format: HEADER_LDR_FORMAT flag.
  * @ldr_size: Size of bootloader image in bytes.
@@ -53,7 +55,7 @@ enum os_area_ldr_format {
 struct os_area_header {
 	u8 magic_num[16];
 	u32 hdr_version;
-	u32 os_area_offset;
+	u32 db_area_offset;
 	u32 ldr_area_offset;
 	u32 _reserved_1;
 	u32 ldr_format;
@@ -112,10 +114,95 @@ struct os_area_params {
 	u8 _reserved_5[8];
 };
 
+enum {
+	OS_AREA_DB_MAGIC_NUM = 0x2d64622dU,
+};
+
+/**
+ * struct os_area_db - Shared flash memory database.
+ * @magic_num: Always '-db-' = 0x2d64622d.
+ * @version: os_area_db format version number.
+ * @index_64: byte offset of the database id index for 64 bit variables.
+ * @count_64: number of usable 64 bit index entries
+ * @index_32: byte offset of the database id index for 32 bit variables.
+ * @count_32: number of usable 32 bit index entries
+ * @index_16: byte offset of the database id index for 16 bit variables.
+ * @count_16: number of usable 16 bit index entries
+ *
+ * Flash rom storage for exclusive use by guests running in the other os lpar.
+ * The current system configuration allocates 1K (two segments) for other os
+ * use.
+ */
+
+struct os_area_db {
+	u32 magic_num;
+	u16 version;
+	u16 _reserved_1;
+	u16 index_64;
+	u16 count_64;
+	u16 index_32;
+	u16 count_32;
+	u16 index_16;
+	u16 count_16;
+	u32 _reserved_2;
+	u8 _db_data[1000];
+};
+
+/**
+ * enum os_area_db_owner - Data owners.
+ */
+
+enum os_area_db_owner {
+	OS_AREA_DB_OWNER_ANY = -1,
+	OS_AREA_DB_OWNER_NONE = 0,
+	OS_AREA_DB_OWNER_PROTOTYPE = 1,
+	OS_AREA_DB_OWNER_LINUX = 2,
+	OS_AREA_DB_OWNER_PETITBOOT = 3,
+	OS_AREA_DB_OWNER_MAX = 32,
+};
+
+enum os_area_db_key {
+	OS_AREA_DB_KEY_ANY = -1,
+	OS_AREA_DB_KEY_NONE = 0,
+	OS_AREA_DB_KEY_RTC_DIFF = 1,
+	OS_AREA_DB_KEY_VIDEO_MODE = 2,
+	OS_AREA_DB_KEY_MAX = 8,
+};
+
+struct os_area_db_id {
+	int owner;
+	int key;
+};
+
+static const struct os_area_db_id os_area_db_id_empty = {
+	.owner = OS_AREA_DB_OWNER_NONE,
+	.key = OS_AREA_DB_KEY_NONE
+};
+
+static const struct os_area_db_id os_area_db_id_any = {
+	.owner = OS_AREA_DB_OWNER_ANY,
+	.key = OS_AREA_DB_KEY_ANY
+};
+
+static const struct os_area_db_id os_area_db_id_rtc_diff = {
+	.owner = OS_AREA_DB_OWNER_LINUX,
+	.key = OS_AREA_DB_KEY_RTC_DIFF
+};
+
+static const struct os_area_db_id os_area_db_id_video_mode = {
+	.owner = OS_AREA_DB_OWNER_LINUX,
+	.key = OS_AREA_DB_KEY_VIDEO_MODE
+};
+
 #define SECONDS_FROM_1970_TO_2000 946684800LL
 
 /**
  * struct saved_params - Static working copies of data from the PS3 'os area'.
+ *
+ * The order of preference we use for the rtc_diff source:
+ *  1) The database value.
+ *  2) The game os value.
+ *  3) The number of seconds from 1970 to 2000.
  */
 
 struct saved_params {
@@ -182,17 +269,17 @@ static void __init os_area_get_property(
 static void _dump_header(const struct os_area_header *h, const char *func,
 	int line)
 {
-	pr_debug("%s:%d: h.magic_num:         '%s'\n", func, line,
+	pr_debug("%s:%d: h.magic_num:       '%s'\n", func, line,
 		h->magic_num);
-	pr_debug("%s:%d: h.hdr_version:       %u\n", func, line,
+	pr_debug("%s:%d: h.hdr_version:     %u\n", func, line,
 		h->hdr_version);
-	pr_debug("%s:%d: h.os_area_offset:   %u\n", func, line,
-		h->os_area_offset);
+	pr_debug("%s:%d: h.db_area_offset:  %u\n", func, line,
+		h->db_area_offset);
 	pr_debug("%s:%d: h.ldr_area_offset: %u\n", func, line,
 		h->ldr_area_offset);
-	pr_debug("%s:%d: h.ldr_format:        %u\n", func, line,
+	pr_debug("%s:%d: h.ldr_format:      %u\n", func, line,
 		h->ldr_format);
-	pr_debug("%s:%d: h.ldr_size:          %xh\n", func, line,
+	pr_debug("%s:%d: h.ldr_size:        %xh\n", func, line,
 		h->ldr_size);
 }
 
@@ -222,7 +309,7 @@ static void _dump_params(const struct os
 		p->dns_secondary[2], p->dns_secondary[3]);
 }
 
-static int __init verify_header(const struct os_area_header *header)
+static int verify_header(const struct os_area_header *header)
 {
 	if (memcmp(header->magic_num, "cell_ext_os_area", 16)) {
 		pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
@@ -234,7 +321,7 @@ static int __init verify_header(const st
 		return -1;
 	}
 
-	if (header->os_area_offset > header->ldr_area_offset) {
+	if (header->db_area_offset > header->ldr_area_offset) {
 		pr_debug("%s:%d offsets failed\n", __func__, __LINE__);
 		return -1;
 	}
@@ -242,6 +329,319 @@ static int __init verify_header(const st
 	return 0;
 }
 
+static int db_verify(const struct os_area_db *db)
+{
+	if (db->magic_num != OS_AREA_DB_MAGIC_NUM) {
+		pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
+		return -1;
+	}
+
+	if (db->version != 1) {
+		pr_debug("%s:%d version failed\n", __func__, __LINE__);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct db_index {
+       uint8_t owner:5;
+       uint8_t key:3;
+};
+
+struct db_iterator {
+	const struct os_area_db *db;
+	struct os_area_db_id match_id;
+	struct db_index *idx;
+	struct db_index *last_idx;
+	union {
+		uint64_t *value_64;
+		uint32_t *value_32;
+		uint16_t *value_16;
+	};
+};
+
+static unsigned int db_align_up(unsigned int val, unsigned int size)
+{
+	return (val + (size - 1)) & (~(size - 1));
+}
+
+/**
+ * db_for_each_64 - Iterator for 64 bit entries.
+ *
+ * A NULL value for id can be used to match all entries.
+ * OS_AREA_DB_OWNER_ANY and OS_AREA_DB_KEY_ANY can be used to match all.
+ */
+
+static int db_for_each_64(const struct os_area_db *db,
+	const struct os_area_db_id *match_id, struct db_iterator *i)
+{
+next:
+	if (!i->db) {
+		i->db = db;
+		i->match_id = match_id ? *match_id : os_area_db_id_any;
+		i->idx = (void *)db + db->index_64;
+		i->last_idx = i->idx + db->count_64;
+		i->value_64 = (void *)db + db->index_64
+			+ db_align_up(db->count_64, 8);
+	} else {
+		i->idx++;
+		i->value_64++;
+	}
+
+	if (i->idx >= i->last_idx) {
+		pr_debug("%s:%d: reached end\n", __func__, __LINE__);
+		return 0;
+	}
+
+	if (i->match_id.owner != OS_AREA_DB_OWNER_ANY
+		&& i->match_id.owner != (int)i->idx->owner)
+		goto next;
+	if (i->match_id.key != OS_AREA_DB_KEY_ANY
+		&& i->match_id.key != (int)i->idx->key)
+		goto next;
+
+	return 1;
+}
+
+static int db_delete_64(struct os_area_db *db, const struct os_area_db_id *id)
+{
+	struct db_iterator i;
+
+	for (i.db = NULL; db_for_each_64(db, id, &i); ) {
+
+		pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+
+		i.idx->owner = 0;
+		i.idx->key = 0;
+		*i.value_64 = 0;
+	}
+	return 0;
+}
+
+static int db_set_64(struct os_area_db *db, const struct os_area_db_id *id,
+	uint64_t value)
+{
+	struct db_iterator i;
+
+	pr_debug("%s:%d: (%d:%d) <= %llxh\n", __func__, __LINE__,
+		id->owner, id->key, (unsigned long long)value);
+
+	if (!id->owner || id->owner == OS_AREA_DB_OWNER_ANY
+		|| id->key == OS_AREA_DB_KEY_ANY) {
+		pr_debug("%s:%d: bad id: (%d:%d)\n", __func__,
+			__LINE__, id->owner, id->key);
+		return -1;
+	}
+
+	db_delete_64(db, id);
+
+	i.db = NULL;
+	if (db_for_each_64(db, &os_area_db_id_empty, &i)) {
+
+		pr_debug("%s:%d: got (%d:%d) %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+
+		i.idx->owner = id->owner;
+		i.idx->key = id->key;
+		*i.value_64 = value;
+
+		pr_debug("%s:%d: set (%d:%d) <= %llxh\n", __func__, __LINE__,
+			i.idx->owner, i.idx->key,
+			(unsigned long long)*i.value_64);
+		return 0;
+	}
+	pr_debug("%s:%d: database full.\n",
+		__func__, __LINE__);
+	return -1;
+}
+
+static int db_get_64(const struct os_area_db *db,
+	const struct os_area_db_id *id, uint64_t *value)
+{
+	struct db_iterator i;
+
+	i.db = NULL;
+	if (db_for_each_64(db, id, &i)) {
+		*value = *i.value_64;
+		pr_debug("%s:%d: found %lld\n", __func__, __LINE__,
+				(long long int)*i.value_64);
+		return 0;
+	}
+	pr_debug("%s:%d: not found\n", __func__, __LINE__);
+	return -1;
+}
+
+static int db_get_rtc_diff(const struct os_area_db *db, int64_t *rtc_diff)
+{
+	return db_get_64(db, &os_area_db_id_rtc_diff, (uint64_t*)rtc_diff);
+}
+
+#define dump_db(a) _dump_db(a, __func__, __LINE__)
+static void _dump_db(const struct os_area_db *db, const char *func,
+	int line)
+{
+	pr_debug("%s:%d: db.magic_num:      '%s'\n", func, line,
+		(const char*)&db->magic_num);
+	pr_debug("%s:%d: db.version:         %u\n", func, line,
+		db->version);
+	pr_debug("%s:%d: db.index_64:        %u\n", func, line,
+		db->index_64);
+	pr_debug("%s:%d: db.count_64:        %u\n", func, line,
+		db->count_64);
+	pr_debug("%s:%d: db.index_32:        %u\n", func, line,
+		db->index_32);
+	pr_debug("%s:%d: db.count_32:        %u\n", func, line,
+		db->count_32);
+	pr_debug("%s:%d: db.index_16:        %u\n", func, line,
+		db->index_16);
+	pr_debug("%s:%d: db.count_16:        %u\n", func, line,
+		db->count_16);
+}
+
+static void os_area_db_init(struct os_area_db *db)
+{
+	enum {
+		HEADER_SIZE = offsetof(struct os_area_db, _db_data),
+		INDEX_64_COUNT = 64,
+		VALUES_64_COUNT = 57,
+		INDEX_32_COUNT = 64,
+		VALUES_32_COUNT = 57,
+		INDEX_16_COUNT = 64,
+		VALUES_16_COUNT = 57,
+	};
+
+	memset(db, 0, sizeof(struct os_area_db));
+
+	db->magic_num = OS_AREA_DB_MAGIC_NUM;
+	db->version = 1;
+	db->index_64 = HEADER_SIZE;
+	db->count_64 = VALUES_64_COUNT;
+	db->index_32 = HEADER_SIZE
+			+ INDEX_64_COUNT * sizeof(struct db_index)
+			+ VALUES_64_COUNT * sizeof(u64);
+	db->count_32 = VALUES_32_COUNT;
+	db->index_16 = HEADER_SIZE
+			+ INDEX_64_COUNT * sizeof(struct db_index)
+			+ VALUES_64_COUNT * sizeof(u64)
+			+ INDEX_32_COUNT * sizeof(struct db_index)
+			+ VALUES_32_COUNT * sizeof(u32);
+	db->count_16 = VALUES_16_COUNT;
+
+	/* Rules to check db layout. */
+
+	BUILD_BUG_ON(sizeof(struct db_index) != 1);
+	BUILD_BUG_ON(sizeof(struct os_area_db) != 2 * OS_AREA_SEGMENT_SIZE);
+	BUILD_BUG_ON(INDEX_64_COUNT & 0x7);
+	BUILD_BUG_ON(VALUES_64_COUNT > INDEX_64_COUNT);
+	BUILD_BUG_ON(INDEX_32_COUNT & 0x7);
+	BUILD_BUG_ON(VALUES_32_COUNT > INDEX_32_COUNT);
+	BUILD_BUG_ON(INDEX_16_COUNT & 0x7);
+	BUILD_BUG_ON(VALUES_16_COUNT > INDEX_16_COUNT);
+	BUILD_BUG_ON(HEADER_SIZE
+			+ INDEX_64_COUNT * sizeof(struct db_index)
+			+ VALUES_64_COUNT * sizeof(u64)
+			+ INDEX_32_COUNT * sizeof(struct db_index)
+			+ VALUES_32_COUNT * sizeof(u32)
+			+ INDEX_16_COUNT * sizeof(struct db_index)
+			+ VALUES_16_COUNT * sizeof(u16)
+			> sizeof(struct os_area_db));
+}
+
+/**
+ * update_flash_db - Helper for os_area_queue_work_handler.
+ *
+ */
+
+static void update_flash_db(void)
+{
+	int result;
+	int file;
+	off_t offset;
+	ssize_t count;
+	static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+	const struct os_area_header *header;
+	struct os_area_db* db;
+
+	/* Read in header and db from flash. */
+
+	file = sys_open("/dev/ps3flash", O_RDWR, 0);
+
+	if (file < 0) {
+		pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
+		goto fail_open;
+	}
+
+	header = kmalloc(buf_len, GFP_KERNEL);
+
+	if (!header) {
+		pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
+		goto fail_malloc;
+	}
+
+	offset = sys_lseek(file, 0, SEEK_SET);
+
+	if (offset != 0) {
+		pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
+		goto fail_header_seek;
+	}
+
+	count = sys_read(file, (char __user *)header, buf_len);
+
+	result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
+		|| count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+
+	if (result) {
+		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
+		dump_header(header);
+		goto fail_header;
+	}
+
+	/* Now got a good db offset and some maybe good db data. */
+
+	db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+
+	result = db_verify(db);
+
+	if (result) {
+		printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
+			"formatting.\n", __func__, __LINE__);
+		dump_db(db);
+		os_area_db_init(db);
+	}
+
+	/* Now got good db data. */
+
+	db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
+
+	offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
+		SEEK_SET);
+
+	if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
+		pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
+		goto fail_db_seek;
+	}
+
+	count = sys_write(file, (const char __user *)db,
+		sizeof(struct os_area_db));
+
+	if (count < sizeof(struct os_area_db)) {
+		pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
+	}
+
+fail_db_seek:
+fail_header:
+fail_header_seek:
+	kfree(header);
+fail_malloc:
+	sys_close(file);
+fail_open:
+	return;
+}
+
 /**
  * os_area_queue_work_handler - Asynchronous write handler.
  *
@@ -264,6 +664,12 @@ static void os_area_queue_work_handler(s
 		pr_debug("%s:%d of_find_node_by_path failed\n",
 			__func__, __LINE__);
 
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+	update_flash_db();
+#else
+	printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
+		__func__, __LINE__);
+#endif
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
@@ -278,11 +684,15 @@ static void os_area_queue_work(void)
 /**
  * ps3_os_area_save_params - Copy data from os area mirror to @saved_params.
  *
- * For the convenience of the guest, the HV makes a copy of the os area in
+ * For the convenience of the guest the HV makes a copy of the os area in
  * flash to a high address in the boot memory region and then puts that RAM
- * address and the byte count into the repository for retreval by the guest.
+ * address and the byte count into the repository for retrieval by the guest.
  * We copy the data we want into a static variable and allow the memory setup
  * by the HV to be claimed by the lmb manager.
+ *
+ * The os area mirror will not be available to a second stage kernel, and
+ * the header verify will fail.  In this case, the saved_params values will
+ * be set from flash memory or the passed in device tree in ps3_os_area_init().
  */
 
 void __init ps3_os_area_save_params(void)
@@ -292,6 +702,7 @@ void __init ps3_os_area_save_params(void
 	unsigned int size;
 	struct os_area_header *header;
 	struct os_area_params *params;
+	struct os_area_db *db;
 
 	pr_debug(" -> %s:%d\n", __func__, __LINE__);
 
@@ -311,16 +722,22 @@ void __init ps3_os_area_save_params(void
 
 	if (result) {
 		/* Second stage kernels exit here. */
-
 		pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
 		dump_header(header);
 		return;
 	}
 
+	db = (struct os_area_db *)__va(lpar_addr
+		+ header->db_area_offset * OS_AREA_SEGMENT_SIZE);
+
 	dump_header(header);
 	dump_params(params);
+	dump_db(db);
 
-	saved_params.rtc_diff = params->rtc_diff;
+	result = db_verify(db) || db_get_rtc_diff(db, &saved_params.rtc_diff);
+	if (result)
+		saved_params.rtc_diff = params->rtc_diff ? params->rtc_diff
+			: SECONDS_FROM_1970_TO_2000;
 	saved_params.av_multi_out = params->av_multi_out;
 	saved_params.valid = 1;
 

Re: [patch 6/6] PS3: Add os-area database routines

From: Geoff Levand <hidden>
Date: 2007-10-09 01:08:33

Geert Uytterhoeven wrote:
On Sat, 6 Oct 2007 geoffrey.levand@am.sony.com wrote:
quoted
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -112,10 +114,91 @@ struct os_area_params {
 	u8 _reserved_5[8];
 };
 
+/**
+ * struct os_area_db - Shared flash memory database.
+ * @magic_num: Always '-db-' = 0x2d64622d.
                                  ^^^^^^^^^^
#define?

Well, this is a comment, and when debugging it is handy to
know the value.

quoted
@@ -242,6 +325,303 @@ static int __init verify_header(const st
 	return 0;
 }
 
+static int db_verify(const struct os_area_db *db)
+{
+	if (db->magic_num != 0x2d64622dU) {
                             ^^^^^^^^^^^
#define?

Sure, it is OK here.

quoted
+static void os_area_db_init(struct os_area_db *db)
+{
+	/*
+	 * item      | start | size
+	 * ----------+-------+-------
+	 * header    | 0     | 24
+	 * index_64  | 24    | 64
+	 * values_64 | 88    | 57*8 = 456
+	 * index_32  | 544   | 64
+	 * values_32 | 609   | 57*4 = 228
+	 * index_16  | 836   | 64
+	 * values_16 | 900   | 57*2 = 114
+	 * end       | 1014  | -
+	 */
Lots of #defines and calculations?

OK.

quoted
+
+	memset(db, 0, sizeof(struct os_area_db));
+
+	db->magic_num = 0x2d64622dU;
                        ^^^^^^^^^^^
#define?
quoted
+	db->version = 1;
+	db->index_64 = 24;
                       ^^
quoted
+	db->count_64 = 57;
                       ^^
quoted
+	db->index_32 = 544;
                       ^^^
quoted
+	db->count_32 = 57;
                       ^^
quoted
+	db->index_16 = 836;
                       ^^^
quoted
+	db->count_16 = 57;
                       ^^
#defines?
quoted
+static void update_flash_db(void)
+{
+	int result;
+	int file;
+	off_t offset;
+	ssize_t count;
+	static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+	const struct os_area_header *header;
+	struct os_area_db* db;
+
+	/* Read in header and db from flash. */
+
+	file = sys_open("/dev/ps3flash", O_RDWR, 0);
Ah, file operations from kernel space...

Yes.  I was thinking we could make an interface to the flash driver.

 
quoted
@@ -264,6 +644,9 @@ static void os_area_queue_work_handler(s
 		pr_debug("%s:%d of_find_node_by_path failed\n",
 			__func__, __LINE__);
 
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+	update_flash_db();
+#endif
Is this #ifdef needed? You don't reference ps3flash symbols directly, only by
opening /dev/ps3flash. If you always call update_flash_db(), you can print an
error message and the user will notice things haven't been written to flash.

My thinking was that the file I/O code would be removed by the optimizer
when not needed.  I added a message.

Re: [patch 6/6] PS3: Add os-area database routines

From: Geoff Levand <hidden>
Date: 2007-10-09 01:12:33

Geert Uytterhoeven wrote:
On Sat, 6 Oct 2007 geoffrey.levand@am.sony.com wrote:
quoted
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
quoted
+static int db_get_video_mode(const struct os_area_db *db,
+	unsigned int *video_mode)
        ^^^^^^^^^^^^^^
quoted
+{
+	return db_get_64(db, &os_area_db_id_video_mode, (uint64_t*)video_mode);
                                                        ^^^^^^^^^^^
quoted
+}
Woops, memory corruption, when writing a 64-bit value to a 32-bit variable.
Whoa!  That routines is not even used, so I removed it.

-Geoff  

Re: [patch 6/6] PS3: Add os-area database routines

From: Geert Uytterhoeven <hidden>
Date: 2007-10-09 09:35:57

On Mon, 8 Oct 2007, Ranulf Doswell wrote:
On 08/10/2007, Geoff Levand [off-list ref] wrote:
quoted
quoted
How do we go about claiming one of these OS_AREA_DB_OWNER_ keys? I'd
very much like to use this functionality in my python-ps3 games library.
It sounds like you should be storing your info in the file system like
all other applications do.

I'd agree that for large amounts of application specific data, the
filesystem is the correct approach.

However, in this case the only data required is a single identifier used to
identify one PS3 from another, and in fact this single 64-bit token can be
shared amongst many other applications that require the same function -
certainly I intend to expose it in a common way in my games library's API
for all users of the library.
MAC address?

With kind regards,
 
Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
 
Phone:    +32 (0)2 700 8453	
Fax:      +32 (0)2 700 8622	
E-mail:   Geert.Uytterhoeven@sonycom.com	
Internet: http://www.sony-europe.com/
 	
Sony Network and Software Technology Center Europe	
A division of Sony Service Centre (Europe) N.V.	
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium	
VAT BE 0413.825.160 · RPR Brussels	
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

Re: [patch v2] PS3: Add os-area database routines

From: Geert Uytterhoeven <hidden>
Date: 2007-10-09 11:39:00

On Mon, 8 Oct 2007, Geoff Levand wrote:
  o Add a KERN_WARNING message when flash driver is not available.
quoted hunk
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
+static void update_flash_db(void)
+{
+	int result;
+	int file;
+	off_t offset;
+	ssize_t count;
+	static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+	const struct os_area_header *header;
+	struct os_area_db* db;
+
+	/* Read in header and db from flash. */
+
+	file = sys_open("/dev/ps3flash", O_RDWR, 0);
+
+	if (file < 0) {
+		pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
                ^^^^^^^^
pr_warn?

If the ps3flash module is not loaded, you want to see the warning.
quoted hunk
@@ -264,6 +664,12 @@ static void os_area_queue_work_handler(s
 		pr_debug("%s:%d of_find_node_by_path failed\n",
 			__func__, __LINE__);
 
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+	update_flash_db();
+#else
+	printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
+		__func__, __LINE__);
+#endif
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
Alternatively:

    #if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
    static int update_flash_db(void)
    {
	...
	return error;
    }
    #else
    static inline int update_flash_db(void)
    {
	return -Exxx;
    }
    #endif

	if (update_flash_db())
	    printk(KERN_WARNING ...);


With kind regards,
 
Geert Uytterhoeven
Software Architect

Sony Network and Software Technology Center Europe
The Corporate Village · Da Vincilaan 7-D1 · B-1935 Zaventem · Belgium
 
Phone:    +32 (0)2 700 8453	
Fax:      +32 (0)2 700 8622	
E-mail:   Geert.Uytterhoeven@sonycom.com	
Internet: http://www.sony-europe.com/
 	
Sony Network and Software Technology Center Europe	
A division of Sony Service Centre (Europe) N.V.	
Registered office: Technologielaan 7 · B-1840 Londerzeel · Belgium	
VAT BE 0413.825.160 · RPR Brussels	
Fortis Bank Zaventem · Swift GEBABEBB08A · IBAN BE39001382358619

Re: [patch 6/6] PS3: Add os-area database routines

From: Ranulf Doswell <hidden>
Date: 2007-10-09 12:23:42

On 09/10/2007, Geert Uytterhoeven [off-list ref] wrote:
On Mon, 8 Oct 2007, Ranulf Doswell wrote:
quoted
However, in this case the only data required is a single identifier used
to
quoted
identify one PS3 from another, and in fact this single 64-bit token can
be
quoted
shared amongst many other applications that require the same function -
certainly I intend to expose it in a common way in my games library's
API
quoted
for all users of the library.
MAC address?
Indeed, that's perfect! That solution also just occurred to me whilst
walking back from lunch and when I come back to check my e-mail you've
already suggested it! Funny how I've been ignoring the most obvious answer
for weeks!

Cheers,
    Ralf.

Re: [patch v2] PS3: Add os-area database routines

From: Linas Vepstas <hidden>
Date: 2007-10-09 17:15:51

On Mon, Oct 08, 2007 at 06:07:24PM -0700, Geoff Levand wrote:
Subject: PS3: Add os-area database routines

Add support for a simple tagged database in the PS3 flash rom
os-area.  The database allows the flash rom os-area to be shared
between a bootloader and installed operating systems.   The
application ps3-flash-util or the library libps3-utils from the
ps3-utils package can be used for userspace database operations.
Perhaps I missed the discussion; but .. out of general curiosity,
what is the relation between this and the ppc_md.nvram_* system?
I note that pseries, powermac, chrp, celleb implement the nvram calls,
but cell and ps3 do not. So clearly, whatever this is, its not 
layered on top of nvram?

FWIW, I don't quite understand the nvram system; it seems to have
partitions; one part is an "os area", and a chuck of it is set 
up as a file system.

So I'm wondering -- wouldn't the DB os-area be "generically 
interesting" to other ppowerpc platforms? Maybe even other arches?
And why isn't this built on top of the nvram structure? ... etc?

--linas
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help