[coreboot-gerrit] Patch set updated for coreboot: 206bdde Remove inessential mappings in cbfs_media and re-structuring payload loading

Naman Govil (namangov@gmail.com) gerrit at coreboot.org
Sun Aug 10 12:45:59 CEST 2014


Naman Govil (namangov at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6169

-gerrit

commit 206bdde425c71e0a0ac91b03fc4bd1c0c7d351c3
Author: Naman Govil <namangov at gmail.com>
Date:   Mon Jun 30 22:57:11 2014 +0530

    Remove inessential mappings in cbfs_media and re-structuring payload loading
    
    Reducing the sram usage while booting by removing unwanted map()s by creating
    a structure to replace it with appropriate read()s. Removing dependency for mapping
    entire segments for payload loading by segragating segments by reading metadata and
    processing them.
    
    Change-Id: If503368553308a2fdd3ecc1a312a11f14c7a707f
    Signed-off-by: Naman Govil <namangov at gmail.com>
---
 src/arch/x86/boot/smbios.c             |   8 +-
 src/include/cbfs_core.h                |  32 ++++-
 src/include/payload_loader.h           |   4 +
 src/lib/cbfs.c                         |  82 +++++++----
 src/lib/cbfs_core.c                    | 212 ++++++++++++++++++---------
 src/lib/loaders/cbfs_payload_loader.c  |  13 +-
 src/lib/loaders/load_and_run_payload.c |   3 -
 src/lib/selfboot.c                     | 255 ++++++++++++++++++++++++---------
 8 files changed, 432 insertions(+), 177 deletions(-)

diff --git a/src/arch/x86/boot/smbios.c b/src/arch/x86/boot/smbios.c
index ce47a8b..37c4b80 100644
--- a/src/arch/x86/boot/smbios.c
+++ b/src/arch/x86/boot/smbios.c
@@ -28,7 +28,6 @@
 #include <arch/cpu.h>
 #include <cpu/x86/name.h>
 #include <cbfs_core.h>
-#include <arch/byteorder.h>
 #include <elog.h>
 #if CONFIG_CHROMEOS
 #include <vendorcode/google/chromeos/gnvs.h>
@@ -152,11 +151,10 @@ static int smbios_write_type0(unsigned long *current, int handle)
 #endif
 
 	{
-		const struct cbfs_header *header;
+		struct cbfs_header header;
 		u32 romsize = CONFIG_ROM_SIZE;
-		header = cbfs_get_header(CBFS_DEFAULT_MEDIA);
-		if (header != CBFS_HEADER_INVALID_ADDRESS)
-			romsize = ntohl(header->romsize);
+		if (!cbfs_get_header(CBFS_DEFAULT_MEDIA, &header))
+			romsize = header.romsize;
 		t->bios_rom_size = (romsize / 65535) - 1;
 	}
 
diff --git a/src/include/cbfs_core.h b/src/include/cbfs_core.h
index a1d8127..ecfee36 100644
--- a/src/include/cbfs_core.h
+++ b/src/include/cbfs_core.h
@@ -4,6 +4,7 @@
  * Copyright (C) 2008 Jordan Crouse <jordan at cosmicpenguin.net>
  * Copyright (C) 2012 Google, Inc.
  * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2014 Naman Govil <namangov at gmail.com>
  *
  * This file is dual-licensed. You can choose between:
  *   - The GNU GPL, version 2, as published by the Free Software Foundation
@@ -189,6 +190,12 @@ struct cbfs_optionrom {
 #define CBFS_MEDIA_INVALID_MAP_ADDRESS	((void*)(0xffffffff))
 #define CBFS_DEFAULT_MEDIA		((void*)(0x0))
 
+struct cbfs_file_handle {
+	uint32_t data_offset;
+	uint32_t data_len;
+	struct cbfs_file file;
+};
+
 /* Media for CBFS to load files. */
 struct cbfs_media {
 
@@ -220,16 +227,29 @@ struct cbfs_media {
 /* returns pointer to a file entry inside CBFS or NULL */
 struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name);
 
-/* returns pointer to file content inside CBFS after if type is correct */
-void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
-			    int type, size_t *sz);
 
 /* returns decompressed size on success, 0 on failure */
 int cbfs_decompress(int algo, void *src, void *dst, int len);
 
-/* returns a pointer to CBFS master header, or CBFS_HEADER_INVALID_ADDRESS
- *  on failure */
-const struct cbfs_header *cbfs_get_header(struct cbfs_media *media);
+/* finds the CBFS master header and fills it in a cbfs_header structure,
+ *  return 0 on success and <0 if header not found */
+int cbfs_get_header(struct cbfs_media *media, struct cbfs_header *header);
+
+/* Returns success (0) on finding the file requested by verifying name;
+ * -1 if file not found
+ * The absolute data_offset to the file is stored */
+int cbfs_find_file(struct cbfs_media *media, struct cbfs_file_handle *f,
+		const char *name);
+
+/* Returns success (0) on finding the file requested by verifying name and type;
+ * -1 if file not found
+ *  The absolute data_offset to the file is stored */
+int cbfs_find_file_by_type(struct cbfs_media *media, struct cbfs_file_handle *f,
+		const char *name, int type);
+
+/* returns pointer to file content inside CBFS after verifying if type is correct */
+void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
+		int type, size_t *sz);
 
 #endif /* __ROMCC__ */
 
diff --git a/src/include/payload_loader.h b/src/include/payload_loader.h
index 7a3f045..cac7d27 100644
--- a/src/include/payload_loader.h
+++ b/src/include/payload_loader.h
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2014 Google Inc.
+ * Copyright (C) 2014 Naman Govil <namangov at gmail.com>
  *
  * 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
@@ -21,6 +22,7 @@
 
 #include <stdint.h>
 #include <stddef.h>
+#include <cbfs_core.h>
 
 struct buffer_area {
 	void *data;
@@ -32,6 +34,8 @@ struct payload {
 	struct buffer_area backing_store;
 	/* Used when payload wants memory coreboot ramstage is running at. */
 	struct buffer_area bounce;
+	struct cbfs_media *media;
+	struct cbfs_file_handle f;
 	void *entry;
 };
 
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index dc08937..d4db51d 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2008, Jordan Crouse <jordan at cosmicpenguin.net>
  * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
- *
+ * Copyright (C) 2014, Naman Govil <namangov at gmail.com>
  * 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; version 2 of the License.
@@ -119,39 +119,73 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor,
 
 void * cbfs_load_stage(struct cbfs_media *media, const char *name)
 {
-	struct cbfs_stage *stage = (struct cbfs_stage *)
-		cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL);
-	/* this is a mess. There is no ntohll. */
-	/* for now, assume compatible byte order until we solve this. */
-	uint32_t entry;
+	struct cbfs_file_handle f;
+	struct cbfs_stage stage;
+	ssize_t value_read;
+	void * data;
+	struct cbfs_media default_media;
+	void * errorptr = (void *)-1;
+
+	if (media == CBFS_DEFAULT_MEDIA) {
+			media = &default_media;
+			if (init_default_cbfs_media(media) != 0) {
+				ERROR("Failed to initialize default media.\n");
+				return errorptr;
+			}
+	}
+
+	if (cbfs_find_file_by_type(media, &f, name, CBFS_TYPE_STAGE) < 0) {
+		ERROR("Stage not loaded.\n");
+		return errorptr;
+	}
+
+	value_read = media->read(media, &stage, f.data_offset, sizeof(stage));
+	if (value_read != sizeof(stage))
+		return errorptr;
+
+	void * entry;
 	uint32_t final_size;
 
-	if (stage == NULL)
-		return (void *) -1;
+	DEBUG("Read Complete @offset = 0x%x and length = %d\n",
+			f.data_offset, value_read);
 
 	LOG("loading stage %s @ 0x%x (%d bytes), entry @ 0x%llx\n",
 			name,
-			(uint32_t) stage->load, stage->memlen,
-			stage->entry);
+			(uint32_t) stage.load, stage.memlen,
+			stage.entry);
 
-	final_size = cbfs_decompress(stage->compression,
-				     ((unsigned char *) stage) +
-				     sizeof(struct cbfs_stage),
-				     (void *) (uint32_t) stage->load,
-				     stage->len);
-	if (!final_size)
-		return (void *) -1;
+
+	if (stage.compression == CBFS_COMPRESS_NONE) {
+		value_read = media->read(media, (void *) (uintptr_t) stage.load,
+				f.data_offset + sizeof(stage), stage.len);
+		if (value_read != f.data_len)
+			return errorptr;
+		DEBUG("Read Done\n");
+		final_size = stage.len;
+	}
+	else {
+		data = media->map(media, f.data_offset + sizeof(stage), stage.len);
+		if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
+			ERROR("Map not successful");
+			return errorptr;
+		}
+
+		DEBUG("Map Done\n");
+		final_size = cbfs_decompress(stage.compression, data,
+				     (void *) (uint32_t) stage.load,
+				     stage.len);
+		media->unmap(media, data);
+		if (!final_size)
+			return errorptr;
+	}
 
 	/* Stages rely the below clearing so that the bss is initialized. */
