CHROMIUM: Refactor chromeos platform layer to cover both arm and x86.
authorVadim Bendebury <vbendeb@chromium.org>
Fri, 6 May 2011 21:04:18 +0000 (14:04 -0700)
committerGrant Grundler <grundler@google.com>
Thu, 24 May 2012 22:14:34 +0000 (15:14 -0700)
This CL completes the set of modifications required to support
chromeos ARM platforms (see
http://codereview.chromium.org/6883204 and
http://codereview.chromium.org/6902164 submitted earlier).

The chromeos.c interface layer is refactored: the platform
independent components consolidated, and platform specific ones
are moved to the appropriate platform modules. The ability to run
arm/chromos_arm.c as a module is eliminated, and the default
value of the shared memory window base is set.

The unused APIs (chromeos_is_devmode() and
chromeos_initialized()) are removed, appropriate Kconfig and
Makefile changes are made to reflect single chromeos.c module for
both platforms.

fs/proc/breakme.c is modified to allow requesting a recovery mode
reboot, to facilitate testing of the chromeos API.

BUG=chromium-os:12522
TEST=manual:

. build the new kernel image for mario, alex and kaen

. on all platforms run `crossystem' and observe the results (the
  results look reasonable).

. on all systems request reboot in recovery mode using `crossystem
  recovery_request=0xc1' and reboot. Observe the systems come back in
  recovery mode.

. on mario and alex recuest recovery by executing `echo need_recovery
  > /proc/breakme' and reboot. Observe the systems come back in
  recovery mode.

Change-Id: Ifa30aafa110479ee8981325a5e08fb3127ef8b6e
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: http://gerrit.chromium.org/gerrit/450
Reviewed-by: Olof Johansson <olofj@chromium.org>
[olofj: removed breakme modification when splitting branches]
Signed-off-by: Olof Johansson <olofj@chromium.org>
14 files changed:
drivers/platform/Kconfig
drivers/platform/Makefile
drivers/platform/arm/Kconfig
drivers/platform/arm/Makefile
drivers/platform/arm/chromeos.c [deleted file]
drivers/platform/arm/chromeos_arm.c
drivers/platform/chromeos.c [new file with mode: 0644]
drivers/platform/chromeos.h [new file with mode: 0644]
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/chromeos.c [deleted file]
drivers/platform/x86/chromeos_acpi.c
drivers/platform/x86/chromeos_acpi.h [deleted file]
include/linux/chromeos_platform.h

index 7e0a663..7c47a8c 100644 (file)
@@ -7,3 +7,12 @@ endif
 if ARM
 source "drivers/platform/arm/Kconfig"
 endif
+
+config CHROMEOS
+       bool
+       depends on ARM_CHROMEOS_FIRMWARE || (NVRAM && ACPI_CHROMEOS)
+
+       ---help---
+         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.
index 13a8d2a..189556a 100644 (file)
@@ -3,3 +3,4 @@
 #
 obj-$(CONFIG_ARM)              += arm/
 obj-$(CONFIG_X86)              += x86/
+obj-$(CONFIG_CHROMEOS)         += chromeos.o
index f5e97ea..816b682 100644 (file)
@@ -14,20 +14,11 @@ menuconfig ARM_PLATFORM_DEVICES
 if ARM_PLATFORM_DEVICES
 
 config ARM_CHROMEOS_FIRMWARE
-       tristate "ChromeOS firmware interface driver"
+       bool "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
index bf97d26..67814b4 100644 (file)
@@ -3,4 +3,3 @@
 # 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
deleted file mode 100644 (file)
index e531015..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  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);
-
index adfa40b..01dd2b3 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/ide.h>
+#include "../chromeos.h"
 
 /* TODO:
  * replace the shared memory block with FDT
@@ -53,6 +54,7 @@ struct shared_data {
 
 static struct dentry *debugfs_entry;
 static struct shared_data *firmware_shared_data;
+static u64 phys_window_base = 0x3ff00000;
 
 /* location where the nvram data blends into the sector on the MMC device */
 static u16 nv_offset, nv_size;
@@ -75,7 +77,8 @@ static int verify_shared_memory(void)
 
        if ((nv_offset > SECTOR_SIZE) ||
            !nv_size ||
-           ((nv_offset + nv_size) > SECTOR_SIZE)) {
+           ((nv_offset + nv_size) > SECTOR_SIZE) ||
+           (nv_size > MAX_NVRAM_BUFFER_SIZE)) {
                /* nvram block won't fit into a sector */
                pr_err(MODULE_NAME ": bad nvram location: %d:%d!\n",
                       nv_offset, nv_size);
@@ -181,27 +184,17 @@ static int chromeos_write_nvram_block(struct page *page, sector_t sector)
 
 
 /*
- * This function excpects exactly nv_size bytes to be passed in for writing.
- * It reads the appropriate mmc one sector block, blends in the new nvram
- * contents and then writes the sector back. If successful, the cached nvram
- * in the shared memory is also updated.
+ * This function accepts a buffer with exactly nv_size bytes. It reads the
+ * appropriate mmc one sector block, blends in the new nvram contents and then
+ * writes the sector back. If successful, the cached nvram in the shared
+ * memory is also updated.
  */
-static int chromeos_write(struct file *unused1, const char __user *data,
-                         size_t len, loff_t *unused2)
+static int _chromeos_write(const u8 *data)
 {
        struct page *page;
        char *virtual_addr;
        int rv;
 
-       if (!access_ok(VERIFY_READ, data, len))
-               return -EFAULT;
-
-       if (len != nv_size) {
-               pr_err(MODULE_NAME ": %d != %d, invalid block size\n",
-                      len, nv_size);
-               return -EINVAL;
-       }
-
        page = alloc_page(GFP_NOIO);
        if (!page) {
                pr_err(MODULE_NAME ": page allocation failed\n");
@@ -219,9 +212,9 @@ static int chromeos_write(struct file *unused1, const char __user *data,
        if (rv)
                goto unwind;
 
-       /* as a sanity check, lets' confirm that what we read is indeed the
-        *  sector containing the NVRAM. Note that on a running system the
-        *  NVRAM block will include its CRC.
+       /* As a sanity check, let's confirm that what we read is indeed the
+        * sector containing the NVRAM. Note that on a running system the
+        * NVRAM block will include its CRC.
         */
        if (memcmp(virtual_addr + nv_offset,
                   firmware_shared_data->nvcxt_cache, nv_size)) {
@@ -235,19 +228,15 @@ static int chromeos_write(struct file *unused1, const char __user *data,
         * Sector has been read, lets blend in nvram data and write the sector
         * back.
         */
-       if (copy_from_user(virtual_addr + nv_offset, data, len)) {
-               pr_err(MODULE_NAME ": copy failed!\n");
-               rv = -EFAULT;
-               goto unwind;
-       }
+       memcpy(virtual_addr + nv_offset, data, nv_size);
 
        rv = chromeos_write_nvram_block(page, firmware_shared_data->nvcxt_lba);
        if (!rv) {
                /* Write was successful, now update the local cache */
                memcpy(firmware_shared_data->nvcxt_cache,
                       virtual_addr + nv_offset,
-                      len);
-               rv = len;
+                      nv_size);
+               rv = nv_size;
        }
 
 unwind:
@@ -255,6 +244,27 @@ unwind:
        return rv;
 }
 
+static int chromeos_write(struct file *unused1, const char __user *data,
+                         size_t len, loff_t *unused2)
+{
+       u8 local_copy[MAX_NVRAM_BUFFER_SIZE];
+
+       if (!access_ok(VERIFY_READ, data, len))
+               return -EFAULT;
+
+       if (len != nv_size) {
+               pr_err(MODULE_NAME ": %d != %d, invalid block size\n",
+                      len, nv_size);
+               return -EINVAL;
+       }
+
+       if (copy_from_user(local_copy, data, len)) {
+               pr_err(MODULE_NAME ": copy failed!\n");
+               return -EFAULT;
+       }
+       return _chromeos_write(local_copy);
+}
+
 static const struct file_operations dbg_fops = {
        .open           = debugfs_open,
        .read           = seq_read,
@@ -263,7 +273,47 @@ static const struct file_operations dbg_fops = {
        .release        = single_release,
 };
 
-static void chromeos_arm_exit(void)
+
+/*
+ * Read the nvram buffer contents into the user provided space.
+ *
+ * retrun number of bytes copied, or -1 on any error.
+ */
+int chromeos_platform_read_nvram(u8 *nvram_buffer, int buf_size)
+{
+       if (!firmware_shared_data) {
+               pr_err(MODULE_NAME ": %s NVRAM not configured!\n", __func__);
+               return -1;
+       }
+
+       if (buf_size < nv_size) {
+               pr_err(MODULE_NAME
+                      ": not enough room to read nvram (%d < %d)\n",
+                      buf_size, nv_size);
+               return -1;
+       }
+
+       memcpy(nvram_buffer, firmware_shared_data->nvcxt_cache, nv_size);
+       return nv_size;
+}
+
+int chromeos_platform_write_nvram(u8 *nvram_buffer, int buf_size)
+{
+       if (!firmware_shared_data) {
+               pr_err(MODULE_NAME ": %sw NVRAM not configured!\n", __func__);
+               return -1;
+       }
+
+       if (buf_size != nv_size) {
+               pr_err(MODULE_NAME ": wrong write buffer size (%d != %d)\n",
+                      buf_size, nv_size);
+               return -1;
+       }
+
+       return _chromeos_write(nvram_buffer);
+}
+
+static void __init chromeos_arm_shutdown(void)
 {
        if (debugfs_entry) {
                debugfs_remove(debugfs_entry);
@@ -274,10 +324,9 @@ static void chromeos_arm_exit(void)
                iounmap(firmware_shared_data);
                firmware_shared_data = NULL;
        }
-       pr_debug(MODULE_NAME ": removed\n");
 }
 
-int chromeos_arm_init(void)
+static int __init chromeos_arm_init(void)
 {
        if (!phys_window_base) {
                pr_err(MODULE_NAME ": memory window base undefined\n");
@@ -307,26 +356,38 @@ int chromeos_arm_init(void)
        nv_offset = firmware_shared_data->vbnv[0];
        nv_size = firmware_shared_data->vbnv[1];
 
-       if (verify_shared_memory())
-               goto error_exit;
+       if (verify_shared_memory()) {
+               chromeos_arm_shutdown();
+               return -EINVAL;
+       }
+
 
        debugfs_entry = debugfs_create_file(MODULE_NAME, S_IRUGO | S_IWUSR,
                                            NULL, NULL, &dbg_fops);
        if (!debugfs_entry) {
                pr_err(MODULE_NAME ": failed to create a debugfs file!\n");
-               goto error_exit;
+               chromeos_arm_shutdown();
+               return -EINVAL;
        }
        pr_debug(MODULE_NAME ": firmware cookie lba = %llx\n",
                 firmware_shared_data->nvcxt_lba);
        return 0;
-
- error_exit:
-       chromeos_arm_exit();
-       return -ENODEV;
 }
+subsys_initcall(chromeos_arm_init);
+
+static int __init get_mem_base(char *p)
+{
+       char *endptr;   /* local pointer to end of parsed string */
+       u64 base = simple_strtoull(p, &endptr, 0);
 
-MODULE_AUTHOR("ChromiumOS Authors");
-MODULE_LICENSE("GPL");
+       /* 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;
+}
 
-module_init(chromeos_arm_init);
-module_exit(chromeos_arm_exit);
+early_param("cros_shared_mem", get_mem_base);
diff --git a/drivers/platform/chromeos.c b/drivers/platform/chromeos.c
new file mode 100644 (file)
index 0000000..a76b891
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  ChromeOS platform support code. Glue layer between higher level functions
+ *  and per-platform firmware interfaces.
+ *
+ *  Copyright (C) 2010 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/types.h>
+#include <linux/chromeos_platform.h>
+#include <linux/module.h>
+#include "chromeos.h"
+
+static int chromeos_read_nvram(u8 *nvram_buffer, int buf_size);
+static int chromeos_write_nvram_byte(unsigned offset, u8 value);
+
+/* the following defines are copied from
+ * vboot_reference:firmware/lib/vboot_nvstorage.c.
+ */
+#define RECOVERY_OFFSET              2
+#define VBNV_RECOVERY_RW_INVALID_OS  0x43
+
+int chromeos_set_need_recovery(void)
+{
+       if (!chromeos_legacy_set_need_recovery())
+               return 0;
+
+       return chromeos_write_nvram_byte(RECOVERY_OFFSET,
+                                        VBNV_RECOVERY_RW_INVALID_OS);
+}
+
+/*
+ * Lifted from vboot_reference:firmware/lib/vboot_nvstorage.c and formatted.
+ *
+ * Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
+ * algorithm would be faster, but for only 15 bytes isn't worth the code size.
+ */
+static u8 crc8(const u8 *data, int len)
+{
+       unsigned crc = 0;
+       int i, j;
+
+       for (j = len; j; j--, data++) {
+               crc ^= (*data << 8);
+               for (i = 8; i; i--) {
+                       if (crc & 0x8000)
+                               crc ^= (0x1070 << 3);
+                       crc <<= 1;
+               }
+       }
+       return (u8)(crc >> 8);
+}
+
+static int chromeos_write_nvram_byte(unsigned offset, u8 value)
+{
+       u8 nvram_buffer[MAX_NVRAM_BUFFER_SIZE];
+
+       int size = chromeos_read_nvram(nvram_buffer, sizeof(nvram_buffer));
+
+       if (size <= 0)
+               return -EINVAL;
+
+       if (offset >= (size - 1))
+               return -EINVAL;
+
+       if (nvram_buffer[offset] == value)
+               return 0;
+
+       nvram_buffer[offset] = value;
+       nvram_buffer[size - 1] = crc8(nvram_buffer, size - 1);
+
+       return chromeos_platform_write_nvram(nvram_buffer, size);
+}
+
+/*
+ * Read nvram buffer contents and verify it. Return 0 on success and -1 on
+ * failure (uninitialized subsystem, corrupted crc8 value, not enough room in
+ * the buffer, etc.).
+ *
+ * If everything checks out - return number of bytes in the NVRAM buffer, -1
+ * on any error.
+ */
+static int chromeos_read_nvram(u8 *nvram_buffer, int buf_size)
+{
+       int size = chromeos_platform_read_nvram(nvram_buffer, buf_size);
+
+       if (size <= 0)
+               return -1;
+
+       if (nvram_buffer[size - 1] != crc8(nvram_buffer, size - 1)) {
+               pr_err("%s: NVRAM contents corrupted\n", __func__);
+               return -1;
+       }
+       return size;
+}
diff --git a/drivers/platform/chromeos.h b/drivers/platform/chromeos.h
new file mode 100644 (file)
index 0000000..7c2d8fa
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+#ifndef _DRIVERS_PLATFORM_CHROMEOS_H
+#define _DRIVERS_PLATFORM_CHROMEOS_H
+
+#define MAX_NVRAM_BUFFER_SIZE 64  /* Should be enough for anything. */
+
+#ifdef CONFIG_ACPI_CHROMEOS
+extern int chromeos_legacy_set_need_recovery(void);
+#else
+static inline int chromeos_legacy_set_need_recovery(void) { return -ENODEV; }
+#endif
+
+extern int chromeos_platform_read_nvram(u8 *nvram_buffer, int buf_size);
+extern int chromeos_platform_write_nvram(u8 *nvram_buffer, int buf_size);
+
+#endif /* _DRIVERS_PLATFORM_CHROMEOS_H */
index 5536568..46085da 100644 (file)
@@ -688,15 +688,6 @@ config ACPI_CHROMEOS
          This driver provides the firmware interface for the services exported
          through the CHROMEOS interfaces when using ChromeOS ACPI firmware.
 
-config CHROMEOS
-       bool
-       depends on NVRAM
-       depends on ACPI_CHROMEOS
-       ---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.
-
 config IBM_RTL
        tristate "Device driver to enable PRTL support"
        depends on X86 && PCI
index 727c213..c365c48 100644 (file)
@@ -51,4 +51,3 @@ obj-$(CONFIG_INTEL_OAKTRAIL)  += intel_oaktrail.o
 obj-$(CONFIG_SAMSUNG_Q10)      += samsung-q10.o
 obj-$(CONFIG_APPLE_GMUX)       += apple-gmux.o
 obj-$(CONFIG_ACPI_CHROMEOS)    += chromeos_acpi.o
-obj-$(CONFIG_CHROMEOS)         += chromeos.o
diff --git a/drivers/platform/x86/chromeos.c b/drivers/platform/x86/chromeos.c
deleted file mode 100644 (file)
index 8997c3e..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- *  ChromeOS platform support code. Glue layer between higher level functions
- *  and per-platform firmware interfaces.
- *
- *  Copyright (C) 2010 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/kernel.h>
-#include <linux/module.h>
-#include <linux/nvram.h>
-#include <linux/types.h>
-#include <linux/chromeos_platform.h>
-
-#include "chromeos_acpi.h"
-
-static bool chromeos_inited;
-static bool chromeos_nvram_buffer_available;
-static int chromeos_read_nvram(u8 *nvram_buffer, int buf_size);
-static int chromeos_write_nvram(unsigned offset, u8 value);
-
-#define MAX_NVRAM_BUFFER_SIZE 64  /* Should be enough for anything. */
-
-/* the following defines are copied from
- * vboot_reference:firmware/lib/vboot_nvstorage.c.
- */
-#define RECOVERY_OFFSET              2
-#define VBNV_RECOVERY_RW_INVALID_OS  0x43
-
-bool chromeos_is_devmode(void)
-{
-       struct chromeos_acpi_datum *chsw = &chromeos_acpi_if_data.switch_state;
-       /*
-        * If switch_state is unset, report system as in devmode since we're
-        * probably running on a non-chromeos system.
-        */
-       return (!chsw->cad_is_set) || (chsw->cad_value & CHSW_DEVELOPER_MODE);
-}
-EXPORT_SYMBOL(chromeos_is_devmode);
-
-/*
- * This function is used with BIOSes which do not export VBNV element through
- * ACPI. These BIOSes use a fixed location in NVRAM to communicate the need to
- * restart in recovery mode.
- */
-static void chromeos_set_nvram_flag(int index, unsigned char flag)
-{
-       unsigned char cur;
-
-       cur = nvram_read_byte(index);
-       /* already set. */
-       if (cur & flag)
-               return;
-       nvram_write_byte(cur | flag, index);
-}
-
-static bool chromeos_on_legacy_firmware(void)
-{
-       /*
-        * Presense of the CHNV ACPI element implies running on a legacy
-        * firmware
-        */
-       return chromeos_acpi_if_data.chnv.cad_is_set;
-}
-
-int chromeos_set_need_recovery(void)
-{
-       if (chromeos_on_legacy_firmware()) {
-               /* Use fixed location to request recovery reboot. */
-               struct chromeos_acpi_datum *chnv = &chromeos_acpi_if_data.chnv;
-               chromeos_set_nvram_flag(chnv->cad_value,
-                                              CHNV_RECOVERY_FLAG);
-               return 0;
-       }
-
-       if (chromeos_nvram_buffer_available) {
-               return chromeos_write_nvram(RECOVERY_OFFSET,
-                                           VBNV_RECOVERY_RW_INVALID_OS);
-       }
-       return -EINVAL;
-}
-EXPORT_SYMBOL(chromeos_set_need_recovery);
-
-bool chromeos_initialized(void)
-{
-       return chromeos_inited;
-}
-EXPORT_SYMBOL(chromeos_initialized);
-
-/*
- * Lifted from vboot_reference:firmware/lib/vboot_nvstorage.c and formatted.
- *
- * Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
- * algorithm would be faster, but for only 15 bytes isn't worth the code size.
- */
-static u8 crc8(const u8 *data, int len)
-{
-       unsigned crc = 0;
-       int i, j;
-
-       for (j = len; j; j--, data++) {
-               crc ^= (*data << 8);
-               for (i = 8; i; i--) {
-                       if (crc & 0x8000)
-                               crc ^= (0x1070 << 3);
-                       crc <<= 1;
-               }
-       }
-       return (u8)(crc >> 8);
-}
-
-static int chromeos_write_nvram(unsigned offset, u8 value)
-{
-       u8 nvram_buffer[MAX_NVRAM_BUFFER_SIZE];
-       u8 new_crc;
-       unsigned size;
-       unsigned base;
-
-       if (chromeos_read_nvram(nvram_buffer, sizeof(nvram_buffer)))
-               return -ENODEV;
-
-       size = chromeos_acpi_if_data.nv_size.cad_value;
-       base = chromeos_acpi_if_data.nv_base.cad_value;;
-
-       if (offset >= (size - 1))
-               return -EINVAL;
-
-       nvram_buffer[offset] = value;
-       new_crc = crc8(nvram_buffer, size - 1);
-
-       nvram_write_byte(base + offset, value);
-       nvram_write_byte(base + size - 1, new_crc);
-       return 0;
-}
-
-/*
- * read nvram buffer contents and verify it.
- * Return 0 on success and -1 on failure (uninitialized, or corrupted crc8
- * value). The passed in memory space is guaranteed to be large enough for the
- * nvram buffer contents.
- */
-static int chromeos_read_nvram(u8 *nvram_buffer, int buf_size)
-{
-       int start, size, i;
-
-       if (!chromeos_inited)
-               return -1;
-
-       start = chromeos_acpi_if_data.nv_base.cad_value;
-       size = chromeos_acpi_if_data.nv_size.cad_value;
-
-       if (size > buf_size) {
-               pr_err("%s: buffer range exceeded\n", __func__);
-               return -1;
-       }
-
-       for (i = 0; i < size; i++)
-               nvram_buffer[i] = nvram_read_byte(start++);
-
-       if (nvram_buffer[size - 1] != crc8(nvram_buffer, size - 1)) {
-               pr_err("%s: NVRAM contents corrupted\n", __func__);
-               return -1;
-       }
-       return 0;
-}
-
-static int __init chromeos_init(void)
-{
-       u8 nvram_buffer[MAX_NVRAM_BUFFER_SIZE];
-
-       if (!chromeos_acpi_if_data.switch_state.cad_is_set) {
-               pr_err("Chrome OS platform not found\n");
-               return -ENODEV;
-       }
-
-       chromeos_inited = true;
-
-       if (chromeos_on_legacy_firmware()) {
-               pr_info("Legacy ChromeOS firmware detected\n");
-               return 0;
-       }
-
-       pr_info("ChromeOS firmware detected\n");
-
-       /* check NVRAM buffer sanity */
-       if (!chromeos_acpi_if_data.nv_base.cad_is_set ||
-           !chromeos_acpi_if_data.nv_size.cad_is_set ||
-           (chromeos_acpi_if_data.nv_size.cad_value > MAX_NVRAM_BUFFER_SIZE) ||
-           chromeos_read_nvram(nvram_buffer, sizeof(nvram_buffer))) {
-               pr_warning("Chrome NVram buffer not used\n");
-               chromeos_nvram_buffer_available = false;
-       } else {
-               chromeos_nvram_buffer_available = true;
-       }
-
-       return 0;
-}
-subsys_initcall_sync(chromeos_init);
index 33fcb01..61e52f7 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/nvram.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 
-#include "chromeos_acpi.h"
+#define CHNV_DEBUG_RESET_FLAG  0x40         /* flag for S3 reboot */
+#define CHNV_RECOVERY_FLAG     0x80         /* flag for recovery reboot */
 
-struct chromeos_acpi_if chromeos_acpi_if_data;
-EXPORT_SYMBOL_GPL(chromeos_acpi_if_data);
+#define CHSW_RECOVERY_FW       0x00000002   /* recovery button depressed */
+#define CHSW_RECOVERY_EC       0x00000004   /* recovery button depressed */
+#define CHSW_DEVELOPER_MODE    0x00000020   /* developer switch set */
+#define CHSW_WP                        0x00000200   /* write-protect (optional) */
+
+/*
+ * Structure containing one ACPI exported integer along with the validity
+ * flag.
+ */
+struct chromeos_acpi_datum {
+       unsigned cad_value;
+       bool     cad_is_set;
+};
+
+/*
+ * Structure containing the set of ACPI exported integers required by chromeos
+ * wrapper.
+ */
+struct chromeos_acpi_if {
+       struct chromeos_acpi_datum      switch_state;
+
+       /* chnv is a single byte offset in nvram. exported by older firmware */
+       struct chromeos_acpi_datum      chnv;
+
+       /* vbnv is an address range in nvram, exported by newer firmware */
+       struct chromeos_acpi_datum      nv_base;
+       struct chromeos_acpi_datum      nv_size;
+};
 
 #define MY_LOGPREFIX "chromeos_acpi: "
 #define MY_ERR KERN_ERR MY_LOGPREFIX
@@ -57,9 +85,11 @@ static const struct acpi_device_id chromeos_device_ids[] = {
 };
 
 MODULE_DEVICE_TABLE(acpi, chromeos_device_ids);
+
 static int chromeos_device_add(struct acpi_device *device);
 static int chromeos_device_remove(struct acpi_device *device, int type);
 
+static struct chromeos_acpi_if chromeos_acpi_if_data;
 static struct acpi_driver chromeos_acpi_driver = {
        .name = "ChromeOS Device",
        .class = "ChromeOS",
@@ -113,6 +143,106 @@ struct chromeos_acpi_dev {
 
 static struct chromeos_acpi_dev chromeos_acpi = { };
 
+static bool chromeos_on_legacy_firmware(void)
+{
+       /*
+        * Presense of the CHNV ACPI element implies running on a legacy
+        * firmware
+        */
+       return chromeos_acpi_if_data.chnv.cad_is_set;
+}
+
+/*
+ * This function operates on legacy BIOSes which do not export VBNV element
+ * through ACPI. These BIOSes use a fixed location in NVRAM to contain a
+ * bitmask of known flags.
+ *
+ * @flag - the bitmask to set, it is the responsibility of the caller to set
+ *         the proper bits.
+ *
+ * returns 0 on success (is running in legacy mode and chnv is initialized) or
+ *         -1 otherwise.
+ */
+static int chromeos_set_nvram_flag(u8 flag)
+{
+       u8 cur;
+       unsigned index = chromeos_acpi_if_data.chnv.cad_value;
+
+       if (!chromeos_on_legacy_firmware())
+               return -ENODEV;
+
+       cur = nvram_read_byte(index);
+
+       if ((cur & flag) != flag)
+               nvram_write_byte(cur | flag, index);
+       return 0;
+}
+
+int chromeos_legacy_set_need_recovery(void)
+{
+       return chromeos_set_nvram_flag(CHNV_RECOVERY_FLAG);
+}
+
+/*
+ * Read the nvram buffer contents into the user provided space.
+ *
+ * retrun number of bytes copied, or -1 on any error.
+ */
+int chromeos_platform_read_nvram(u8 *nvram_buffer, int buf_size)
+{
+
+       int base, size, i;
+
+       if (!chromeos_acpi_if_data.nv_base.cad_is_set ||
+           !chromeos_acpi_if_data.nv_size.cad_is_set) {
+               printk(MY_ERR "%s: NVRAM not configured!\n", __func__);
+               return -ENODEV;
+       }
+
+       base = chromeos_acpi_if_data.nv_base.cad_value;
+       size = chromeos_acpi_if_data.nv_size.cad_value;
+
+       if (buf_size < size) {
+               pr_err("%s: not enough room to read nvram (%d < %d)\n",
+                      __func__, buf_size, size);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < size; i++)
+               nvram_buffer[i] = nvram_read_byte(base++);
+
+       return size;
+}
+
+int chromeos_platform_write_nvram(u8 *nvram_buffer, int buf_size)
+{
+       unsigned base, size, i;
+
+       if (!chromeos_acpi_if_data.nv_base.cad_is_set ||
+           !chromeos_acpi_if_data.nv_size.cad_is_set) {
+               printk(MY_ERR "%s: NVRAM not configured!\n", __func__);
+               return -ENODEV;
+       }
+
+       size = chromeos_acpi_if_data.nv_size.cad_value;
+       base = chromeos_acpi_if_data.nv_base.cad_value;
+
+       if (buf_size != size) {
+               printk(MY_ERR "%s: wrong buffer size (%d != %d)!\n", __func__,
+                      buf_size, size);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < size; i++) {
+               u8 c;
+
+               c = nvram_read_byte(base + i);
+               if (c == nvram_buffer[i])
+                       continue;
+               nvram_write_byte(nvram_buffer[i], base + i);
+       }
+       return 0;
+}
 
 /*
  * To show attribute value just access the container structure's `value'
@@ -642,7 +772,8 @@ static int __init chromeos_acpi_init(void)
                chromeos_acpi.p_dev = NULL;
                return ret;
        }
