Naman Govil (namangov@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6169
-gerrit
commit ee26c8c2a2d4132e9b9389327ad48d2a71e0bf44 Author: Naman Govil namangov@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@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 | 263 +++++++++++++++++++++++++-------- 8 files changed, 441 insertions(+), 176 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@cosmicpenguin.net * Copyright (C) 2012 Google, Inc. * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. + * Copyright (C) 2014 Naman Govil namangov@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@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@cosmicpenguin.net * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. - * + * Copyright (C) 2014, Naman Govil namangov@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@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@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..e509dff 100644 --- a/src/lib/selfboot.c +++ b/src/lib/selfboot.c @@ -3,7 +3,7 @@ * * Copyright (C) 2003 Eric W. Biederman ebiederm@xmission.com * Copyright (C) 2009 Ron Minnich rminnich@gmail.com - * + * Copyright (C) 2014 Naman Govil namangov@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,85 @@ static int relocate_segment(unsigned long buffer, struct segment *seg) }
+static struct sb_helper *get_selfboot_method(struct payload *payload) +{ + struct sb_helper sbh; + if (cbfs_helper.init(&sbh, payload)) + return &cbfs_helper; + if (backing_store_helper.init(&sbh, 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; + + if (sbh == NULL) + return -1; + 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; + sbh->open(payload); + + 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,36 +405,32 @@ 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++; + current_offset += sizeof(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; - } - - /* 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; } - + sbh->close(payload); 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); unsigned long bounce_high = lb_end; + if (sbh == NULL) + return -1;
for(ptr = head->next; ptr != head; ptr = ptr->next) { if (bootmem_region_targets_usable_ram(ptr->s_dstaddr, @@ -362,7 +478,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 +494,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 +505,31 @@ 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"); + sbh->open(payload); + v_map = sbh->map(payload, payload->f.data_offset + ptr->s_offset, + len); + + sbh->close(payload); + 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"); + sbh->open(payload); + v_read = sbh->read(payload, dest, payload->f.data_offset + ptr->s_offset, + len); + sbh->close(payload); + if (v_read != len) { + printk(BIOS_ERR, "Reading of uncompressed segments not successful\n"); + return -1; + } break; } default: @@ -404,11 +538,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,13 +578,17 @@ 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; /* 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");