-	memset((void *)((uintptr_t)stage->load + final_size), 0,
-	       stage->memlen - final_size);
+	memset((void *)((uintptr_t)stage.load + final_size), 0,
+	       stage.memlen - final_size);
 
 	DEBUG("stage loaded.\n");
-
-	entry = stage->entry;
-	// entry = ntohll(stage->entry);
-
-	return (void *) entry;
+	entry = (void *)(uintptr_t)stage.entry;
+	return entry;
 }
 
 /* Simple buffer */
diff --git a/src/lib/cbfs_core.c b/src/lib/cbfs_core.c
index 50c037e..34b9073 100644
--- a/src/lib/cbfs_core.c
+++ b/src/lib/cbfs_core.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2011 secunet Security Networks AG
  * Copyright (C) 2013 The Chromium OS Authors. All rights reserved.
+ * Copyright (C) 2014 Naman Govil <namangov at gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,150 +53,225 @@
 #include <cbfs.h>
 #include <string.h>
 
-/* returns a pointer to CBFS master header, or CBFS_HEADER_INVALID_ADDRESS
- *  on failure */
-const struct cbfs_header *cbfs_get_header(struct cbfs_media *media)
+/* fills in the header structure with a pointer to CBFS master header,
+   returns 0 on success and <0 if header not found */
+int cbfs_get_header(struct cbfs_media *media, struct cbfs_header *header)
 {
-	const struct cbfs_header *header;
 	struct cbfs_media default_media;
+	ssize_t header_size;
 
 	if (media == CBFS_DEFAULT_MEDIA) {
 		media = &default_media;
 		if (init_default_cbfs_media(media) != 0) {
 			ERROR("Failed to initialize default media.\n");
-			return CBFS_HEADER_INVALID_ADDRESS;
+			return -1;
 		}
 	}
 
 	media->open(media);
 	DEBUG("CBFS_HEADER_ROM_ADDRESS: 0x%x/0x%x\n", CBFS_HEADER_ROM_ADDRESS,
 	      CONFIG_ROM_SIZE);
-	header = media->map(media, CBFS_HEADER_ROM_ADDRESS, sizeof(*header));
+	header_size = media->read(media, (void *)header ,
+			CBFS_HEADER_ROM_ADDRESS, sizeof(*header));
 	media->close(media);
 
-	if (header == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
+	header->magic = ntohl(header->magic);
+	header->version = ntohl(header->version);
+	header->romsize = ntohl(header->romsize);
+	header->bootblocksize = ntohl(header->bootblocksize);
+	header->align = ntohl(header->align);
+	header->offset = ntohl(header->offset);
+	header->architecture = ntohl(header->architecture);
+	header->pad[0] = ntohl(header->pad[0]);
+
+	if (header_size != sizeof(*header)) {
 		ERROR("Failed to load CBFS header from 0x%x\n",
 		      CBFS_HEADER_ROM_ADDRESS);
-		return CBFS_HEADER_INVALID_ADDRESS;
+		return -1;
 	}
-
-	if (CBFS_HEADER_MAGIC != ntohl(header->magic)) {
+	else if (CBFS_HEADER_MAGIC != header->magic) {
 		ERROR("Could not find valid CBFS master header at %x: "
 		      "%x vs %x.\n", CBFS_HEADER_ROM_ADDRESS, CBFS_HEADER_MAGIC,
-		      ntohl(header->magic));
+		      header->magic);
 		if (header->magic == 0xffffffff) {
 			ERROR("Maybe ROM is not mapped properly?\n");
 		}
-		return CBFS_HEADER_INVALID_ADDRESS;
+		return -1;
 	}
-	return header;
+	return 0;
 }
 
 /* public API starts here*/
-struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
+/* This functions finds the absolute data_offset of a file searched for by
+   name. Returns 0 on success and -1 on failure
+ */
+int cbfs_find_file(struct cbfs_media *media, struct cbfs_file_handle *f,
+		const char *name)
 {
-	const char *file_name;
-	uint32_t offset, align, romsize, name_len;
-	const struct cbfs_header *header;
-	struct cbfs_file file, *file_ptr;
+	uint32_t offset, align, romsize,name_len;
 	struct cbfs_media default_media;
+	ssize_t value_read;
+	const char *file_name;
+	struct cbfs_header header;
 
 	if (media == CBFS_DEFAULT_MEDIA) {
 		media = &default_media;
 		if (init_default_cbfs_media(media) != 0) {
 			ERROR("Failed to initialize default media.\n");
-			return NULL;
+			return -1;
 		}
 	}
 
-	if (CBFS_HEADER_INVALID_ADDRESS == (header = cbfs_get_header(media)))
-		return NULL;
+	if (cbfs_get_header(media, &header))
+		return -1;
 
-	// Logical offset (for source media) of first file.
-	offset = ntohl(header->offset);
-	align = ntohl(header->align);
-	romsize = ntohl(header->romsize);
+	// Offset (for source media) of first file.
+	offset = header.offset;
+	align = header.align;
+	romsize = header.romsize;
 
-	// TODO Add a "size" in CBFS header for a platform independent way to
-	// determine the end of CBFS data.
 #if defined(CONFIG_ARCH_X86) && CONFIG_ARCH_X86
-	romsize -= htonl(header->bootblocksize);
+	romsize -= header.bootblocksize;
 #endif
 	DEBUG("CBFS location: 0x%x~0x%x, align: %d\n", offset, romsize, align);
-
 	DEBUG("Looking for '%s' starting from 0x%x.\n", name, offset);
 	media->open(media);
-	while (offset < romsize &&
-	       media->read(media, &file, offset, sizeof(file)) == sizeof(file)) {
-		if (memcmp(CBFS_FILE_MAGIC, file.magic,
-			   sizeof(file.magic)) != 0) {
+	while (offset < romsize)
+	{
+		value_read = media->read(media, &f->file, offset, sizeof(f->file));
+		if(value_read != sizeof(f->file)){
+			media->close(media);
+			return -1;
+		}
+		f->file.len = ntohl(f->file.len);
+		f->file.offset = ntohl(f->file.offset);
+		f->file.type = ntohl(f->file.type);
+
+		if (memcmp(CBFS_FILE_MAGIC, f->file.magic,
+			   sizeof(f->file.magic)) != 0) {
 			uint32_t new_align = align;
 			if (offset % align)
 				new_align += align - (offset % align);
-			ERROR("ERROR: No file header found at 0x%x - "
-			      "try next aligned address: 0x%x.\n", offset,
-			      offset + new_align);
+			ERROR("ERROR: No file header found at 0x%x - try next aligned address: 0x%x.\n", offset,offset+new_align);
 			offset += new_align;
 			continue;
 		}
-		name_len = ntohl(file.offset) - sizeof(file);
-		DEBUG(" - load entry 0x%x file name (%d bytes)...\n", offset,
-		      name_len);
 
-		// load file name (arbitrary length).
-		file_name = (const char *)media->map(
-				media, offset + sizeof(file), name_len);
+		name_len = f->file.offset - sizeof(f->file);
+		DEBUG(" - load entry 0x%x file name (%d bytes)...\n", offset,name_len);
+		file_name = media->map(media, offset + sizeof(f->file),
+				name_len);
 		if (file_name == CBFS_MEDIA_INVALID_MAP_ADDRESS) {
 			ERROR("ERROR: Failed to get filename: 0x%x.\n", offset);
 		} else if (strcmp(file_name, name) == 0) {
-			int file_offset = ntohl(file.offset),
-			    file_len = ntohl(file.len);
-			DEBUG("Found file (offset=0x%x, len=%d).\n",
-			    offset + file_offset, file_len);
-			media->unmap(media, file_name);
-			file_ptr = media->map(media, offset,
-					      file_offset + file_len);
-			media->close(media);
-			return file_ptr;
+				f->data_offset = offset + f->file.offset;
+				f->data_len = f->file.len;
+				media->unmap(media, file_name);
+				DEBUG("Found file:offset = 0x%x, len=%d\n",
+						f->data_offset, f->data_len);
+				return 0;
 		} else {
-			DEBUG(" (unmatched file @0x%x: %s)\n", offset,
-			      file_name);
-			media->unmap(media, file_name);
+			DEBUG("unmatched file offset = 0x%x : %s\n", offset, file_name);
+			media->unmap(media,file_name);
 		}
-
 		// Move to next file.
-		offset += ntohl(file.len) + ntohl(file.offset);
+		offset += f->file.len + f->file.offset;
 		if (offset % align)
 			offset += align - (offset % align);
+		DEBUG("Going for next offset\n");
 	}
 	media->close(media);
-	LOG("WARNING: '%s' not found.\n", name);
-	return NULL;
+	LOG("Warning: '%s' not found\n",name);
+	return -1;
 }
 
+
+/* This functions finds the absolute data_offset of a file searched for by
+   name and type using cbfs_find_file(). Returns 0 on success and -1 on failure
+ */
+int cbfs_find_file_by_type(struct cbfs_media *media, struct cbfs_file_handle *f,
+		const char *name, int type)
+{
+
+	if (cbfs_find_file(media, f, name) < 0) {
+		ERROR("Failed to find file\n");
+		return -1;
+	}
+
+	if (f->file.type == type) {
+		DEBUG("File of matching type has been found\n");
+		return 0;
+	}
+
+	return -1;
+}
+
+
+/*Returns pointer to file content inside CBFS after verifying type
+ */
 void *cbfs_get_file_content(struct cbfs_media *media, const char *name,
-			    int type, size_t *sz)
+		int type, size_t *sz)
 {
-	struct cbfs_file *file = cbfs_get_file(media, name);
+	struct cbfs_file_handle f;
+	struct cbfs_media default_media;
+	void *content;
 
 	if (sz)
 		*sz = 0;
 
-	if (file == NULL) {
-		ERROR("Could not find file '%s'.\n", name);
-		return NULL;
+	if (media == CBFS_DEFAULT_MEDIA) {
+		media = &default_media;
+		if (init_default_cbfs_media(media) != 0) {
+			ERROR("Failed to initialize default media.\n");
+			return NULL;
+		}
 	}
 
-	if (ntohl(file->type) != type) {
-		ERROR("File '%s' is of type %x, but we requested %x.\n", name,
-		      ntohl(file->type), type);
+	if (cbfs_find_file_by_type(media, &f, name, type) < 0) {
+		ERROR("File not found\n");
 		return NULL;
 	}
 
+	DEBUG("Found file. Will be mapping it now!\n");
+
 	if (sz)
-		*sz = ntohl(file->len);
+		*sz = f.data_len;
 
-	return (void *)CBFS_SUBHEADER(file);
+	content = media->map(media, f.data_offset, f.data_len);
+
+	if (content == CBFS_MEDIA_INVALID_MAP_ADDRESS)
+		return NULL;
+	else
+		return content;
+}
+
+/* returns pointer to file entry inside the CBFS or NULL
+*/
+struct cbfs_file *cbfs_get_file(struct cbfs_media *media, const char *name)
+{
+	struct cbfs_file_handle f;
+	struct cbfs_media default_media;
+	struct cbfs_file *fileptr;
+
+	if (media == CBFS_DEFAULT_MEDIA) {
+		media = &default_media;
+		if (init_default_cbfs_media(media) != 0) {
+			ERROR("Failed to initialize media\n");
+			return NULL;
+		}
+	}
+
+	if (cbfs_find_file(media, &f, name) < 0) {
+		ERROR("Failed to find file\n");
+		return NULL;
+	}
+
+	fileptr = media->map(media, f.data_offset - f.file.offset, f.data_len + f.file.offset);
+
+	if (fileptr == CBFS_MEDIA_INVALID_MAP_ADDRESS)
+		return NULL;
+	else
+		return fileptr;
 }
 
 int cbfs_decompress(int algo, void *src, void *dst, int len)
diff --git a/src/lib/loaders/cbfs_payload_loader.c b/src/lib/loaders/cbfs_payload_loader.c
index 2c1d179..175dd7d 100644
--- a/src/lib/loaders/cbfs_payload_loader.c
+++ b/src/lib/loaders/cbfs_payload_loader.c
@@ -2,6 +2,7 @@
  * This file is part of the coreboot project.
  *
  * Copyright (C) 2014 Google Inc.
+ * Copyright (C) 2014 Naman Govil <namangov at gmail.com>
  *
  * 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
@@ -19,21 +20,19 @@
 
 #include <cbfs.h>
 #include <payload_loader.h>
+#include <cbfs_core.h>
 
 static int cbfs_locate_payload(struct payload *payload)
 {
-	void *buffer;
-	size_t size;
 	const int type = CBFS_TYPE_PAYLOAD;
+	struct cbfs_media *m;
 
-	buffer = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, payload->name,
-					type, &size);
+	m = CBFS_DEFAULT_MEDIA;
 
-	if (buffer == NULL)
+	if (cbfs_find_file_by_type(m, &payload->f, payload->name, type) < 0)
 		return -1;
 
-	payload->backing_store.data = buffer;
-	payload->backing_store.size = size;
+	payload->media = m;
 
 	return 0;
 }
diff --git a/src/lib/loaders/load_and_run_payload.c b/src/lib/loaders/load_and_run_payload.c
index 2204090..0dcecfb 100644
--- a/src/lib/loaders/load_and_run_payload.c
+++ b/src/lib/loaders/load_and_run_payload.c
@@ -58,9 +58,6 @@ struct payload *payload_load(void)
 				ops->name);
 			continue;
 		}
-		printk(BIOS_DEBUG, "%s: located payload @ %p, %zu bytes.\n",
-			ops->name, payload->backing_store.data,
-			payload->backing_store.size);
 		break;
 	}
 
