[LinuxBIOS] patch: extending LAR, and removing elf from linuxbios (it is not needed)

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Tue Aug 28 01:54:41 CEST 2007


On 27.08.2007 19:25, ron minnich wrote:
> 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.
> 
> 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 payload0, payload1, 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!

What about creating directories for each payload so we can differentiate
between multiple payloads (in the original sense)?

  normal/payload0/segment0 (33192 bytes, lzma compressed to 18088 bytes
@0x38 load @0x100000, entry 0x105258)
  normal/payload0/segment1 (72 bytes, lzma compressed to 47 bytes
@0x4718 load @0x1225a0, entry 0x105258)
  normal/payload1/segment0 (xxx bytes, lzma compressed to yyy bytes
@0xfoo load @0xbar, entry 0xbaz)
  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)

The normal/payload0/ directory would contain the ELF segments of the
first payload etc. The mapping between your proposal and mine would be:
Yours          <->      Mine
normal/payload0   normal/payload0/segment0
normal/payload1   normal/payload0/segment1
N/A               normal/payload1/segment0

What do you think?

Comments about the patch:

> --- include/lar.h	(revision 464)

This is against an old tree. lar has changed in between.

> +++ include/lar.h	(working copy)
> @@ -54,7 +54,7 @@
>  
>  #define MAGIC "LARCHIVE"
>  #define MAX_PATHLEN 1024
> -
> +/* NOTE -- This and the user-mode lar.h are NOT IN SYNC. Be careful. */

Maybe also mention util/lar/README which is even less in sync.

>  struct lar_header {
>  	char magic[8];
>  	u32 len;
> @@ -62,6 +62,13 @@
>  	u32 checksum;
>  	u32 compchecksum;
>  	u32 offset;
> +	u32 entry;		/* we might need to make this u64 */
> +	u32 loadaddress; /* ditto */
> +	/* Compression:
> +	 * 0 = no compression
> +	 * 1 = lzma
> +	 * 2 = nrv2b
> +	 */
>  	u32 compression;
>  };
>  

Maybe we should introduce a major/minor version in the LAR header? Or a
different magic string for each revision?
Do we also need an alignment parameter in the header (like "free
placement, but please align to xx")?

> @@ -69,6 +76,8 @@
>  	void *start;
>  	int len;
>  	u32 reallen;
> +	void * entry;
> +	void * loadaddress;

void *entry;
void *loadaddress;

>  	u32 compression;
>  };
>  
> @@ -77,5 +86,6 @@
>  int copy_file(struct mem_file *archive, char *filename, void *where);
>  int run_file(struct mem_file *archive, char *filename, void *where);
>  int execute_in_place(struct mem_file *archive, char *filename);
> -
> +int run_address(void *f);
> +void * load_file(struct mem_file *archive, char *filename);

void *load_file(...)

>  #endif /* LAR_H */
> --- lib/lar.c	(revision 464)
> +++ lib/lar.c	(working copy)
> @@ -52,19 +59,69 @@
>  		// FIXME: check checksum
>  
>  		if (strcmp(fullname, filename) == 0) {
> +			printk(BIOS_SPEW, "LAR: it matches %s @ %p\n", fullname, header);
>  			result->start = walk + ntohl(header->offset);
>  			result->len = ntohl(header->len);
>  			result->reallen = ntohl(header->reallen);
>  			result->compression = ntohl(header->compression);
> +			result->entry = (void *)ntohl(header->entry);
> +			result->loadaddress = (void *)ntohl(header->loadaddress);
> +			printk(BIOS_SPEW, "start %p len %d reallen %d compression %x entry %p loadaddress %p\n", 
> +				result->start, result->len, result->reallen, result->compression, result->entry, result->loadaddress);
>  			return 0;
>  		}
>  		// skip file
>  		walk += (ntohl(header->len) + ntohl(header->offset) -
>  			1) & 0xfffffff0;
>  	}
> +	printk(BIOS_SPEW, "NO FILE FOUND\n");
>  	return 1;
>  }
>  
> +
> +void * load_file(struct mem_file *archive, char *filename)

