Implement VbExLegacy()
The VbExLegacy() functions was not implemented preventing boards
using depthcharge as a boot loader to fail Ctrl+L legacy boot.
Implement this functionality. The arch_final_cleanup() was
implemented on the two architectures so that legacy boot
could properly cleanup before handoff.
BUG=chrome-os-partner:19691
BUG=chrome-os-partner:16685
BRANCH=None
TEST=Enabled SeaBIOS serial and noted messages from SeaBIOS after
invoking Ctrl+L at dev screen on wtm2.
Change-Id: I55d5c02e8c08db1eb2d8b72a09c9c0072ad0ee1e
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/56636
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-by: Stefan Reinauer <reinauer@google.com>
diff --git a/src/arch/arm/boot.c b/src/arch/arm/boot.c
index 5f2fe0d..446afa9 100644
--- a/src/arch/arm/boot.c
+++ b/src/arch/arm/boot.c
@@ -24,6 +24,7 @@
#include "arch/arm/boot.h"
#include "base/cleanup_funcs.h"
+#include "vboot/boot.h"
static inline uint32_t get_cpsr(void)
{
@@ -55,7 +56,7 @@
int boot_arm_linux(uint32_t machine_type, void *fdt, void *entry)
{
- run_cleanup_funcs(CleanupOnHandoff);
+ arch_final_cleanup();
static const uint32_t CpsrF = (0x1 << 6);
static const uint32_t CpsrI = (0x1 << 7);
@@ -91,3 +92,11 @@
return 0;
}
+
+
+int arch_final_cleanup(void)
+{
+ run_cleanup_funcs(CleanupOnHandoff);
+
+ return 0;
+}
diff --git a/src/arch/x86/boot.c b/src/arch/x86/boot.c
index ea09e27..b921e5a 100644
--- a/src/arch/x86/boot.c
+++ b/src/arch/x86/boot.c
@@ -28,6 +28,7 @@
#include "arch/x86/cpu.h"
#include "base/cleanup_funcs.h"
#include "base/timestamp.h"
+#include "vboot/boot.h"
static void * const ParamsBuff = (void *)(uintptr_t)0x1000;
static void * const CmdLineBuff = (void *)(uintptr_t)0x2000;
@@ -80,6 +81,31 @@
hdr->cmd_line_ptr = (uintptr_t)cmd_line;
+ arch_final_cleanup();
+
+ puts("\nStarting kernel ...\n\n");
+ timestamp_add_now(TS_START_KERNEL);
+
+ /*
+ * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params
+ * structure, and then jump to the kernel. We assume that %cs is
+ * 0x10, 4GB flat, and read/execute, and the data segments are 0x18,
+ * 4GB flat, and read/write.
+ */
+ __asm__ __volatile__ (
+ "movl $0, %%ebp \n"
+ "cli \n"
+ "jmp *%[kernel_entry] \n"
+ :: [kernel_entry]"a"(entry),
+ [boot_params] "S"(boot_params),
+ "b"(0), "D"(0)
+ : "%ebp"
+ );
+ return 0;
+}
+
+int arch_final_cleanup(void)
+{
/*
* Un-cache the ROM so the kernel has one more MTRR available.
* Coreboot should have assigned this to the top available variable
@@ -102,23 +128,5 @@
run_cleanup_funcs(CleanupOnHandoff);
- puts("\nStarting kernel ...\n\n");
- timestamp_add_now(TS_START_KERNEL);
-
- /*
- * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params
- * structure, and then jump to the kernel. We assume that %cs is
- * 0x10, 4GB flat, and read/execute, and the data segments are 0x18,
- * 4GB flat, and read/write.
- */
- __asm__ __volatile__ (
- "movl $0, %%ebp \n"
- "cli \n"
- "jmp *%[kernel_entry] \n"
- :: [kernel_entry]"a"(entry),
- [boot_params] "S"(boot_params),
- "b"(0), "D"(0)
- : "%ebp"
- );
return 0;
}
diff --git a/src/vboot/callbacks/legacy.c b/src/vboot/callbacks/legacy.c
index 485fdf6..3d4f53c 100644
--- a/src/vboot/callbacks/legacy.c
+++ b/src/vboot/callbacks/legacy.c
@@ -20,11 +20,112 @@
* MA 02111-1307 USA
*/
+#include <string.h>
+#include <endian.h>
#include <libpayload.h>
+#include <lzma.h>
#include <vboot_api.h>
+#include <cbfs.h>
+#include <cbfs_ram.h>
+
+#include "drivers/flash/flash.h"
+#include "image/fmap.h"
+#include "vboot/boot.h"
+
+static void load_payload_and_run(struct cbfs_payload *payload);
int VbExLegacy(void)
{
- printf("VbExLegacy not implemented.\n");
+ FmapArea area;
+ struct cbfs_media media;
+ void *data;
+ struct cbfs_payload *payload;
+ const char *area_name = "RW_LEGACY";
+
+ if (fmap_find_area(area_name, &area)) {
+ printf("Fmap region %s not found.\n", area_name);
+ return 1;
+ }
+ data = flash_read(area.offset, area.size);
+
+ if (data == NULL) {
+ printf("Could not read in legacy cbfs data.\n");
+ return 1;
+ }
+
+ if (init_cbfs_ram_media(&media, data, area.size)) {
+ printf("Could not initialize legacy cbfs.\n");
+ return 1;
+ }
+
+ payload = cbfs_load_payload(&media, "payload");
+
+ if (payload == NULL) {
+ printf("Could not find payload in legacy cbfs.\n");
+ return 1;
+ }
+
+ load_payload_and_run(payload);
+
+ /* Should never return unless there is an error. */
return 1;
}
+
+static void load_payload_and_run(struct cbfs_payload *payload)
+{
+ /* This is a minimalistic SELF parser. */
+ struct cbfs_payload_segment *seg = &payload->segments;
+ char *base = (void *)seg;
+
+ while (1) {
+ void (*payload_entry)(void);
+ void *src = base + be32toh(seg->offset);
+ void *dst = (void *)(unsigned long)be64toh(seg->load_addr);
+ u32 src_len = be32toh(seg->len);
+ u32 dst_len = be32toh(seg->mem_len);
+
+ switch (seg->type) {
+ case PAYLOAD_SEGMENT_CODE:
+ case PAYLOAD_SEGMENT_DATA:
+ printf("CODE/DATA: dst=%p dst_len=%d src=%p "
+ "src_len=%d compression=%d\n", dst, dst_len,
+ src, src_len, be32toh(seg->compression));
+ if (be32toh(seg->compression) ==
+ CBFS_COMPRESS_NONE) {
+ memcpy(dst, src, src_len);
+ } else if (be32toh(seg->compression) ==
+ CBFS_COMPRESS_LZMA) {
+ unsigned long ret;
+ ret = ulzma(src, dst);
+ if (ret != dst_len) {
+ printf("LZMA: Decompression failed. "
+ "ret=%ld, expected %d.\n", ret,
+ dst_len);
+ return;
+ }
+ } else {
+ printf("Compression type %x not supported\n",
+ be32toh(seg->compression));
+ return;
+ }
+ break;
+ case PAYLOAD_SEGMENT_BSS:
+ printf("BSS: dst=%p len=%d\n", dst, dst_len);
+ memset(dst, 0, dst_len);
+ break;
+ case PAYLOAD_SEGMENT_PARAMS:
+ printf("PARAMS: skipped\n");
+ break;
+ case PAYLOAD_SEGMENT_ENTRY:
+ arch_final_cleanup();
+ payload_entry = dst;
+ payload_entry();
+ return;
+ default:
+ printf("segment type %x not implemented. Exiting\n",
+ seg->type);
+ return;
+ }
+ seg++;
+ }
+}