summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2011-08-17 15:24:55 -0700
committerSimon Glass <sjg@chromium.org>2011-08-30 13:25:18 -0700
commitf759070b539747df59380ca0164b25515d927908 (patch)
tree24607aaca599f57a75eb1a393b63f3217e3a4ea7 /lib
parent569408cfc87ca2cc9a45e1ebbb934624788610bf (diff)
CHROMIUMOS: Refactor boot_device to support multiple devices nicely
Now that we have MMC, USB and IDE, with some enabled for only some platforms, the code has become ugly. This refactors the code to separate out each device into its own file, with a generic start/scan interface. This also fixes the problem with indexing of devices, where it could not cope with MMC and IDE active at the same time. BUG=chromium-os:19518 TEST=build on Seaboard; vbexport_test diskinfo See that all boot devices are found with SD and USB inserted Change-Id: I4844f7b33885ec01e922686a17c90afdf0a55a9d Reviewed-on: http://gerrit.chromium.org/gerrit/6254 Tested-by: Simon Glass <sjg@chromium.org> Reviewed-by: Che-Liang Chiou <clchiou@chromium.org> Reviewed-by: Stefan Reinauer <reinauer@google.com> Reviewed-by: Anton Staaf <robotboy@chromium.org> Reviewed-on: http://gerrit.chromium.org/gerrit/6918 Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/vbexport/Makefile3
-rw-r--r--lib/vbexport/boot_device.c239
-rw-r--r--lib/vbexport/boot_device.h75
-rw-r--r--lib/vbexport/boot_device_ide.c51
-rw-r--r--lib/vbexport/boot_device_mmc.c61
-rw-r--r--lib/vbexport/boot_device_usb.c60
-rw-r--r--lib/vbexport/misc.c8
7 files changed, 366 insertions, 131 deletions
diff --git a/lib/vbexport/Makefile b/lib/vbexport/Makefile
index 64e633a46b..974dd43488 100644
--- a/lib/vbexport/Makefile
+++ b/lib/vbexport/Makefile
@@ -13,6 +13,9 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libvbexport.a
COBJS-$(CONFIG_CHROMEOS) += boot_device.o
+COBJS-$(CONFIG_CHROMEOS_IDE) += boot_device_ide.o
+COBJS-$(CONFIG_MMC) += boot_device_mmc.o
+COBJS-$(CONFIG_CHROMEOS_USB) += boot_device_usb.o
COBJS-$(CONFIG_CHROMEOS) += display.o
COBJS-$(CONFIG_CHROMEOS) += keyboard.o
COBJS-$(CONFIG_CHROMEOS) += load_firmware.o
diff --git a/lib/vbexport/boot_device.c b/lib/vbexport/boot_device.c
index adb67e3253..d3c43ba946 100644
--- a/lib/vbexport/boot_device.c
+++ b/lib/vbexport/boot_device.c
@@ -9,24 +9,21 @@
*/
#include <common.h>
-#ifdef CONFIG_MMC
-#include <mmc.h>
-#endif
#include <part.h>
-#include <usb.h>
#include <chromeos/common.h>
#include <linux/list.h>
/* Import the header files from vboot_reference. */
#include <vboot_api.h>
+#include "boot_device.h"
+
#define PREFIX "boot_device: "
-/*
- * Total number of storage devices, USB + MMC + reserved.
- * MMC is 2 now. Reserve extra 3 for margin of safety.
- */
-#define MAX_DISK_INFO (USB_MAX_STOR_DEV + 2 + 3)
+/* Maximum number of devices we can support */
+enum {
+ MAX_DISK_INFO = 10,
+};
/* TODO Move these definitions to vboot_wrapper.h or somewhere like that. */
enum {
@@ -36,151 +33,115 @@ enum {
VBERROR_DISK_WRITE_ERROR,
};
-static uint32_t get_dev_flags(const block_dev_desc_t *dev)
-{
- return dev->removable ? VB_DISK_FLAG_REMOVABLE : VB_DISK_FLAG_FIXED;
-}
+/* Boot interfaces that we know about */
+struct boot_interface *interface[IF_TYPE_MAX];
+int interface_count;
-static const char *get_dev_name(const block_dev_desc_t *dev)
+int boot_device_register_interface(struct boot_interface *iface)
{
- /*
- * See the definitions of IF_TYPE_* in /include/part.h.
- * 8 is max size of strings, the "UNKNOWN".
- */
- static const char all_disk_types[IF_TYPE_MAX][8] = {
- "UNKNOWN", "IDE", "SCSI", "ATAPI", "USB",
- "DOC", "MMC", "SD", "SATA"};
-
- if (dev->if_type >= IF_TYPE_MAX) {
- return all_disk_types[0];
- }
- return all_disk_types[dev->if_type];
+ if (interface_count >= ARRAY_SIZE(interface))
+ return -1;
+ interface[interface_count++] = iface;
+ return 0;
}
-static void init_usb_storage(void)
+int boot_device_matches(const block_dev_desc_t *dev,
+ uint32_t disk_flags, uint32_t *flags)
{
- /*
- * We should stop all USB devices first. Otherwise we can't detect any
- * new devices.
- */
- usb_stop();
-
- if (usb_init() >= 0)
- usb_stor_scan(/*mode=*/1);
+ *flags = dev->removable ? VB_DISK_FLAG_REMOVABLE :
+ VB_DISK_FLAG_FIXED;
+ return (*flags & disk_flags) == disk_flags;
}
-block_dev_desc_t *iterate_internal_devices(int *index_ptr)
-{
-#ifdef CONFIG_MMC
- struct mmc *mmc;
- int index;
-
- for (index = *index_ptr; (mmc = find_mmc_device(index)); index++) {
- /* Skip device that cannot be initialized */
- if (!mmc_init(mmc))
- break;
- }
-
- /*
- * find_mmc_device() returns a pointer from a global linked list. So
- * &mmc->block_dev is not a dangling pointer after this function
- * is returned.
- */
-
- *index_ptr = index + 1;
- if (mmc)
- return &mmc->block_dev;
-#endif
-#ifdef CONFIG_CMD_IDE
-#ifdef CONFIG_MMC
- /* TODO(reinauer) Fix index handling first */
-#error "MMC and IDE can not be enabled at the same time right now."
-#endif
- block_dev_desc_t *ide;
- ide = ide_get_dev(*index_ptr);
- *index_ptr = *index_ptr + 1;
-
- if (ide)
- return ide;
-#endif
- return NULL;
-}
-
-block_dev_desc_t *iterate_usb_device(int *index_ptr)
-{
- return usb_stor_get_dev((*index_ptr)++);
-}
-
-/*
- * This appends [dev] to [info] and increments [count_ptr] if [disk_flags] is a
- * subset of the flags of [dev].
+/**
+ * Scan a list of devices and add those which match the supplied disk_flags
+ * to the info array.
+ *
+ * @param name Peripheral name
+ * @param devs List of devices to check
+ * @param count Number of devices
+ * @param disk_flags Disk flags which must be present for each device added
+ * @param info Output array of matching devices
+ * @return number of devices added (0 if none)
*/
-void add_device_if_flags_match(block_dev_desc_t *dev, const uint32_t disk_flags,
- VbDiskInfo *info, uint32_t *count_ptr)
+static int add_matching_devices(const char *name, block_dev_desc_t **devs,
+ int count, uint32_t disk_flags, VbDiskInfo *info)
{
- uint32_t flags = get_dev_flags(dev);
-
- /*
- * Only add this storage device if the properties of disk_flags is a
- * subset of the properties of flags.
- */
- if ((flags & disk_flags) != disk_flags)
- return;
-
- info->handle = (VbExDiskHandle_t)dev;
- info->bytes_per_lba = dev->blksz;
- info->lba_count = dev->lba;
- info->flags = flags;
- info->name = get_dev_name(dev);
- (*count_ptr)++;
+ int added = 0;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ block_dev_desc_t *dev = devs[i];
+ uint32_t flags;
+
+ /*
+ * Only add this storage device if the properties of
+ * disk_flags is a subset of the properties of flags.
+ */
+ if (boot_device_matches(dev, disk_flags, &flags)) {
+ info->handle = (VbExDiskHandle_t)dev;
+ info->bytes_per_lba = dev->blksz;
+ info->lba_count = dev->lba;
+ info->flags = flags;
+ info->name = name;
+ info++, added++;
+ }
+ }
+ return added;
}
-VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count_ptr,
- uint32_t disk_flags)
+VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count_ptr,
+ uint32_t disk_flags)
{
VbDiskInfo *infos;
- uint32_t count, max_count;
- int iterator_state;
- block_dev_desc_t *dev;
-
- *infos_ptr = NULL;
- *count_ptr = 0;
+ uint32_t max_count; /* maximum devices to scan for */
+ uint32_t count = 0; /* number of matching devices found */
+ block_dev_desc_t *dev[MAX_DISK_INFO];
+ int upto;
/* We return as many disk infos as possible. */
- /*
- * We assume there is only one non-removable storage device. So if the
- * caller asks for non-removable devices, we return at most one device.
- * Otherwise we return at most MAX_DISK_INFO device.
- */
- max_count = (disk_flags & VB_DISK_FLAG_REMOVABLE) ? MAX_DISK_INFO : 1;
-
- /* count is the number of device returned */
+ max_count = MAX_DISK_INFO;
+
infos = (VbDiskInfo *)VbExMalloc(sizeof(VbDiskInfo) * max_count);
- count = 0;
-
- iterator_state = 0;
- while (count < max_count && (dev = iterate_internal_devices(&iterator_state)))
- add_device_if_flags_match(dev, disk_flags,
- infos + count, &count);
-
- /* Skip probing USB device if not require removable devices. */
- if (count < max_count && (disk_flags & VB_DISK_FLAG_REMOVABLE)) {
- /* Initialize USB device before probing them. */
- init_usb_storage();
-
- iterator_state = 0;
- while (count < max_count &&
- (dev = iterate_usb_device(&iterator_state)))
- add_device_if_flags_match(dev, disk_flags,
- infos + count, &count);
+
+ /* Scan through all the interfaces looking for devices */
+ for (upto = 0; upto < interface_count && count < max_count; upto++) {
+ struct boot_interface *iface = interface[upto];
+ int found;
+
+ found = iface->start(disk_flags);
+ if (found < 0) {
+ VBDEBUG(PREFIX "%s: start() failed\n", iface->name);
+ continue;
+ }
+ if (!found) {
+ VBDEBUG(PREFIX "%s - start() returned 0\n",
+ iface->name);
+ continue;
+ }
+
+ found = iface->scan(dev, max_count - count, disk_flags);
+ if (found < 0) {
+ VBDEBUG(PREFIX "%s: scan() failed\n", iface->name);
+ continue;
+ }
+ assert(found <= max_count - count);
+
+ /* Now record the devices that have the required flags */
+ count += add_matching_devices(iface->name, dev, found,
+ disk_flags, infos);
}
if (count) {
*infos_ptr = infos;
*count_ptr = count;
- } else
+ } else {
+ *infos_ptr = NULL;
+ *count_ptr = 0;
VbExFree(infos);
+ }
+ /* The operation itself succeeds, despite scan failure all about */
return VBERROR_SUCCESS;
}
@@ -227,3 +188,19 @@ VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
return VBERROR_SUCCESS;
}
+
+int boot_device_init(void)
+{
+ int err = 0;
+
+#ifdef CONFIG_CHROMEOS_USB
+ err |= boot_device_usb_probe();
+#endif
+#ifdef CONFIG_MMC
+ err |= boot_device_mmc_probe();
+#endif
+#ifdef CONFIG_CHROMEOS_IDE
+ err |= boot_device_ide_probe();
+#endif
+ return err;
+}
diff --git a/lib/vbexport/boot_device.h b/lib/vbexport/boot_device.h
new file mode 100644
index 0000000000..f32fe1a6ec
--- /dev/null
+++ b/lib/vbexport/boot_device.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+/*
+ * This is an interface that we can boot from. It provides a function to start
+ * up the peripheral and also one to scan for available devices attached to
+ * this peripheral.
+ */
+struct boot_interface {
+ const char *name;
+ int type; /* IF_TYPE... from part.h */
+
+ /**
+ * Start the peripheral interface, so we are ready to scan for
+ * devices. This function can return 0 if it knows that there is
+ * no need to scan. If it returns 1 or more, then a scan will
+ * started.
+ *
+ * @param flags Flags for this disk: VB_DISK_FLAG_...
+ * @return 0 if no devices, >=1 if we have devices, -1 on error
+ */
+ int (*start)(uint32_t flags);
+
+ /**
+ * Scan this peripheral for available devices
+ *
+ * @param desc Array to put available devices into
+ * @param max_devs Maximum number of devices to return
+ * @param flags Flags for this disk: VB_DISK_FLAG_...
+ * @return number of devices found, or -1 on error
+ */
+ int (*scan)(block_dev_desc_t **desc, int max_devs, uint32_t flags);
+};
+
+/**
+ * Register a new boot interface.
+ *
+ * @param iface The interface to register
+ * @return 0 if ok, -1 on error
+ */
+int boot_device_register_interface(struct boot_interface *iface);
+
+/**
+ * Checks if a given device matches the provided disk_flags.
+ *
+ * @param dev Device to check
+ * @param disk_flags Disk flags which must be present for this device
+ * @param flags Returns calculated flags for this device
+ * @return 1 if the device matches, 0 if not
+ */
+int boot_device_matches(const block_dev_desc_t *dev, uint32_t disk_flags,
+ uint32_t *flags);
+
+/**
+ * Probe functions for available interfaces
+ *
+ * @return 0 if ok, -1 on error
+ */
+int boot_device_usb_probe(void);
+int boot_device_mmc_probe(void);
+int boot_device_ide_probe(void);
+
+/**
+ * Register all the available boot devices.
+ *
+ * @return 0 if ok, -1 on error
+ */
+int boot_device_init(void);
diff --git a/lib/vbexport/boot_device_ide.c b/lib/vbexport/boot_device_ide.c
new file mode 100644
index 0000000000..a7b496ca53
--- /dev/null
+++ b/lib/vbexport/boot_device_ide.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <ide.h>
+
+#include "boot_device.h"
+
+#include <vboot_api.h>
+
+static int boot_device_ide_start(uint32_t disk_flags)
+{
+ /* We expect to have at least one IDE device */
+ return 1;
+}
+
+static int boot_device_ide_scan(block_dev_desc_t **desc, int max_devs,
+ uint32_t disk_flags)
+{
+ int index, found;
+
+ for (index = found = 0; index < max_devs; index++) {
+ block_dev_desc_t *ide;
+
+ ide = ide_get_dev(index);
+ if (!ide)
+ break;
+
+ desc[index++] = ide;
+ }
+ return found;
+}
+
+static struct boot_interface ide_interface = {
+ .name = "ide",
+ .type = IF_TYPE_IDE,
+ .start = boot_device_ide_start,
+ .scan = boot_device_ide_scan,
+};
+
+int boot_device_ide_probe(void)
+{
+ return boot_device_register_interface(&ide_interface);
+}
diff --git a/lib/vbexport/boot_device_mmc.c b/lib/vbexport/boot_device_mmc.c
new file mode 100644
index 0000000000..01f2bc9b6a
--- /dev/null
+++ b/lib/vbexport/boot_device_mmc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <mmc.h>
+
+#include "boot_device.h"
+
+#include <vboot_api.h>
+
+static int boot_device_mmc_start(uint32_t disk_flags)
+{
+ /* We expect to have at least one MMC device */
+ return 1;
+}
+
+static int boot_device_mmc_scan(block_dev_desc_t **desc, int max_devs,
+ uint32_t disk_flags)
+{
+ int index, found;
+
+ for (index = found = 0; index < max_devs; index++) {
+ struct mmc *mmc;
+ uint32_t flags;
+
+ mmc = find_mmc_device(index);
+ if (!mmc)
+ break;
+
+ /* Skip device that don't match or cannot be initialized */
+ if (boot_device_matches(&mmc->block_dev, disk_flags, &flags) &&
+ mmc_init(mmc) == 0) {
+ /*
+ * find_mmc_device() returns a pointer from a global
+ * linked list. So &mmc->block_dev is not a dangling
+ * pointer after this function is returned.
+ */
+ desc[found++] = &mmc->block_dev;
+ }
+ }
+ return found;
+}
+
+static struct boot_interface mmc_interface = {
+ .name = "mmc",
+ .type = IF_TYPE_MMC,
+ .start = boot_device_mmc_start,
+ .scan = boot_device_mmc_scan,
+};
+
+int boot_device_mmc_probe(void)
+{
+ return boot_device_register_interface(&mmc_interface);
+}
diff --git a/lib/vbexport/boot_device_usb.c b/lib/vbexport/boot_device_usb.c
new file mode 100644
index 0000000000..d261e4e964
--- /dev/null
+++ b/lib/vbexport/boot_device_usb.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "boot_device.h"
+
+#include <vboot_api.h>
+
+static int boot_device_usb_start(uint32_t disk_flags)
+{
+ /* If we aren't looking for removable disks, skip USB */
+ if (!(disk_flags & VB_DISK_FLAG_REMOVABLE))
+ return 0;
+
+ /*
+ * We should stop all USB devices first. Otherwise we can't detect any
+ * new devices.
+ */
+ usb_stop();
+
+ if (usb_init() >= 0)
+ usb_stor_scan(/*mode=*/1);
+ return 1;
+}
+
+static int boot_device_usb_scan(block_dev_desc_t **desc, int max_devs,
+ uint32_t disk_flags)
+{
+ int index;
+
+ max_devs = min(max_devs, USB_MAX_STOR_DEV);
+
+ for (index = 0; index < max_devs; index++) {
+ desc[index] = usb_stor_get_dev(index);
+ if (!desc[index])
+ break;
+ }
+ return index;
+}
+
+static struct boot_interface usb_interface = {
+ .name = "usb",
+ .type = IF_TYPE_USB,
+ .start = boot_device_usb_start,
+ .scan = boot_device_usb_scan,
+};
+
+int boot_device_usb_probe(void)
+{
+ return boot_device_register_interface(&usb_interface);
+}
diff --git a/lib/vbexport/misc.c b/lib/vbexport/misc.c
index f4f73e4763..6af3bb4b62 100644
--- a/lib/vbexport/misc.c
+++ b/lib/vbexport/misc.c
@@ -13,6 +13,8 @@
#include <chromeos/cros_gpio.h>
#include <vboot_api.h>
+#include "boot_device.h"
+
#define PREFIX "misc: "
uint32_t VbExIsShutdownRequested(void)
@@ -42,5 +44,11 @@ uint32_t VbExIsShutdownRequested(void)
int vbexport_init(void)
{
+ int err = boot_device_init();
+
+ if (err) {
+ printf("vbexport_init: boot devices probe failed\n");
+ return -1;
+ }
return 0;
}