[klibc] ARM: create /arch.cmd commands from firmware tags

ARM communicates with its firmware with a tagged data structure.
This takes appropriate chunks of the tagged data structure and converts
it to /arch.cmd options for kinit.

Bug report and initial patch by Thomas Gleixner <tglx@linuxtronix.de>,
significantly modified by me.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 7447a19..3797582 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -56,7 +56,6 @@
 
 extern void paging_init(struct meminfo *, struct machine_desc *desc);
 extern void reboot_setup(char *str);
-extern int root_mountflags;
 extern void _stext, _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
@@ -517,20 +516,31 @@
 	*cmdline_p = command_line;
 }
 
-static void __init
-setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
+/*
+ * Generate /arch.cmd, which contains command-line equivalent options
+ * for kinit.  We do this in two steps: save into a buffer, and then
+ * write out the file, since the first step will typically be done
+ * very early, and the second step needs to be done after rootfs is fully
+ * operational.
+ */
+static char __initdata arch_cmd_buffer[256];
+static int __initdata arch_cmd_len;
+
+static int __init write_arch_init_command(void)
 {
-#ifdef CONFIG_BLK_DEV_RAM
-	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
+	int fd;
 
-	rd_image_start = image_start;
-	rd_prompt = prompt;
-	rd_doload = doload;
+	fd = sys_open("/arch.cmd", O_WRONLY|O_CREAT|O_APPEND, 0666);
+	if (fd < 0)
+		return fd;
 
-	if (rd_sz)
-		rd_size = rd_sz;
-#endif
+	sys_write(fd, arch_cmd_buffer, arch_cmd_len);
+	sys_close(fd);
+
+	return 0;
 }
+	
+late_initcall(write_arch_init_command);
 
 static void __init
 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
@@ -596,13 +606,27 @@
  * a param_struct).  The list is terminated with a zero-length tag (this tag
  * is not parsed in any way).
  */
+
+
 static int __init parse_tag_core(const struct tag *tag)
 {
+	char *buf = arch_cmd_buffer + arch_cmd_len;
+	char *end = arch_cmd_buffer + sizeof arch_cmd_buffer;
+
+	if (end-buf <= 3)
+		return -ENOMEM;
+
+	*buf++ = 'r';
+	*buf = 'o';
 	if (tag->hdr.size > 2) {
 		if ((tag->u.core.flags & 1) == 0)
-			root_mountflags &= ~MS_RDONLY;
+			*buf = 'w';
 		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
 	}
+	buf++;
+	*buf++ = '\n';
+
+	arch_cmd_len = end-buf;
 	return 0;
 }
 
@@ -651,11 +675,35 @@
 
 static int __init parse_tag_ramdisk(const struct tag *tag)
 {
-	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
-		      (tag->u.ramdisk.flags & 2) == 0,
-		      tag->u.ramdisk.start, tag->u.ramdisk.size);
+#ifdef CONFIG_BLK_DEV_RAM
+	char *buf = arch_cmd_buffer + arch_cmd_len;
+	char *end = arch_cmd_buffer + sizeof arch_cmd_buffer;
+	int len;
+	
+	len = snprintf(buf, end-buf,
+		       "ramdisk_start=%u\n"
+		       "load_ramdisk=%d\n"
+		       "prompt_ramdisk=%d\n",
+		       tag->u.ramdisk.start,
+		       tag->u.ramdisk.flags & 1 ? 0 : 1,
+		       tag->u.ramdisk.flags & 2 ? 0 : 1);
+	if (len >= end-buf)
+		return -ENOMEM;
+	buf += len;
+
+	if (tag->u.ramdisk.size) {
+		len = snprintf(buf, end-buf,
+			       "ramdisk_size=%u\n",
+			       tag->u.ramdisk.size);
+		if (len >= end-buf)
+			return -ENOMEM;
+		buf += len;
+	}
+
+	arch_cmd_len = end-buf;
+#endif
 	return 0;
-}
+}	
 
 __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);