CHROMIUM: arm: driver for accessing shared memory, first cut.
authorVadim Bendebury <vbendeb@chromium.org>
Fri, 29 Apr 2011 02:07:47 +0000 (19:07 -0700)
committerGrant Grundler <grundler@google.com>
Thu, 24 May 2012 22:14:34 +0000 (15:14 -0700)
This change borrows from the previously submitted for review
http://codereview.chromium.org/6880063 (it was considered
too impacting) and needs to be accompanied by the config
change as per http://codereview.chromium.org/6902094

Also, for this to work it is required  that u-boot creates
a certain memory structure at 1M below the top of the
available physical memory, and modifies the kernel command
line to exclude the top 1 megabyte of DRAM from the kernel's
control.

It was envisioned originally, that drivers/platform/x86/chromeos.c
would be a common module providing dm-verity with interface
to platform specific modules, but as of now that file is too
much x86 centric, so a new interface file,
drivers/platform/arm/chromeos.c is introduced with this CL,
these two files will have to be merged with the underlying
drivers refactored.

Apart form adding new config options, this CL introduces the
actual driver which discovers the shared memory object and
exposes the shared memory as a file in /sys/kernel/debug to
be parsed by crossystem.

Blending in of the actual gpio states into the mapped
memory, as well as handling of nonvolatile storage will be
added in the upcoming CLs.

Change-Id: Ia961081ac1a7f760b4fa67b691c2774d810f3369
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
BUG=chromium-os:12522
TEST=manual

- recompile the kernel
- scp chromeos_arm.ko to the target's /var directory
- on the target:
  insmod /var/chromeos_arm.ko
  rmmod chromeos_arm
  insmod /var/chromeos_arm.ko
  dmesg | grep chromeos_arm:
- observe messages indicating installing/removal of
  the driver
- observe that the file /sys/kernel/debug/chromeos_arm gets
  created/removed with driver installation/removal

localhost var # wc -c /sys/kernel/debug/chromeos_arm
892 /sys/kernel/debug/chromeos_arm

Review URL: http://codereview.chromium.org/6883204

Documentation/kernel-parameters.txt
drivers/platform/Kconfig
drivers/platform/Makefile
drivers/platform/arm/Kconfig [new file with mode: 0644]
drivers/platform/arm/Makefile [new file with mode: 0644]
drivers/platform/arm/chromeos.c [new file with mode: 0644]
drivers/platform/arm/chromeos_arm.c [new file with mode: 0644]
include/linux/chromeos_platform.h

index c1601e5..695bd1e 100644 (file)
@@ -594,6 +594,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        a memory unit (amount[KMG]). See also
                        Documentation/kdump/kdump.txt for an example.
 
+       cros_shared_mem=[ARM]
+                       Format: <hex integer>
+                       Base address of the ChromeOS shared memory window,
+                       aligned at megabyte boundary, window size is fixed at
+                       1 megabyte.
+
        cs89x0_dma=     [HW,NET]
                        Format: <dma>
 
index 8390dca..7e0a663 100644 (file)
@@ -1,3 +1,9 @@
+# drivers/platform/Kconfig
+
 if X86
 source "drivers/platform/x86/Kconfig"
 endif
+
+if ARM
+source "drivers/platform/arm/Kconfig"
+endif
index 782953a..13a8d2a 100644 (file)
@@ -1,5 +1,5 @@
 #
 # Makefile for linux/drivers/platform
 #
-
+obj-$(CONFIG_ARM)              += arm/
 obj-$(CONFIG_X86)              += x86/