void *load_file(...)

> +{
> +	int ret;
> +	struct mem_file result;
> +	void *where;
> +	void *entry;
> +
> +	ret = find_file(archive, filename, &result);
> +	if (ret) {
> +		printk(BIOS_INFO, "LAR: load_file: No such file '%s'\n",
> +		       filename);
> +		return (void *)-1;
> +	}
> +	entry = result.entry;
> +	where = result.loadaddress;
> +	printk(BIOS_SPEW, "LAR: Compression algorithm #%i used\n", result.compression);
> +	/* no compression */
> +	if (result.compression == 0) {
> +		memcpy(where, result.start, result.len);
> +		return entry;
> +	}
> +#ifdef CONFIG_COMPRESSION_LZMA
> +	/* lzma */
> +	unsigned long ulzma(unsigned char * src, unsigned char * dst);

dito.

> +	if (result.compression == 1) {
> +		ulzma(result.start, where);
> +		return entry;
> +	}
> +#endif
> +#ifdef CONFIG_COMPRESSION_NRV2B
> +	/* nrv2b */
> +	unsigned long unrv2b(u8 * src, u8 * dst, unsigned long *ilen_p);

dito.

> +	if (result.compression == 2) {
> +		int tmp;
> +		unrv2b(result.start, where, &tmp);
> +		return entry;
> +	}
> +#endif
> +	printk(BIOS_INFO, "LAR: Compression algorithm #%i not supported!\n", result.compression);
> +	return (void *)-1;
> +}
> +

> --- mainboard/emulation/qemu-x86/initram.c	(revision 464)
> +++ mainboard/emulation/qemu-x86/initram.c	(working copy)
> @@ -19,10 +19,12 @@
>  
>  #include <console.h>
>  
> +int (*pk)(int msg_level, const char *fmt, ...) = printk;
> +
>  int main(void)
>  {
> -	printk(BIOS_INFO, "RAM init code started.\n");
> -	printk(BIOS_INFO, "Nothing to do.\n");
> +	pk(BIOS_INFO, "RAM init code started.\n");
> +	pk(BIOS_INFO, "Nothing to do.\n");
>  
>  	return 0;
>  }

My eyes!

> --- mainboard/emulation/qemu-x86/Makefile	(revision 464)
> +++ mainboard/emulation/qemu-x86/Makefile	(working copy)
> @@ -41,14 +41,17 @@
>  #
>  
>  INITRAM_OBJ = $(obj)/mainboard/$(MAINBOARDDIR)/initram.o
> +$(obj)/mainboard/$(MAINBOARDDIR)/initram.o: $(src)/mainboard/$(MAINBOARDDIR)/initram.c
> +	cc -c $(INITCFLAGS)  -fPIE $(src)/mainboard/$(MAINBOARDDIR)/initram.c -o $(obj)/mainboard/$(MAINBOARDDIR)/initram.o
> +
>  # These are possibly not permanent
> -INITRAM_OBJ += $(obj)/lib/console.o $(obj)/lib/vtxprintf.o $(obj)/lib/uart8250.o $(obj)/arch/x86/post_code.o
> +#INITRAM_OBJ += $(obj)/lib/console.o $(obj)/lib/vtxprintf.o $(obj)/lib/uart8250.o $(obj)/arch/x86/post_code.o
>  
>  $(obj)/linuxbios.initram: $(obj)/stage0.init $(obj)/stage0.o $(INITRAM_OBJ)
>  	$(Q)# initram links against stage0
>  	$(Q)printf "  LD      $(subst $(shell pwd)/,,$(@))\n"
> -	$(Q)$(LD)  -Ttext 0x80000 $(INITRAM_OBJ) \
> -		--entry=main -o $(obj)/linuxbios.initram.o
> +	$(Q)$(LD)  $(INITRAM_OBJ) \
> +		--entry=main -R $(obj)/stage0.o -o $(obj)/linuxbios.initram.o
>  	$(Q)printf "  OBJCOPY $(subst $(shell pwd)/,,$(@))\n"
>  	$(Q)$(OBJCOPY) -O binary $(obj)/linuxbios.initram.o \
>  		$(obj)/linuxbios.initram