-       printk(MY_INFO "installed\n");
+       printk(MY_INFO "installed%s\n",
+              chromeos_on_legacy_firmware() ? " (legacy mode)" : "");
        return 0;
 }
 
diff --git a/drivers/platform/x86/chromeos_acpi.h b/drivers/platform/x86/chromeos_acpi.h
deleted file mode 100644 (file)
index 9fe6bf1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef _DRIVERS_PLATFORM_X86_CHROMEOS_ACPI_H
-#define _DRIVERS_PLATFORM_X86_CHROMEOS_ACPI_H
-
-#include <linux/types.h>
-
-#define NVRAM_BYTES (128 - NVRAM_FIRST_BYTE) /* from drivers/char/nvram.c */
-
-#define CHNV_DEBUG_RESET_FLAG  0x40         /* flag for S3 reboot */
-#define CHNV_RECOVERY_FLAG     0x80         /* flag for recovery reboot */
-
-#define CHSW_RECOVERY_FW       0x00000002   /* recovery button depressed */
-#define CHSW_RECOVERY_EC       0x00000004   /* recovery button depressed */
-#define CHSW_DEVELOPER_MODE    0x00000020   /* developer switch set */
-#define CHSW_WP                        0x00000200   /* write-protect (optional) */
-
-/*
- * Structure containing one ACPI exported integer along with the validity
- * flag.
- */
-struct chromeos_acpi_datum {
-       unsigned cad_value;
-       bool     cad_is_set;
-};
-
-/*
- * Structure containing the set of ACPI exported integers required by chromeos
- * wrapper.
- */
-struct chromeos_acpi_if {
-       struct chromeos_acpi_datum      switch_state;
-
-       /* chnv is a single byte offset in nvram. exported by older firmware */
-       struct chromeos_acpi_datum      chnv;
-
-       /* vbnv is an address range in nvram, exported by newer firmware */
-       struct chromeos_acpi_datum      nv_base;
-       struct chromeos_acpi_datum      nv_size;
-};
-
-
-extern struct chromeos_acpi_if chromeos_acpi_if_data;
-
-#endif /* _DRIVERS_PLATFORM_X86_CHROMEOS_ACPI_H */
index 7f16af3..3d22906 100644 (file)
@@ -4,31 +4,23 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 
+extern int chromeos_platform_read_nvram(u8 *nvram_buffer, int buf_size);
+extern int chromeos_platform_write_nvram(u8 *nvram_buffer, int buf_size);
+
 #ifdef CONFIG_CHROMEOS
 /*
  * ChromeOS platform support code. Glue layer between higher level functions
  * and per-platform firmware interfaces.
  */
 
-/* Checks to see if the current device is in devmode */
-extern bool chromeos_is_devmode(void);
-
 /*
  * Set the taint bit telling firmware that the currently running side needs
  * recovery (or reinstall).
  */
 extern int chromeos_set_need_recovery(void);
 
-extern u64 phys_window_base;
-
 #else
 
-/* Stubbed-out versions so we can keep code common */
-static inline bool chromeos_is_devmode(void)
-{
-       return true;
-}
-
 static inline int chromeos_set_need_recovery(void)
 {
        return -ENODEV;