diff --git a/drivers/platform/arm/Kconfig b/drivers/platform/arm/Kconfig
new file mode 100644 (file)
index 0000000..f5e97ea
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# ARM Platform Specific Drivers
+#
+
+menuconfig ARM_PLATFORM_DEVICES
+       bool "ARM Specific Device Drivers"
+       default n
+       ---help---
+         Say Y here to get to see options for device drivers for various
+         ARM platforms. This option alone does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and disabled.
+
+if ARM_PLATFORM_DEVICES
+
+config ARM_CHROMEOS_FIRMWARE
+       tristate "ChromeOS firmware interface driver"
+       select CHROMEOS
+       ---help---
+         This driver provides an interface to ChromeOS firmware.
+
+         Say Y here if you are building for a ChromeOS device.
+
+config CHROMEOS
+       bool
+       depends on ARM_CHROMEOS_FIRMWARE
+
+       ---help---
+         This driver provides abstracted interfaces to the firmware features
+         provided on ChromeOS devices. It depends on a lowlevel driver to
+         implement the firmware interface on the platform.
+
+endif # CROS_PLATFORM_DEVICES
diff --git a/drivers/platform/arm/Makefile b/drivers/platform/arm/Makefile
new file mode 100644 (file)
index 0000000..bf97d26
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# Makefile for linux/drivers/platform/arm
+# arm Platform-Specific Drivers
+#
+obj-$(CONFIG_ARM_CHROMEOS_FIRMWARE) += chromeos_arm.o
+obj-$(CONFIG_CHROMEOS) += chromeos.o
diff --git a/drivers/platform/arm/chromeos.c b/drivers/platform/arm/chromeos.c
new file mode 100644 (file)
index 0000000..e531015
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  ChromeOS platform support code. Glue layer between higher level functions
+ *  and per-platform firmware interfaces.
+ *
+ *  Copyright (C) 2011 The Chromium OS Authors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This module isolates ChromeOS platform specific behavior.  In particular,
+ * it uses calls from chromeos_acpi.c to control the boot flow, and exports some
+ * helper functions for kernel-side consumers of platform configuration, such
+ * as nvram flags.
+ */
+
+#include <linux/chromeos_platform.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+u64 phys_window_base;
+EXPORT_SYMBOL(phys_window_base);
+
+int chromeos_set_need_recovery(void)
+{
+       return -1;
+}
+
+static int __init get_mem_base(char *p)
+{
+        char *endptr;   /* local pointer to end of parsed string */
+        u64 base = simple_strtoull(p, &endptr, 0);
+
+       /* rudimentary sanity check */
+       if (base & ((1 << 20) -1)) {
+               pr_err("chromeos: unaligned window base 0x%llx\n", base);
+               return -1;
+       }
+
+       phys_window_base = base;
+       return 0;
+}
+
+early_param("cros_shared_mem", get_mem_base);
+
diff --git a/drivers/platform/arm/chromeos_arm.c b/drivers/platform/arm/chromeos_arm.c
new file mode 100644 (file)
index 0000000..213017f
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  ChromeOS platform support code. Glue layer between higher level functions
+ *  and per-platform firmware interfaces.
+ *
+ *  Copyright (C) 2011 The Chromium OS Authors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <linux/chromeos_platform.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+
+/* TODO:
+ * let firmware assign gpio_lines
+ * u32 gpio_data = (gpio_lines << 1) | is_active_high;
+ */
+
+/* gpio lines */
+#define GPIO_RECOVERY  56
+#define GPIO_DEVELOPER 168
+#define GPIO_FW_WP     59
+
+/* TODO:
+ * replace the shared memory block with FDT
+ * or structured ATAGS
+ */
+
+#define FIRMWARE_SHARED_PHYSICAL_SIZE (1024 * 1024)
+
+/* shared data layout in phisical memory */
+#define SIZE_SIGNATURE         16
+#define SIZE_CHSW              4
+#define SIZE_HWID              256
+#define SIZE_FWID              256
+#define SIZE_FRID              256
+#define SIZE_BOOT_REASON       4
+#define SIZE_ACTIVE_MAIN       4
+#define SIZE_ACTIVE_EC         4
+#define SIZE_ACTIVE_MAIN_TYPE  4
+#define SIZE_RECOVERY_REASON   4
+#define SIZE_GPIO              (4 * 11)
+#define SIZE_NV_OFFSET         4
+#define SIZE_NV_SIZE           4
+#define SIZE_FMAP_ADDR         8
+#define SIZE_NVBLK_LBA         8
+#define SIZE_NV_COPY           16
+
+#define OFFSET_SIGNATURE       0
+#define OFFSET_CHSW            (OFFSET_SIGNATURE + SIZE_SIGNATURE)
+#define OFFSET_HWID            (OFFSET_CHSW + SIZE_CHSW)
+#define OFFSET_FWID            (OFFSET_HWID + SIZE_HWID)
+#define OFFSET_FRID            (OFFSET_FWID + SIZE_FWID)
+#define OFFSET_BOOT_REASON     (OFFSET_FRID + SIZE_FRID)
+#define OFFSET_ACTIVE_MAIN     (OFFSET_BOOT_REASON + SIZE_BOOT_REASON)
+#define OFFSET_ACTIVE_EC       (OFFSET_ACTIVE_MAIN + SIZE_ACTIVE_MAIN)
+#define OFFSET_ACTIVE_MAIN_TYPE        (OFFSET_ACTIVE_EC + SIZE_ACTIVE_EC)
+#define OFFSET_RECOVERY_REASON (OFFSET_ACTIVE_MAIN_TYPE + SIZE_ACTIVE_MAIN_TYPE)
+#define OFFSET_GPIO            (OFFSET_RECOVERY_REASON + SIZE_RECOVERY_REASON)
+#define OFFSET_NV_OFFSET       (OFFSET_GPIO + SIZE_GPIO)
+#define OFFSET_NV_SIZE         (OFFSET_NV_OFFSET + SIZE_NV_OFFSET)
+#define OFFSET_FMAP_ADDR       (OFFSET_NV_SIZE + SIZE_NV_SIZE)
+#define OFFSET_NVBLK_LBA       (OFFSET_FMAP_ADDR + SIZE_FMAP_ADDR)
+#define OFFSET_NV_COPY         (OFFSET_NVBLK_LBA + SIZE_NVBLK_LBA)
+
+#define MODULE_NAME "chromeos_arm"
+static struct dentry *debugfs_entry;
+
+static void *firmware_shared_data;
+
+static u64 firmware_cookie_lba;
+
+static u64 get_firmware_u64(unsigned offset)
+{
+       return (*(u64*)(firmware_shared_data + offset));
+}
+
+static int check_firmware_signature(void)
+{
+       const char signature[] = "CHROMEOS";
+       return memcmp(firmware_shared_data, signature, sizeof(signature));
+}
+
+static int chromeos_arm_show(struct seq_file *s, void *unused)
+{
+       seq_write(s, firmware_shared_data, OFFSET_NV_COPY + SIZE_NV_COPY);
+       return 0;
+}
+
+static int debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, chromeos_arm_show, inode->i_private);
+}
+
+static const struct file_operations dbg_fops = {
+       .open           = debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void chromeos_arm_exit(void)
+{
+       if (debugfs_entry) {
+               debugfs_remove(debugfs_entry);
+               debugfs_entry = NULL;
+       }
+
+       if (firmware_shared_data) {
+               iounmap(firmware_shared_data);
+               firmware_shared_data = NULL;
+       }
+       pr_debug(MODULE_NAME ": removed\n");
+}
+
+int chromeos_arm_init(void)
+{
+       if (!phys_window_base) {
+               pr_err(MODULE_NAME ": memory window base undefined\n");
+               return -ENODEV;
+       }
+
+       pr_info(MODULE_NAME ": memory window base at %llx\n", phys_window_base);
+
+       /*
+        * TODO(vbendeb): FIXME: we are getting a pointer to some memory which
+        * is beyond the kernel controlled memory range. Strictly speaking
+        * this pointer should not be just dereferenced, ioread()/iowrite()
+        * should be used instead to comply with some code analysis tools and
+        * run time checks (when enabled). A possible solution would be to
+        * copy data from the window into a kernel allocated buffer.
+        *
+        * This will have to be addressed when the FDT rework comes along.
+        */
+       firmware_shared_data = ioremap(phys_window_base,
+                                      FIRMWARE_SHARED_PHYSICAL_SIZE);
+       if (!firmware_shared_data) {
+               pr_err(MODULE_NAME ": failed to map address %llx\n",
+                      phys_window_base);
+               return -EINVAL;
+       }
+
+       if (check_firmware_signature()) {
+               pr_err(MODULE_NAME ": signature verification failed!\n");
+               goto error_exit;
+       }
+
+       debugfs_entry = debugfs_create_file(MODULE_NAME, S_IRUGO,
+                                           NULL, NULL, &dbg_fops);
+       if (!debugfs_entry) {
+               pr_err(MODULE_NAME ": signature verification failed!\n");
+               goto error_exit;
+       }
+       firmware_cookie_lba = get_firmware_u64(OFFSET_NVBLK_LBA);
+       pr_debug(MODULE_NAME ": firmware cookie lba = %llx\n",
+                firmware_cookie_lba);
+       return 0;
+
+ error_exit:
+       chromeos_arm_exit();
+       return -ENODEV;
+}
+
+MODULE_AUTHOR("ChromiumOS Authors");
+MODULE_LICENSE("GPL");
+
+module_init(chromeos_arm_init);
+module_exit(chromeos_arm_exit);
index 02e72ac..7f16af3 100644 (file)
@@ -19,6 +19,8 @@ extern bool chromeos_is_devmode(void);
  */
 extern int chromeos_set_need_recovery(void);
 
+extern u64 phys_window_base;
+
 #else
 
 /* Stubbed-out versions so we can keep code common */