diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 4fc7c9795a..2ff87af963 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -27,32 +27,17 @@ INITCFLAGS := $(CFLAGS) -I$(src)/include/cpu/generic/x86 -I$(src)/include \ SILENT := &> /dev/null # -# Build the final ROM image. +# Build the ROM Image / LAR archive # -# These are the main LinuxBIOS components. Do not change the order unless you -# know exactly what you are doing. +# LinuxBIOS v3 is completely modular. One module, the bootblock (stage0), +# is mandatory. All modules are packed together in a LAR archive. +# The LAR archive may contain any number of stages, payloads and option ROMs. # -LINUXBIOS_COMPONENTS := linuxbios.lar linuxbios.vpd stage0.init +ROM_SIZE := $(shell expr $(CONFIG_LINUXBIOS_ROMSIZE_KB) \* 1024 ) -$(obj)/linuxbios.rom: $(patsubst %,$(obj)/%,$(LINUXBIOS_COMPONENTS)) - $(Q)cat $^ > $@ - $(Q)# QEMU wants bios.bin: - $(Q)# Run "qemu -L build/ -nographic -hda /dev/zero". - $(Q)cp $@ $(obj)/bios.bin - -# -# Build the LAR archive. -# -# LinuxBIOS v3 is completely modular and based on a very small startup -# code (stage0) plus a LAR archive. The LAR archive may contain any number -# of stages, payloads and option ROMs. -# - -LAR_SIZE := $(shell expr \( $(CONFIG_LINUXBIOS_ROMSIZE_KB) - 16 \) \* 1024 ) - -$(obj)/linuxbios.lar: $(obj)/util/lar/lar lzma $(obj)/linuxbios.initram $(obj)/linuxbios.stage2 payload - $(Q)printf "Building LinuxBIOS archive... \n" +$(obj)/linuxbios.rom: $(obj)/linuxbios.bootblock $(obj)/util/lar/lar lzma $(obj)/linuxbios.initram $(obj)/linuxbios.stage2 payload + $(Q)printf "Building LinuxBIOS image... \n" $(Q)rm -rf $(obj)/lar.tmp $(Q)mkdir $(obj)/lar.tmp $(Q)mkdir $(obj)/lar.tmp/normal @@ -60,7 +45,14 @@ $(obj)/linuxbios.lar: $(obj)/util/lar/lar lzma $(obj)/linuxbios.initram $(obj)/l $(Q)cp $(obj)/linuxbios.stage2 $(obj)/lar.tmp/normal/stage2 $(Q)cp $(CONFIG_PAYLOAD) $(obj)/lar.tmp/normal/payload $(Q)printf " " - $(Q)cd $(obj)/lar.tmp && ../util/lar/lar -cv ../linuxbios.lar . -s $(LAR_SIZE) + $(Q)cd $(obj)/lar.tmp && ../util/lar/lar -cv ../linuxbios.rom . \ + -s $(ROM_SIZE) -b $(obj)/linuxbios.bootblock + $(Q)# QEMU wants bios.bin: + $(Q)# Run "qemu -L build/ -nographic -hda /dev/zero". + $(Q)cp $@ $(obj)/bios.bin + +$(obj)/linuxbios.bootblock: $(obj)/linuxbios.vpd $(obj)/stage0.init + $(Q)cat $^ > $@ # # LinuxBIOS stage0. This is the LinuxBIOS "boot block code". diff --git a/util/lar/Makefile b/util/lar/Makefile index 2576d5b250..8d211d0355 100644 --- a/util/lar/Makefile +++ b/util/lar/Makefile @@ -18,7 +18,7 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA ## -SOURCE := lar.c create.c extract.c list.c lib.c +SOURCE := lar.c create.c extract.c list.c lib.c bootblock.c $(obj)/util/lar/lar: $(patsubst %,$(src)/util/lar/%,$(SOURCE)) $(Q)printf "Building LAR utility... " diff --git a/util/lar/bootblock.c b/util/lar/bootblock.c new file mode 100644 index 0000000000..2d2509e576 --- /dev/null +++ b/util/lar/bootblock.c @@ -0,0 +1,90 @@ +/* + * lar - LinuxBIOS archiver + * + * Copyright (C) 2007 coresystems GmbH + * Written by Stefan Reinauer 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 +#include +#include +#include +#include + +#include "lar.h" +#include "lib.h" + +char *bootblock_code; +int bootblock_len; + +int load_bootblock(const char *bootblock) +{ + struct stat statbuf; + int ret, filelen; + FILE *fh; + + ret = stat(bootblock, &statbuf); + if (ret) { + fprintf(stderr, "No such file %s\n", bootblock); + exit(1); + } + bootblock_len = statbuf.st_size; + + /* We might want to find additional criteria + * for identifying a bootblock file + */ + if (bootblock_len != BOOTBLOCK_SIZE) { + printf("Warning: %s does not seem to be a bootblock, " + "so ignore it\n", bootblock); + bootblock_code=NULL; + bootblock_len=0; + // Is this an error condition? + } + + bootblock_code = malloc(bootblock_len); + if (!bootblock_code) { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + + fh = fopen(bootblock, "r"); + if (!fh) { + fprintf(stderr, "Error while reading file %s\n", bootblock); + exit(1); + } + + fread(bootblock_code, bootblock_len, 1, fh); + fclose(fh); + + return ret; +} + +int fixup_bootblock(void) +{ + /* Per definition the bootblock starts with 256 empty bytes. + * These are utilized to make the bootblock part of a lar file, + * and store the image size. + * + * We will also calculate a checksum here. + */ + + /* first try. Clear out ugly left-over from ld hack */ + bootblock_code[bootblock_len - 13] = '\0'; + bootblock_code[bootblock_len - 12] = '\0'; + + return 0; +} + diff --git a/util/lar/create.c b/util/lar/create.c index 503a3bc1e4..609c1ef3f3 100644 --- a/util/lar/create.c +++ b/util/lar/create.c @@ -28,6 +28,8 @@ #include #include #include +#include + #include "lib.h" #include "lar.h" @@ -36,6 +38,7 @@ int create_lar(const char *archivename, struct file *files) { int i, ret; int diff = 0; + int bb_header_len = 0; FILE *archive, *source; char *tempmem; char *filebuf; @@ -133,11 +136,42 @@ int create_lar(const char *archivename, struct file *files) } /* Calculate difference, if a size has been specified. + * If diff is below zero, the size has been exceeded. + * If diff is above zero, it specifies the number of + * padding bytes required for the image. * Otherwise diff stays 0 and no action is taken below. */ if (get_larsize()) diff = get_larsize() - currentsize; + /* If there's a bootblock loaded, some space is required + * _after_ the padding. + * Calculate this size here, but write the bootblock later. + */ + + if (bootblock_len) { + printf ("Detected bootblock of %d bytes\n", bootblock_len); + + bb_header_len = sizeof(struct lar_header) + + ((strlen(basename(get_bootblock()))+15) & 0xfffffff0); + + bb_header_len = (bb_header_len + 15) & 0xfffffff0; + + printf ("Required bootblock header of %d bytes\n", bb_header_len); + + diff -= bootblock_len; + diff -= bb_header_len; + } + + /* The image became too big. Print an error message and exit, + * deleting the file. So nobody used an invalid image by accident. + * + * Don't delete the image in "Out of memory" situations. If memory + * is _that_ tight that a few bytes don't fit anymore, everything + * else will fail as well, so just print an error and exit the + * program as soon as possible. + */ + if (diff < 0) { fprintf(stderr, "Error: LAR archive exceeded size (%ld > %ld)\n", @@ -150,6 +184,8 @@ int create_lar(const char *archivename, struct file *files) return -1; } + /* Pad the image. */ + if (diff > 0) { char *padding; /* generate padding (0xff is flash friendly) */ @@ -163,6 +199,36 @@ int create_lar(const char *archivename, struct file *files) free(padding); } + if (bootblock_len) { + char *bootblock_header; + struct lar_header *bb; + + bootblock_header = malloc(bb_header_len); + if(!bootblock_header) { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + + memset (bootblock_header, 0, bb_header_len); + + /* construct header */ + bb=(struct lar_header *)bootblock_header; + memcpy(bb->magic, MAGIC, 8); + bb->len = htonl(bootblock_len); + bb->offset = htonl(bb_header_len); + + /* TODO checksum */ + + /* Write filename. we calculated the buffer size, + * so no overflow danger here. + */ + strcpy(bootblock_header+sizeof(struct lar_header), + basename(get_bootblock()) ); + + fwrite(bootblock_header, bb_header_len, 1, archive); + fwrite(bootblock_code, bootblock_len, 1, archive); + } + fclose(archive); if (verbose()) diff --git a/util/lar/lar.c b/util/lar/lar.c index 4cd2a7eec4..e7872848a8 100644 --- a/util/lar/lar.c +++ b/util/lar/lar.c @@ -33,7 +33,7 @@ #include "lib.h" #include "lar.h" -#define VERSION "v0.9" +#define VERSION "v0.9.1" #define COPYRIGHT "Copyright (C) 2006-2007 coresystems GmbH" static int isverbose = 0; @@ -103,7 +103,6 @@ int main(int argc, char *argv[]) larsize = strtol(optarg, (char **)NULL, 10); break; case 'b': - printf("Bootblock handling not yet supported. Ignoring.\n"); bootblock = strdup(optarg); if (!bootblock) { fprintf(stderr, "Out of memory.\n"); @@ -144,7 +143,7 @@ int main(int argc, char *argv[]) if (larmode == NONE) { usage(argv[0]); - printf("Error: No mode specified.\n\n"); + fprintf(stderr, "Error: No mode specified.\n\n"); exit(1); } @@ -154,12 +153,34 @@ int main(int argc, char *argv[]) "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("Warning: When specifying a bootblock " + "you should also set an archive size.\n"); + } + + /* load the bootblock */ + if (larmode == CREATE) { + load_bootblock(bootblock); + fixup_bootblock(); + } + + } + if (optind < argc) { archivename = argv[optind++]; } else { usage(argv[0]); - printf("Error: No archive name.\n\n"); + fprintf(stderr, "Error: No archive name.\n\n"); exit(1); } diff --git a/util/lar/lar.h b/util/lar/lar.h index 2cf19d4a67..56e2376a04 100644 --- a/util/lar/lar.h +++ b/util/lar/lar.h @@ -51,6 +51,7 @@ #define MAGIC "LARCHIVE" #define MAX_PATHLEN 1024 +#define BOOTBLOCK_SIZE 16384 typedef uint32_t u32; diff --git a/util/lar/lib.h b/util/lar/lib.h index b65be1a1cd..de9d37f263 100644 --- a/util/lar/lib.h +++ b/util/lar/lib.h @@ -58,4 +58,10 @@ int list_lar(const char *archivename, struct file *files); /* prototypes for create.c functions */ int create_lar(const char *archivename, struct file *files); +/* prototypes for bootblock.c functions */ +extern char *bootblock_code; +extern int bootblock_len; + +int load_bootblock(const char *bootblock); +int fixup_bootblock(void); #endif