Could you explain that one?

> Index: arch/x86/stage1.c
> ===================================================================
> --- arch/x86/stage1.c	(revision 464)
> +++ arch/x86/stage1.c	(working copy)
> @@ -144,20 +168,32 @@
>  	printk(BIOS_DEBUG, "Stage2 code done.\n");
>  
>  	ret = find_file(&archive, "normal/payload", &result);
> -	if (ret) {
> -		printk(BIOS_ERR, "No such file '%s'.\n", "normal/payload");
> -		die("FATAL: No payload found.\n");
> +	if (! ret)
> +		legacy(&archive, "normal/payload", (void *)UNCOMPRESS_AREA, mem);
> +
> +
> +	/* new style lar boot. Install all the files in memory. 
> +	  * By convention we take the entry point from the first 

Needs real documentation (LAR README maybe?), not just a code comment.

> +	  * one. Look for a cmdline as well. 

dito.

> +	  */
> +	for(i = 0, entry = (void *)0; ;i++) {
> +		char filename[64];
> +		void *newentry;
> +		sprintf(filename, "normal/payload%d", i);
> +		archive.len = *(u32 *)0xfffffff4;
> +		archive.start =(void *)(0UL-archive.len);
> +		newentry = load_file(&archive, filename);
> +		printk("newentry is %p\n", newentry);
> +		if (newentry == (void *)-1)
> +			break;
> +		if (! entry)
> +			entry = newentry;
>  	}
> -	ret = copy_file(&archive, "normal/payload", (void *)UNCOMPRESS_AREA);
> -	if (ret) {
> -		printk(BIOS_ERR, "'%s' found, but could not load it.\n", "normal/payload");
> -		die("FATAL: No usable payload found.\n");
> -	}
> +	printk(BIOS_SPEW, "all loaded, entry %p\n", entry);
> +	run_address(entry);
>  
> -	ret =  elfboot_mem(mem, (void *)UNCOMPRESS_AREA, result.reallen);
> +	die("FATAL: No usable payload found.\n");
>  
> -	printk(BIOS_ERR, "elfboot_mem returns %d\n", ret);
> -
>  	die ("FATAL: Last stage returned to LinuxBIOS.\n");
>  }
>  
> Index: arch/x86/Makefile
> ===================================================================
> --- arch/x86/Makefile	(revision 464)
> +++ arch/x86/Makefile	(working copy)
> @@ -22,7 +22,7 @@
>  ifeq ($(CONFIG_ARCH_X86),y)
>  
>  INITCFLAGS := $(CFLAGS) -I$(src)/include/arch/x86 -I$(src)/include \
> -		-I$(obj) -fno-builtin
> +		-I$(obj) -fno-builtin  

Superfluous whitespace introduction.

>  SILENT := >/dev/null 2>&1
>  
> @@ -77,7 +77,7 @@
>  	fi
>  endif
>  	$(Q)printf "  LAR     $(subst $(shell pwd)/,,$(@))\n"
> -	$(Q)cd $(obj)/lar.tmp && ../util/lar/lar $(COMPRESSFLAG) -c \
> +	$(Q)cd $(obj)/lar.tmp && ../util/lar/lar -p $(COMPRESSFLAG) -c \

lar -p option is not mentioned in the lar help message.

>  		../linuxbios.rom \
>  		$(LARFILES) \
>  		-s $(ROM_SIZE) -b $(obj)/linuxbios.bootblock
> @@ -142,6 +142,9 @@
>  	$(Q)printf "  OBJCOPY $(subst $(shell pwd)/,,$(@))\n"
>  	$(Q)$(OBJCOPY) -O binary $(obj)/stage0.o $(obj)/stage0.init
>  
> +	$(Q)printf " OBJCOPY (stage0 link) $(subst $(shell pwd)/,,$(@))\n"
> +	$(Q)$(OBJCOPY) --prefix-symbols=stage0 $(obj)/stage0.o $(obj)/stage0_link.o
> +
>  	$(Q)printf "  TEST    $(subst $(shell pwd)/,,$(@))\n"
>  	$(Q)test `wc -c < $(obj)/stage0.init` -gt 16128 && \
>  		printf "Error. Bootblock got too big.\n" || true