diff --git a/src/lib/selfboot.c b/src/lib/selfboot.c
index 8e9e0de..10bd2e9 100644
--- a/src/lib/selfboot.c
+++ b/src/lib/selfboot.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2003 Eric W. Biederman <ebiederm at xmission.com>
  * Copyright (C) 2009 Ron Minnich <rminnich at gmail.com>
- *
+ * Copyright (C) 2014 Naman Govil <namangov at gmail.com>
  * 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; version 2 of the License.
@@ -28,6 +28,7 @@
 #include <lib.h>
 #include <bootmem.h>
 #include <payload_loader.h>
+#include <cbfs_core.h>
 
 /* from ramstage.ld: */
 extern unsigned char _ram_seg;
@@ -40,9 +41,9 @@ struct segment {
 	struct segment *next;
 	struct segment *prev;
 	unsigned long s_dstaddr;
-	unsigned long s_srcaddr;
 	unsigned long s_memsz;
 	unsigned long s_filesz;
+	unsigned long s_offset;
 	int compression;
 };
 
@@ -66,6 +67,108 @@ struct segment {
  *   and much simpler than the general case implemented in kexec.
  */
 
+struct sb_helper {
+	int (*init)(struct sb_helper *sbh, struct payload *payload);
+	int (*open)(struct payload *payload);
+	int (*close)(struct payload *payload);
+	size_t (*read)(struct payload *payload, void *dest, size_t offset, size_t size);
+	void *(*map)(struct payload *payload, size_t offset, size_t size);
+	void *sb_media;
+};
+
+static struct cbfs_media default_media;
+
+static int init_cbfs(struct sb_helper *sbh, struct payload *payload)
+{
+	/*Backing store is in use hence no loading via cbfs
+	*/
+	if (payload->backing_store.data != NULL)
+		return 0;
+	if (payload->media == CBFS_DEFAULT_MEDIA) {
+		payload->media = &default_media;
+		if (init_default_cbfs_media(payload->media) != 0) {
+			printk(BIOS_ERR, "Failed to initialize media\n");
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static size_t cbfs_read(struct payload *payload, void *dest, size_t offset, size_t size)
+{
+	return payload->media->read(payload->media, dest, offset, size);
+}
+
+static void *cbfs_map(struct payload *payload, size_t offset, size_t size)
+{
+	void * v_map;
+	v_map = payload->media->map(payload->media, offset, size);
+	if (v_map == CBFS_MEDIA_INVALID_MAP_ADDRESS)
+		return NULL;
+	return v_map;
+}
+
+static int cbfs_open(struct payload *payload)
+{
+	payload->media->open(payload->media);
+	return 0;
+}
+
+static int cbfs_close(struct payload *payload)
+{
+	payload->media->close(payload->media);
+	return 0;
+}
+
+static int init_backing_store(struct sb_helper *sbh, struct payload *payload)
+{
+	if (payload->backing_store.data != NULL)
+		return 1;
+	else
+		return 0;
+}
+
+static size_t backing_store_read(struct payload *payload, void *dest, size_t offset, size_t size)
+{
+	memcpy(dest, (void *)payload->backing_store.data + offset, size);
+	return size;
+}
+
+static void *backing_store_map(struct payload *payload, size_t offset, size_t size)
+{
+	if (payload->backing_store.data == NULL)
+		return NULL;
+	return offset + (char *)payload->backing_store.data;
+}
+
+static int backing_store_open(struct payload *payload)
+{
+	return 0;
+}
+
+static int backing_store_close(struct payload *payload)
+{
+	return 0;
+}
+
+static struct sb_helper cbfs_helper = {
+	.init = init_cbfs,
+	.open = cbfs_open,
+	.close = cbfs_close,
+	.read = cbfs_read,
+	.map = cbfs_map,
+	.sb_media = &default_media,
+};
+
+static struct sb_helper backing_store_helper = {
+	.init = init_backing_store,
+	.open = backing_store_open,
+	.close = backing_store_close,
+	.read = backing_store_read,
+	.map = backing_store_map,
+	.sb_media = NULL,
+};
+
 static unsigned long bounce_size, bounce_buffer;
 
 static void get_bounce_buffer(unsigned long req_size)
@@ -140,7 +243,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 			new->s_memsz = len;
 			seg->s_memsz -= len;
 			seg->s_dstaddr += len;
-			seg->s_srcaddr += len;
+			seg->s_offset += len;
 			if (seg->s_filesz > len) {
 				new->s_filesz = len;
 				seg->s_filesz -= len;
@@ -176,7 +279,7 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 			seg->s_memsz = len;
 			new->s_memsz -= len;
 			new->s_dstaddr += len;
-			new->s_srcaddr += len;
+			new->s_offset += len;
 			if (seg->s_filesz > len) {
 				seg->s_filesz = len;
 				new->s_filesz -= len;
@@ -212,68 +315,80 @@ static int relocate_segment(unsigned long buffer, struct segment *seg)
 }
 
 
+static struct sb_helper *get_selfboot_method(struct payload *payload)
+{
+	if (cbfs_helper.init(&cbfs_helper, payload))
+		return &cbfs_helper;
+	if (backing_store_helper.init(&backing_store_helper, payload))
+		return &backing_store_helper;
+	return NULL;
+}
+
 static int build_self_segment_list(
 	struct segment *head,
-	struct payload *payload, uintptr_t *entry)
+	struct payload *payload, uintptr_t *entry, struct sb_helper *sbh)
 {
 	struct segment *new;
-	struct segment *ptr;
-	struct cbfs_payload_segment *segment, *first_segment;
-	struct cbfs_payload *cbfs_payload;
-	cbfs_payload = payload->backing_store.data;
+	struct cbfs_payload_segment segment;
+	unsigned long current_offset;
+
 	memset(head, 0, sizeof(*head));
 	head->next = head->prev = head;
-	first_segment = segment = &cbfs_payload->segments;
 
-	while(1) {
-		printk(BIOS_DEBUG, "Loading segment from rom address 0x%p\n", segment);
-		switch(segment->type) {
+	current_offset = payload->f.data_offset;
+
+	while(sbh->read(payload, &segment, current_offset, sizeof(segment))
+			== sizeof(segment)) {
+
+		printk(BIOS_DEBUG, "Reading segment from offset 0x%lx\n", current_offset);
+		segment.compression = ntohl(segment.compression);
+		segment.offset = ntohl(segment.offset);
+		segment.load_addr = ntohll(segment.load_addr);
+		segment.mem_len = ntohl(segment.mem_len);
+		segment.len = ntohl(segment.len);
+
+		switch(segment.type) {
 		case PAYLOAD_SEGMENT_PARAMS:
 			printk(BIOS_DEBUG, "  parameter section (skipped)\n");
-			segment++;
+			current_offset += sizeof(segment);
 			continue;
 
 		case PAYLOAD_SEGMENT_CODE:
 		case PAYLOAD_SEGMENT_DATA:
 			printk(BIOS_DEBUG, "  %s (compression=%x)\n",
-					segment->type == PAYLOAD_SEGMENT_CODE ?  "code" : "data",
-					ntohl(segment->compression));
+					segment.type == PAYLOAD_SEGMENT_CODE ?  "code" : "data",
+					segment.compression);
 			new = malloc(sizeof(*new));
-			new->s_dstaddr = ntohll(segment->load_addr);
-			new->s_memsz = ntohl(segment->mem_len);
-			new->compression = ntohl(segment->compression);
-
-			new->s_srcaddr = (uintptr_t)
-				((unsigned char *)first_segment)
-				+ ntohl(segment->offset);
-			new->s_filesz = ntohl(segment->len);
-			printk(BIOS_DEBUG, "  New segment dstaddr 0x%lx memsize 0x%lx srcaddr 0x%lx filesize 0x%lx\n",
-				new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz);
+			new->s_dstaddr = segment.load_addr;
+			new->s_memsz = segment.mem_len;
+			new->compression = segment.compression;
+			new->s_filesz = segment.len;
+			new->s_offset = segment.offset;
+
+			printk(BIOS_DEBUG, "  New segment dstaddr 0x%lx memsize 0x%lx src_offset 0x%lx filesize 0x%lx\n",
+				new->s_dstaddr, new->s_memsz, new->s_offset, new->s_filesz);
 			/* Clean up the values */
 			if (new->s_filesz > new->s_memsz)  {
 				new->s_filesz = new->s_memsz;
 			}
-			printk(BIOS_DEBUG, "  (cleaned up) New segment addr 0x%lx size 0x%lx offset 0x%lx filesize 0x%lx\n",
-				new->s_dstaddr, new->s_memsz, new->s_srcaddr, new->s_filesz);
+			printk(BIOS_DEBUG, "  (cleaned up) New segment addr 0x%lx size 0x%lx src_offset 0x%lx filesize 0x%lx\n",
+				new->s_dstaddr, new->s_memsz, new->s_offset, new->s_filesz);
 			break;
 
 		case PAYLOAD_SEGMENT_BSS:
-			printk(BIOS_DEBUG, "  BSS 0x%p (%d byte)\n", (void *)
-					(intptr_t)ntohll(segment->load_addr),
-				 	ntohl(segment->mem_len));
+			printk(BIOS_DEBUG, "  BSS 0x%p (%d byte)\n",
+					(void *)(intptr_t)segment.load_addr, segment.mem_len);
 			new = malloc(sizeof(*new));
 			new->s_filesz = 0;
-			new->s_srcaddr = (uintptr_t)
-				((unsigned char *)first_segment)
-				+ ntohl(segment->offset);
-			new->s_dstaddr = ntohll(segment->load_addr);
-			new->s_memsz = ntohl(segment->mem_len);
+			new->s_offset = segment.offset;
+			new->s_dstaddr = segment.load_addr;
+			new->s_memsz = segment.mem_len;
 			break;
 
 		case PAYLOAD_SEGMENT_ENTRY:
 			printk(BIOS_DEBUG, "  Entry Point 0x%p\n",
-			       (void *)(intptr_t)ntohll(segment->load_addr));
-			*entry =  ntohll(segment->load_addr);
+			       (void *)(intptr_t)segment.load_addr);
+			*entry = segment.load_addr;
 			/* Per definition, a payload always has the entry point
 			 * as last segment. Thus, we use the occurrence of the
 			 * entry point as break condition for the loop.
@@ -285,32 +400,25 @@ static int build_self_segment_list(
 			/* We found something that we don't know about. Throw
 			 * hands into the sky and run away!
 			 */
-			printk(BIOS_EMERG, "Bad segment type %x\n", segment->type);
+			printk(BIOS_EMERG, "Bad segment type %x\n", segment.type);
 			return -1;
 		}
 
 		/* We have found another CODE, DATA or BSS segment */
-		segment++;
-
-		/* Find place where to insert our segment */
-		for(ptr = head->next; ptr != head; ptr = ptr->next) {
-			if (new->s_srcaddr < ntohll(segment->load_addr))
-				break;
-		}
+		current_offset += sizeof(segment);
 
-		/* Order by stream offset */
-		new->next = ptr;
-		new->prev = ptr->prev;
-		ptr->prev->next = new;
-		ptr->prev = new;
+		/* Insert to the end of the list */
+		new->next = head;
+		new->prev = head->prev;
+		head->prev->next = new;
+		head->prev = new;
 	}
-
 	return 1;
 }
 
 static int load_self_segments(
 	struct segment *head,
-	struct payload *payload)
+	struct payload *payload, struct sb_helper *sbh)
 {
 	struct segment *ptr;
 	const unsigned long one_meg = (1UL << 20);
@@ -362,7 +470,7 @@ static int load_self_segments(
 	payload->bounce.size = bounce_size;
 
 	for(ptr = head->next; ptr != head; ptr = ptr->next) {
-		unsigned char *dest, *src;
+		unsigned char *dest;
 		printk(BIOS_DEBUG, "Loading Segment: addr: 0x%016lx memsz: 0x%016lx filesz: 0x%016lx\n",
 			ptr->s_dstaddr, ptr->s_memsz, ptr->s_filesz);
 
@@ -378,7 +486,8 @@ static int load_self_segments(
 
 		/* Compute the boundaries of the segment */
 		dest = (unsigned char *)(ptr->s_dstaddr);
-		src = (unsigned char *)(ptr->s_srcaddr);
+		size_t v_read;
+		void *v_map;
 
 		/* Copy data from the initial buffer */
 		if (ptr->s_filesz) {
@@ -388,14 +497,27 @@ static int load_self_segments(
 			switch(ptr->compression) {
 				case CBFS_COMPRESS_LZMA: {
 					printk(BIOS_DEBUG, "using LZMA\n");
-					len = ulzma(src, dest);
+					printk(BIOS_DEBUG, "need to map first\n");
+					v_map = sbh->map(payload, payload->f.data_offset + ptr->s_offset,
+							len);
+
+					if (v_map == NULL) {
+						printk(BIOS_ERR, "Failed to map\n");
+						return -1;
+					}
+					len = ulzma(v_map, dest);
 					if (!len) /* Decompression Error. */
 						return 0;
 					break;
 				}
 				case CBFS_COMPRESS_NONE: {
-					printk(BIOS_DEBUG, "it's not compressed!\n");
-					memcpy(dest, src, len);
+					printk(BIOS_DEBUG, "it's not compressed! hence read directly\n");
+					v_read = sbh->read(payload, dest, payload->f.data_offset + ptr->s_offset,
+							len);
+					if (v_read != len) {
+						printk(BIOS_ERR, "Reading of uncompressed segments not successful\n");
+						return -1;
+					}
 					break;
 				}
 				default:
@@ -404,11 +526,10 @@ static int load_self_segments(
 			}
 			end = dest + ptr->s_memsz;
 			middle = dest + len;
-			printk(BIOS_SPEW, "[ 0x%08lx, %08lx, 0x%08lx) <- %08lx\n",
+			printk(BIOS_SPEW, "[ 0x%08lx, %08lx, 0x%08lx )\n",
 				(unsigned long)dest,
 				(unsigned long)middle,
-				(unsigned long)end,
-				(unsigned long)src);
+				(unsigned long)end);
 
 			/* Zero the extra bytes between middle & end */
 			if (middle < end) {
@@ -445,17 +566,23 @@ void *selfload(struct payload *payload)
 {
 	uintptr_t entry = 0;
 	struct segment head;
+	struct sb_helper *sbh;
 
+	sbh = get_selfboot_method(payload);
+	if (sbh == NULL)
+		goto out;
+	/* will not sbh->open() if selfboot method is not valid */
+	sbh->open(payload);
 	/* Preprocess the self segments */
-	if (!build_self_segment_list(&head, payload, &entry))
+	if (!build_self_segment_list(&head, payload, &entry, sbh))
 		goto out;
 
 	/* Load the segments */
-	if (!load_self_segments(&head, payload))
+	if (!load_self_segments(&head, payload, sbh))
 		goto out;
 
 	printk(BIOS_SPEW, "Loaded segments\n");
-
+	sbh->close(payload);
 	return (void *)entry;
 
 out:



More information about the coreboot-gerrit mailing list