mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
The system will default to old behaviour. See Kconfig in the root. I still wish to kill ELF mode very soon, however. LAR is a very capable format. With two simple extensions, we can use LAR to replace all that we are using ELF for now. This change can really make life better: 1. we can use streaming decompress instead of the current "uncompress elf to memory and then copy segments" approach. So we can get rid of THIS hardcode: #define UNCOMPRESS_AREA (0x400000) 2. A simple lar l can show ALL segments, including payload segments 3. It's really easy to see where things will go in memory, and catch problems 4. We can figure out an ELF input file is bogus BEFORE we flash, not AFTER we flash and try to boot it 5. did I mention streaming decompress? 6. We no longer have to worry about where we decompress the elf in memory (this problem was causing trouble when the payload was a linux kernel -- it was so big) 7. Since we have a load address, we can create this lar entry: normal/cmdline and specify that it be loaded at a place where linux will find it as the cmdline. 8. The decision on whether to XIP can be made in the LAR entry, not in hardcode. For example, if initram needs to be XIP, set the load address to 0xffffffff. Done. The change is simple. Add a load address and entry point to the lar header. Extend the lar tool to parse the elf file and create multiple lar segments. It looks like this: normal/payload0 (33192 bytes, lzma compressed to 18088 bytes @0x38 load @0x100000, entry 0x105258) normal/payload1 (72 bytes, lzma compressed to 47 bytes @0x4718 load @0x1225a0, entry 0x105258) normal/option_table (932 bytes @0x4798 load @0, entry 0) normal/stage2 (33308 bytes, lzma compressed to 15474 bytes @0x4b78 load @0, entry 0) normal/initram (4208 bytes @0x8828 load @0, entry 0) linuxbios.bootblock (16384 bytes @0xfc000 load @0, entry 0) note that the payload is now payload/segment0, payload/segment1, etc. I've extended linuxbios to look for these. Note that you can now see all the things that get loaded ;they're no longer hidden in an ELF header somewhere. Elf failures are gone! Note that I've left legacy elf support in, for now, but recommend we get rid of it as soon as possible. patch attached. This is a first pass. lar.c needs some refactoring but I want to get the cmdline going. You can now have a linux payload and it will uncompress with no problems. This has been tested with filo and BOCHS. This patch includes ONLY the lar changes, the other changes are next. Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@481 f3766cd6-281f-0410-b1cd-43a5c92072e9
363 lines
8.3 KiB
C
363 lines
8.3 KiB
C
/*
|
|
* lar - LinuxBIOS archiver
|
|
*
|
|
* Copyright (C) 2006-2007 coresystems GmbH
|
|
* (Written by Stefan Reinauer <stepan@coresystems.de> for coresystems GmbH)
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "lar.h"
|
|
#include "lib.h"
|
|
|
|
#define VERSION "v0.9.1"
|
|
#define COPYRIGHT "Copyright (C) 2006-2007 coresystems GmbH"
|
|
|
|
static int isverbose = 0;
|
|
static int iselfparse = 0;
|
|
static long larsize = 0;
|
|
static char *bootblock = NULL;
|
|
enum compalgo algo = none;
|
|
|
|
static void usage(char *name)
|
|
{
|
|
printf("\nLAR - the LinuxBIOS Archiver " VERSION "\n" COPYRIGHT "\n\n"
|
|
"Usage: %s [-ecxal] archive.lar [[[file1] file2] ...]\n\n", name);
|
|
printf("Examples:\n");
|
|
printf(" lar -c -s 32k -b bootblock myrom.lar foo nocompress:bar\n");
|
|
printf(" lar -a myrom.lar foo blob:baz\n");
|
|
printf(" lar -l myrom.lar\n\n");
|
|
|
|
printf("File names:\n");
|
|
printf(" Names specified in the create or add modes are formatted as\n");
|
|
printf(" follows: [flags]:[filename]:[pathname].\n");
|
|
printf(" * Flags are modifiers for the file. Valid flags:\n");
|
|
printf(" nocompress\tDon't compress the file in the LAR\n");
|
|
printf(" * Filename is the name of the file on disk. If no pathname\n");
|
|
printf(" is specified, then the filename will also be the path name\n");
|
|
printf(" used in the LAR.\n");
|
|
printf(" * Pathname is the name to use in the LAR header.\n\n");
|
|
|
|
printf("Create options:\n");
|
|
printf(" -s [size] \tSpecify the size of the archive.\n");
|
|
printf(" \tUse a 'k' suffix to multiply the size by 1024 or\n");
|
|
printf(" \ta 'm' suffix to multiple the size by 1024*1024.\n");
|
|
printf(" -b [bootblock]\tSpecify the bootblock blob\n");
|
|
printf(" -C [lzma|nrv2b]\tSpecify the compression method to use\n\n");
|
|
printf(" -e pre-parse the payload ELF into LAR segments. Recommended\n\n");
|
|
|
|
printf("General options\n");
|
|
printf(" -v\tEnable verbose mode\n");
|
|
printf(" -V\tShow the version\n");
|
|
printf(" -h\tShow this help\n");
|
|
printf("\n");
|
|
}
|
|
|
|
int elfparse(void)
|
|
{
|
|
return iselfparse;
|
|
}
|
|
|
|
/* Add a human touch to the LAR size by allowing suffixes:
|
|
* XX[KkMm] where k = XX * 1024 and m or M = xx * 1024 * 1024
|
|
*/
|
|
|
|
static void parse_larsize(char *str)
|
|
{
|
|
char *p = NULL;
|
|
unsigned int size = strtoul(str, &p, 0);
|
|
|
|
if (p != NULL) {
|
|
if (*p == 'k' || *p == 'K')
|
|
size *= 1024;
|
|
else if (*p == 'm' || *p == 'M')
|
|
size *= (1024 * 1024);
|
|
else if (*p) {
|
|
fprintf(stderr, "Unknown LAR size suffix '%c'\n", *p);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
larsize = size;
|
|
}
|
|
|
|
int verbose(void)
|
|
{
|
|
return isverbose;
|
|
}
|
|
|
|
long get_larsize(void)
|
|
{
|
|
return larsize;
|
|
}
|
|
|
|
char *get_bootblock(void)
|
|
{
|
|
return bootblock;
|
|
}
|
|
|
|
int create_lar(const char *archivename, struct file *files)
|
|
{
|
|
struct lar *lar = lar_new_archive(archivename, larsize);
|
|
|
|
if (lar == NULL) {
|
|
fprintf(stderr, "Unable to create %s as a LAR archive.\n",
|
|
archivename);
|
|
exit(1);
|
|
}
|
|
|
|
for( ; files; files = files->next) {
|
|
if (lar_add_file(lar, files->name)) {
|
|
fprintf(stderr, "Error adding %s to the LAR.\n", files->name);
|
|
lar_close_archive(lar);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (lar_add_bootblock(lar, bootblock)) {
|
|
fprintf(stderr, "Error adding the bootblock to the LAR.\n");
|
|
lar_close_archive(lar);
|
|
exit(1);
|
|
}
|
|
|
|
lar_close_archive(lar);
|
|
return 0;
|
|
}
|
|
|
|
int add_lar(const char *archivename, struct file *files)
|
|
{
|
|
struct lar *lar = lar_open_archive(archivename);
|
|
|
|
if (lar == NULL) {
|
|
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
|
|
exit(1);
|
|
}
|
|
|
|
for( ; files; files = files->next) {
|
|
if (lar_add_file(lar, files->name)) {
|
|
fprintf(stderr, "Error adding %s to the LAR.\n", files->name);
|
|
lar_close_archive(lar);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
lar_close_archive(lar);
|
|
return 0;
|
|
}
|
|
|
|
int list_lar(const char *archivename, struct file *files)
|
|
{
|
|
struct lar *lar = lar_open_archive(archivename);
|
|
|
|
if (lar == NULL) {
|
|
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
|
|
exit(1);
|
|
}
|
|
|
|
lar_list_files(lar, files);
|
|
lar_close_archive(lar);
|
|
return 0;
|
|
}
|
|
|
|
int extract_lar(const char *archivename, struct file *files)
|
|
{
|
|
int ret;
|
|
|
|
struct lar *lar = lar_open_archive(archivename);
|
|
|
|
if (lar == NULL) {
|
|
fprintf(stderr, "Unable to open LAR archive %s\n", archivename);
|
|
exit(1);
|
|
}
|
|
|
|
ret = lar_extract_files(lar, files);
|
|
lar_close_archive(lar);
|
|
return ret;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int opt;
|
|
int option_index = 0;
|
|
|
|
int larmode = NONE;
|
|
|
|
char *archivename = NULL;
|
|
|
|
static struct option long_options[] = {
|
|
{"add", 0, 0, 'a'},
|
|
{"create", 0, 0, 'c'},
|
|
{"compress-algo", 1, 0, 'C'},
|
|
{"extract", 0, 0, 'x'},
|
|
{"list", 0, 0, 'l'},
|
|
{"size", 1, 0, 's'},
|
|
{"bootblock", 1, 0, 'b'},
|
|
{"elfparse", 1, 0, 'e'},
|
|
{"verbose", 0, 0, 'v'},
|
|
{"version", 0, 0, 'V'},
|
|
{"help", 0, 0, 'h'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
if (argc < 3) {
|
|
usage(argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
while ((opt = getopt_long(argc, argv, "acC:xels:b:vVh?",
|
|
long_options, &option_index)) != EOF) {
|
|
switch (opt) {
|
|
case 'a':
|
|
larmode = ADD;
|
|
break;
|
|
case 'c':
|
|
larmode = CREATE;
|
|
break;
|
|
case 'C':
|
|
if (strcasecmp("lzma", optarg) == 0) {
|
|
algo = lzma;
|
|
}
|
|
if (strcasecmp("nrv2b", optarg) == 0) {
|
|
algo = nrv2b;
|
|
}
|
|
break;
|
|
case 'l':
|
|
larmode = LIST;
|
|
break;
|
|
case 'e':
|
|
iselfparse = 1;
|
|
break;
|
|
case 'x':
|
|
larmode = EXTRACT;
|
|
break;
|
|
case 's':
|
|
parse_larsize(optarg);
|
|
break;
|
|
case 'b':
|
|
bootblock = strdup(optarg);
|
|
if (!bootblock) {
|
|
fprintf(stderr, "Out of memory.\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'v':
|
|
isverbose = 1;
|
|
break;
|
|
case 'V':
|
|
printf("LAR - the LinuxBIOS Archiver " VERSION "\n");
|
|
break;
|
|
default:
|
|
usage(argv[0]);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// tar compatibility: Allow lar x as alternative to
|
|
// lar -x. This should be dropped or done correctly.
|
|
// Right now, you'd have to write lar x -v instead of
|
|
// lar xv... but the author of this software was too
|
|
// lazy to handle all option parameter twice.
|
|
if (larmode == NONE && optind < argc) {
|
|
if (strncmp(argv[optind], "x", 2) == 0)
|
|
larmode = EXTRACT;
|
|
else if (strncmp(argv[optind], "c", 2) == 0)
|
|
larmode = CREATE;
|
|
else if (strncmp(argv[optind], "l", 2) == 0)
|
|
larmode = LIST;
|
|
|
|
/* If larmode changed in this if branch,
|
|
* eat a parameter
|
|
*/
|
|
if (larmode != NONE)
|
|
optind++;
|
|
}
|
|
|
|
if (larmode == NONE) {
|
|
usage(argv[0]);
|
|
fprintf(stderr, "Error: No mode specified.\n\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* size only makes sense when creating a lar */
|
|
if (larmode != CREATE && larsize) {
|
|
printf("Warning: size parameter ignored since "
|
|
"not creating an archive.\n");
|
|
}
|
|
|
|
if (bootblock) {
|
|
|
|
/* adding a bootblock only makes sense when creating a lar */
|
|
if (larmode != CREATE) {
|
|
printf("Warning: bootblock parameter ignored since "
|
|
"not creating an archive.\n");
|
|
}
|
|
|
|
/* adding a bootblock only makes sense when creating a lar */
|
|
if (!larsize) {
|
|
printf("When creating a LAR archive, you must specify an archive size.\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (optind < argc) {
|
|
archivename = argv[optind++];
|
|
} else {
|
|
|
|
usage(argv[0]);
|
|
fprintf(stderr, "Error: No archive name.\n\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* when a new archive is created, recurse over
|
|
* physical files when a directory is found.
|
|
* Otherwise just add the directory to the match list
|
|
*/
|
|
|
|
while (optind < argc) {
|
|
if (larmode == CREATE) {
|
|
add_files(argv[optind++]);
|
|
} else
|
|
add_file_or_directory(argv[optind++]);
|
|
}
|
|
|
|
switch (larmode) {
|
|
case ADD:
|
|
add_lar(archivename, get_files());
|
|
break;
|
|
case EXTRACT:
|
|
extract_lar(archivename, get_files());
|
|
break;
|
|
case CREATE:
|
|
create_lar(archivename, get_files());
|
|
break;
|
|
case LIST:
|
|
list_lar(archivename, get_files());
|
|
break;
|
|
}
|
|
|
|
free_files();
|
|
return 0;
|
|
}
|