Please explain.

> --- util/lar/lar.c	(revision 464)

old revision, you will have to make sure the merge won't kill the
changes since 464.

> +++ util/lar/lar.c	(working copy)
> @@ -37,6 +37,7 @@
>  #define COPYRIGHT "Copyright (C) 2006-2007 coresystems GmbH"
>  
>  static int isverbose = 0;
> +static int isparseelf = 0;
>  static long larsize = 0;
>  static char *bootblock = NULL;
>  enum compalgo algo = none;
> @@ -44,9 +45,14 @@
>  static void usage(char *name)
>  {
>  	printf("\nLAR - the LinuxBIOS Archiver " VERSION "\n" COPYRIGHT "\n\n"
> -	       "Usage: %s [-cxl] archive.lar [[[file1] file2] ...]\n\n", name);
> +	       "Usage: %s [-ecxl] archive.lar [[[file1] file2] ...]\n\n", name);

ecxl is missing a few options, among them p.

>  }
>  
> +int parseelf(void)
> +{
> +	return isparseelf;
> +}
> +
>  int verbose(void)
>  {
>  	return isverbose;
> @@ -78,6 +84,7 @@
>  		{"list", 0, 0, 'l'},
>  		{"size", 1, 0, 's'},
>  		{"bootblock", 1, 0, 'b'},
> +		{"parseelf", 1, 0, 'p'},
>  		{"verbose", 0, 0, 'v'},
>  		{"version", 0, 0, 'V'},
>  		{"help", 0, 0, 'h'},
> @@ -89,7 +96,7 @@
>  		exit(1);
>  	}
>  
> -	while ((opt = getopt_long(argc, argv, "cC:xls:b:vVh?",
> +	while ((opt = getopt_long(argc, argv, "cC:xlps:b:vVh?",
>  				  long_options, &option_index)) != EOF) {
>  		switch (opt) {
>  		case 'c':
> @@ -106,6 +113,9 @@
>  		case 'l':
>  			larmode = LIST;
>  			break;
> +		case 'p':
> +			isparseelf = 1;
> +			break;
>  		case 'x':
>  			larmode = EXTRACT;
>  			break;

> --- util/lar/create.c	(revision 464)
> +++ util/lar/create.c	(working copy)
> @@ -49,6 +49,201 @@
>  	out_len[0] = in_len;
>  }
>  
> +char *readfile(char *name, int *plen)
> +{
> +	int ret, filelen;
> +	FILE *source;
> +	char *filebuf;
> +	struct stat statbuf;
> +	*plen = -1;
> +	ret = stat(name, &statbuf);
> +	if (ret) {
> +		fprintf(stderr, "No such file %s\n", name);
> +		exit(1);
> +	}
> +	filelen = statbuf.st_size;
> +	/* Read file into memory. */
> +	filebuf = malloc(filelen);
> +	source = fopen(name, "r");
> +	if (!source) {
> +		fprintf(stderr, "No such file %s\n", name);
> +		exit(1);
> +	}
> +	fread(filebuf, filelen, 1, source);
> +	fclose(source);
> +	*plen = filelen;
> +	return filebuf;
> +}
> +
> +/* given an output file name, with data pointed to by filebuf, of size filelen,
> +  * output it to the lar define by FILE *lar
> +  */
> +int
> +outputfile(char *name, char *filebuf, int filelen, enum compalgo algo, FILE *archive, u32 entry, u32 loadaddress)

int outputfile(...

> +{
> +	char *pathname;
> +	int i, ret;
> +	int diff = 0;
> +	int bb_header_len = 0;
> +	FILE *source;
> +	char *filetarget;
> +	u32 *walk;
> +	u32 csum;
> +	int pathlen, entrylen;
> +	u32 compfilelen;
> +	long currentsize = 0;
> +	struct lar_header *header;
> +	enum compalgo thisalgo;
> +	char *tempmem;
> +	thisalgo = algo;
> +	int tempsize = sizeof(struct lar_header) + MAX_PATHLEN + filelen + 16;
> +		tempmem = malloc(tempsize);
> +		if (!tempmem) {
> +			fprintf(stderr, "Out of memory.\n");
> +			return (-1);
> +		}
> +		memset(tempmem, 0, tempsize);
> +		header = (struct lar_header *)tempmem;
> +		pathname = tempmem + sizeof(struct lar_header);
> +		pathlen = snprintf(pathname, MAX_PATHLEN - 1, name) + 1;
> +		pathlen = (pathlen + 15) & 0xfffffff0;	/* Align to 16 bytes. */
> +
> +		filetarget = pathname + pathlen;
> +		compress_functions[thisalgo](filebuf, filelen, filetarget,
> +					     &compfilelen);
> +		if ((compfilelen >= filelen) && (thisalgo != none)) {
> +			thisalgo = none;
> +			compress_functions[thisalgo](filebuf, filelen,
> +						     filetarget, &compfilelen);
> +		}
> +
> +		/* Create correct header. */
> +		memcpy(header, MAGIC, 8);
> +		header->compression = htonl(thisalgo);
> +		header->entry = htonl(entry);
> +		header->loadaddress = htonl(loadaddress);
> +		header->reallen = htonl(filelen);
> +		header->len = htonl(compfilelen);
> +		header->offset = htonl(sizeof(struct lar_header) + pathlen);
> +		/* Calculate checksum. */
> +		csum = 0;
> +		for (walk = (u32 *) tempmem;
> +		     walk < (u32 *) (tempmem + compfilelen +
> +				     sizeof(struct lar_header) + pathlen);
> +		     walk++) {
> +			csum += ntohl(*walk);
> +		}
> +		header->checksum = htonl(csum);
> +		/* Write out entry to archive. */
> +		entrylen = (compfilelen + pathlen + sizeof(struct lar_header) +
> +			    15) & 0xfffffff0;
> +
> +		fwrite(tempmem, entrylen, 1, archive);
> +		free(tempmem);
> +	return entrylen;
> +}
> [...]
> +
> +int
> +outputelf(char *name, char *filebuf, int filelen, enum compalgo algo, FILE *archive)

dito.

> +{
> +	int index;

> --- util/lar/Makefile	(revision 464)
> +++ util/lar/Makefile	(working copy)
> @@ -33,14 +34,15 @@
>  endif
>  
>  LAROBJ_ABS := $(patsubst %,$(obj)/util/lar/%,$(LAROBJ))
> -
> +HOSTCFLAGS+=-g
> +HOSTCXXFLAGS+=-g
>  lardir:
>  	$(Q)printf "  BUILD   LAR\n"
>  	$(Q)mkdir -p $(obj)/util/lar
>  
>  $(obj)/util/lar/lar: $(LARDIR) $(LAROBJ_ABS) $(COMPRESSOR)
>  	$(Q)printf "  HOSTCXX $(subst $(shell pwd)/,,$(@))\n"
> -	$(Q)$(HOSTCXX) $(HOSTCXXFLAGS) -o $@ $(LAROBJ_ABS) $(COMPRESSOR)
> +	$(Q)$(HOSTCXX) $(HOSTCXXFLAGS)  -o $@ $(LAROBJ_ABS) $(COMPRESSOR)

Superfluous whitespace.

>  
>  $(obj)/util/lar/%.o: $(src)/util/lar/%.c
>  	$(Q)printf "  HOSTCC  $(subst $(shell pwd)/,,$(@))\n"
> 
> 


Regards,
Carl-Daniel





More information about the coreboot mailing list