vboot: new streaming APIs

This patch adds three functions called from vboot into depthcharge to
support NAND. NAND needs to stream rather than be accessed randomly
in order to skip bad blocks. The intended flow from vboot1 is:
- Read the GPT from a NAND disk handle, and depthcharge will silently
  fill it in with reads from from SPI
- When a partition is selected, open a stream on the volume to access
  NAND
- Sequentially read the NAND partition
- Close the NAND stream
This can be done multiple times when trying different partitions. The
stream is associated with the GPT by reading/opening a stream from the
same disk handle.

This patch includes stub implementations by rspangler to translate the
stream calls to block device calls.

To reduce vboot code duplication, this flow will be done for all media
types eventually, but a STREAMING flag is included to ease the transition.
The draft depthcharge code can be found at
https://chromium-review.googlesource.com/#/c/222312/

BUG=chromium:403432
TEST=stub implementations pass unit tests; together with upcoming depthcharge
and vboot code, actually boots a kernel. This compiles by itself.
BRANCH=none

Change-Id: I660a89594390c72c2ef6ea2564367ce62bd90cf2
Reviewed-on: https://chromium-review.googlesource.com/221992
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Daniel Ehrenberg <dehrenberg@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Randall Spangler <rspangler@chromium.org>
diff --git a/Makefile b/Makefile
index 2f7db8c..a3592ab 100644
--- a/Makefile
+++ b/Makefile
@@ -323,7 +323,8 @@
 
 VBSLK_SRCS += \
 	firmware/stub/vboot_api_stub.c \
-	firmware/stub/vboot_api_stub_disk.c
+	firmware/stub/vboot_api_stub_disk.c \
+	firmware/stub/vboot_api_stub_stream.c
 
 FWLIB2_SRCS += \
 	firmware/2lib/2stub.c
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 9b05371..526c1e4 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -620,6 +620,51 @@
 VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
                         uint64_t lba_count, const void *buffer);
 
+/* Streaming read interface */
+typedef void *VbExStream_t;
+
+/**
+ * Open a stream on a disk
+ *
+ * @param handle	Disk to open the stream against
+ * @param lba_start	Starting sector offset within the disk to stream from
+ * @param lba_count	Maximum extent of the stream in sectors
+ * @param stream	out-paramter for the generated stream
+ *
+ * @return Error code, or VBERROR_SUCCESS.
+ *
+ * lba_start and lba_count are subject to disk type-dependent alignment
+ * restrictions. An invalid value will lead to an error code. In particular,
+ * on raw NAND devices, lba_start and lba_count must be page-aligned after
+ * subtracting the offset of the GPT.
+ */
+VbError_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start,
+			 uint64_t lba_count, VbExStream_t *stream_ptr);
+
+/**
+ * Read from a stream on a disk
+ *
+ * @param stream	Stream to read from
+ * @param bytes		Number of bytes to read
+ * @param buffer	Destination to read into
+ *
+ * @return Error code, or VBERROR_SUCCESS. Failure to read as much data as
+ * requested is an error.
+ *
+ * bytes is subject to disk type-dependent alignment restrictions. An invalid
+ * value will lead to an error code. In particular, on raw NAND devices, bytes
+ * must be a page multiple.
+ */
+VbError_t VbExStreamRead(VbExStream_t stream, uint32_t bytes, void *buffer);
+
+/**
+ * Close a stream
+ *
+ * @param stream	Stream to close
+ */
+void VbExStreamClose(VbExStream_t stream);
+
+
 /*****************************************************************************/
 /* Display */
 
diff --git a/firmware/stub/vboot_api_stub_stream.c b/firmware/stub/vboot_api_stub_stream.c
new file mode 100644
index 0000000..525c8f7
--- /dev/null
+++ b/firmware/stub/vboot_api_stub_stream.c
@@ -0,0 +1,87 @@
+/* Copyright (c) 2014 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.
+ *
+ * Stub implementations of stream APIs.
+ */
+
+#include <stdint.h>
+
+#define _STUB_IMPLEMENTATION_
+
+#include "vboot_api.h"
+
+/* The stub implementation assumes 512-byte disk sectors */
+#define LBA_BYTES 512
+
+/* Internal struct to simulate a stream for sector-based disks */
+struct disk_stream {
+	/* Disk handle */
+	VbExDiskHandle_t handle;
+
+	/* Next sector to read */
+	uint64_t sector;
+
+	/* Number of sectors left in partition */
+	uint64_t sectors_left;
+};
+
+VbError_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start,
+			 uint64_t lba_count, VbExStream_t *stream)
+{
+	struct disk_stream *s;
+
+	if (!handle) {
+		*stream = NULL;
+		return VBERROR_UNKNOWN;
+	}
+
+	s = VbExMalloc(sizeof(*s));
+	s->handle = handle;
+	s->sector = lba_start;
+	s->sectors_left = lba_count;
+
+	*stream = (void *)s;
+
+	return VBERROR_SUCCESS;
+}
+
+VbError_t VbExStreamRead(VbExStream_t stream, uint32_t bytes, void *buffer)
+{
+	struct disk_stream *s = (struct disk_stream *)stream;
+	uint64_t sectors;
+	VbError_t rv;
+
+	if (!s)
+		return VBERROR_UNKNOWN;
+
+	/* For now, require reads to be a multiple of the LBA size */
+	if (bytes % LBA_BYTES)
+		return VBERROR_UNKNOWN;
+
+	/* Fail on overflow */
+	sectors = bytes / LBA_BYTES;
+	if (sectors > s->sectors_left)
+		return VBERROR_UNKNOWN;
+
+	rv = VbExDiskRead(s->handle, s->sector, sectors, buffer);
+	if (rv != VBERROR_SUCCESS)
+		return rv;
+
+	s->sector += sectors;
+	s->sectors_left -= sectors;
+
+	return VBERROR_SUCCESS;
+}
+
+void VbExStreamClose(VbExStream_t stream)
+{
+	struct disk_stream *s = (struct disk_stream *)stream;
+
+	/* Allow freeing a null pointer */
+	if (!s)
+		return;
+
+	VbExFree(s);
+	return;
+}