diff --git a/util/baremetal/Makefile b/util/baremetal/Makefile new file mode 100644 index 0000000000..bd3bfe6e4c --- /dev/null +++ b/util/baremetal/Makefile @@ -0,0 +1,10 @@ +CC = gcc +CFLAGS = -I include -O2 + +DEPS = bootselect.o rom_fill_inbuf.o chooser.o lib/baremetal.a + +bootselect.elf: $(DEPS) + ld -defsym HEAPSIZE=0 -T elfImage.lds $(DEPS) -o bootselect.elf + +clean: + rm bootselect.elf *.o diff --git a/util/baremetal/README b/util/baremetal/README new file mode 100644 index 0000000000..7a8957d56d --- /dev/null +++ b/util/baremetal/README @@ -0,0 +1,28 @@ + This is the bare metal toolkit for LinuxBIOS. + +It was produced and is maintained by Steven James + +It's purpose is to simplify development of standalone ELF executables suitable +as a payload for LinuxBIOS. Two examples are included, hello and bootselect. +Most of this toolkit comes from LinuxBIOS itself. A few pieces are borrowed +from Etherboot (such as code to locate and use the LinuxBIOS table). + +It is important to note that even though the main part is a Library, Since +it is built from GPL code, it falls under GPL, not LGPL. This may matter to +you in production since that means your project will also need to be GPL in +order to be linked with this toolkit. + +This is an early release. It has been used successfully to produce several +payloads. However, as it is an early release, if you intend to use the payloads +in production, it may be best to maintain your own production snapshot for a bit. + + Hello is a simple example program. All it does is say hello, then you +hit reset :-) + + Bootselect allows for multiple choice payloads. It scans the flash ROM +for tagged executable images and checks to see if a character is waiting on the +serial console. If not, the first image is run immediatly. If a character is +waiting, it is dropped, a list of tagged images is presented. The user selects +the image by number. This can come in quite handy for testing, or for loading +diagnostic and other secondary firmware. + diff --git a/util/baremetal/TODO b/util/baremetal/TODO new file mode 100644 index 0000000000..681ee59302 --- /dev/null +++ b/util/baremetal/TODO @@ -0,0 +1,3 @@ + +1. Figure out why the trick of moving out of the way when loading a new ELF + image is failing diff --git a/util/baremetal/bootselect/Makefile b/util/baremetal/bootselect/Makefile new file mode 100644 index 0000000000..f81e436847 --- /dev/null +++ b/util/baremetal/bootselect/Makefile @@ -0,0 +1,14 @@ + +ARCH = i386 + +CC = gcc + +CFLAGS = -I ../include -I ../include/$(ARCH) -O2 + +DEPS = bootselect.o rom_fill_inbuf.o chooser.o ../lib/baremetal.a + +bootselect.elf: $(DEPS) + ld -defsym HEAPSIZE=0x8000 -T elfImage.lds $(DEPS) -o bootselect.elf + +clean: + rm bootselect.elf *.o diff --git a/util/baremetal/bootselect/TODO b/util/baremetal/bootselect/TODO new file mode 100644 index 0000000000..5e69c570f2 --- /dev/null +++ b/util/baremetal/bootselect/TODO @@ -0,0 +1,3 @@ + +Add support for gzipped target +Add support for other stream types such as IDE diff --git a/util/baremetal/bootselect/bootselect.c b/util/baremetal/bootselect/bootselect.c new file mode 100644 index 0000000000..07396535b0 --- /dev/null +++ b/util/baremetal/bootselect/bootselect.c @@ -0,0 +1,50 @@ +/************************************************************************ + * + * bootselect.c + * A standalone rom image selector for LinuxBIOS + * + * Copyright 2002 Steven James and LinuxLabs + * http://www.linuxlabs.com + * + * Licensed under the GNU General Public License (GPL) v2 or later + * + **********************************************************************/ + + +#include +#include +#include +#include + + +#define DPRINTF( x... ) +//#define DPRINTF printk + +extern struct lb_memory *get_lbmem(void); + +char buffer[16]; + +extern struct stream rom_stream; +struct lb_memory *lbmem; + +int main(void) { + int blocks; + + + while(1) { + printk("Welcome to the LinuxLabs boot chooser!\n"); + + lbmem = get_lbmem(); + + DPRINTF("Got lbmem struct: %08x\n", (unsigned int) lbmem); + + if(choose_stream(&rom_stream) <0) + return(-1); + + elfboot(&rom_stream, lbmem); + } + + outb(0x0e, 0x3f9); + +} + diff --git a/util/baremetal/bootselect/chooser.c b/util/baremetal/bootselect/chooser.c new file mode 100644 index 0000000000..7e5f6e8b5a --- /dev/null +++ b/util/baremetal/bootselect/chooser.c @@ -0,0 +1,76 @@ +/************************************************************************ + * + * bootselect.c + * A standalone rom image selector for LinuxBIOS + * + * Copyright 2002 Steven James and LinuxLabs + * http://www.linuxlabs.com + * + * Licensed under the GNU General Public License (GPL) v2 or later + * + **********************************************************************/ + +#include +#include +#include +#include +#include + + +int choose_stream(struct stream *stream) +{ + int stream_count, i,j; + tag_head *directory, *current; + + if(stream->init() < 0) { + printk_err("could not init stream. This is bad!\n"); + return(-1); + } + + if(!stream->init_tags) + return(0); + + stream_count = stream->init_tags(); + + if(!stream_count) + return(0); + + current = directory = malloc(stream_count * sizeof(tag_head)); + + printk_info("Stream count = %u blocks\n", stream_count); + stream->get_tags(directory); + + j=0; + for(i=stream_count; i>0;) { + current->data[5 + current->block_count*16] = 0; +// printk_info("TAG: block_count = %u, current = %08x\n", current->block_count, (unsigned int ) current); + printk_info("STREAM: %u. %s\n", j++, current->data); + i -= current->block_count; + i--; + current += current->block_count+1; + } + + j=0; + if(iskey()) { + j = ttys0_rx_char(); + j=-1; + + while(j<0) { + printk_info("Choose a stream: "); + j = ttys0_rx_char(); + if(j == 0x1b || j == 'x') + return(-1); + + if(j <0x30 || j> 0x39) { + printk_info(" INVALID RESPONSE\n"); + j=-1; + } else + j-=0x30; + } + } + + + stream->load_tag(j); + + return(0); +} diff --git a/util/baremetal/bootselect/elfImage.lds b/util/baremetal/bootselect/elfImage.lds new file mode 100644 index 0000000000..23c112df3d --- /dev/null +++ b/util/baremetal/bootselect/elfImage.lds @@ -0,0 +1,58 @@ + + + + + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +HEAPSIZE = DEFINED(HEAPSIZE) ? HEAPSIZE : 0x8000; + +ENTRY(main) +SECTIONS +{ +/* . = 0x10000 - (elf_note - elf_header); */ + . = 0x1000; + _text = .; /* Text and read-only data */ + .text . : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .rodata (.): { *(.rodata) } + .kstrtab (.): { *(.kstrtab) } + + + . = ALIGN(16); /* Exception table */ + _etext = .; /* End of text section */ + + .data (.): { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + __bss_start = .; /* BSS */ + .bss (.): { + *(.bss) + } + _ebss = .; + _heap = .; + .heap (.): { + . = HEAPSIZE; + } + _eheap = .; + _end = . ; + + _ram_seg = _text; + _eram_seg = _end; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/util/baremetal/bootselect/rom_fill_inbuf.c b/util/baremetal/bootselect/rom_fill_inbuf.c new file mode 100644 index 0000000000..16c738dfb9 --- /dev/null +++ b/util/baremetal/bootselect/rom_fill_inbuf.c @@ -0,0 +1,227 @@ +/* + * Modified from LinuxBIOS by Steven James + * + */ + + + +#include +#include +#include +#include +#include + +#include + +#ifndef ZKERNEL_START +#define ZKERNEL_START 0xfff00000 +#endif + +#ifndef ZKERNEL_MASK +#define ZKERNEL_MASK 0x0000ffff +#endif + +#ifndef _ROMTOP +#define _ROMTOP 0xfffffff0 +#endif + +/* The inbuf copy option has been killed... */ + +#define K64 (64 * 1024) + +static unsigned char *zkernel_start = (unsigned char *)ZKERNEL_START; +static unsigned long zkernel_mask = ZKERNEL_MASK; + +static unsigned char *nvram; +static int block_count; +static int block_offset; + +static unsigned int max_block = (_ROMTOP - ZKERNEL_START)/K64; + + +static int init_bytes(void); + +int rom_seek(unsigned long int where) +{ + block_count = where / K64; + block_offset = where - (block_count * K64); + nvram = zkernel_start + (K64 * block_count); + + return(where); +} + +static void fini_bytes(void) +{ + return; +} + +static byte_offset_t rom_read_bytes(int cp, void *vdest, byte_offset_t count) +{ + unsigned char *dest = vdest; + byte_offset_t bytes = 0; + while (bytes < count) { + int length; + if (block_offset == K64) { + block_offset = 0; + block_count++; + nvram+= K64; + } + if (block_count > max_block) { + printk_emerg( "%6d:%s() - overflowed source buffer. max_block = %u\n", + __LINE__, __FUNCTION__, max_block); + return bytes; + } + length = K64 - block_offset; + if (length > (count - bytes)) { + length = count - bytes; + } + if (cp) { + memcpy(dest, nvram + block_offset, length); + } + dest += length; + block_offset += length; + bytes += length; + } + return bytes; +} + +static byte_offset_t skip_bytes(byte_offset_t count) +{ + return rom_read_bytes(0, 0, count); +} + +static byte_offset_t read_bytes(void *vdest, byte_offset_t count) +{ + return rom_read_bytes(1, vdest, count); +} + +static int tag_count=0; +static int tag_blocks=0; +unsigned long tags[32]; + +void rom_load_tag(int tag) +{ + tag_head current; + int i; + +// printk_info("Loading tag %u @ %08x\n", tag, tags[tag]); + + if(tag < tag_count) { + rom_seek( tags[tag] ); + read_bytes(¤t, sizeof(tag_head) ); + +// printk_info("Tag contents: "); +// for(i=0; i<16; i++) +// printk_info("%02x ", ( (char *) ¤t)[i] ); + +// printk_info("\n"); + +// printk_info("TAG block count = %u\n", current.block_count); + + skip_bytes( current.block_count * sizeof(tag_head) ); + } + +} + +int strncmp(char *subject, char *target, int count) +{ + int i; + + for(i=0; iblock_count, (int) ptr); + count = ptr->block_count; + ptr++; + if(count) { + read_bytes(ptr, sizeof(tag_head) * count); + ptr += count; + } + } +} + + +int search_tags(void) +{ + tag_head current; + + + rom_seek(0); + tag_count=0; + tag_blocks=0; + +// printk_info("Searching for %u byte tags\n", sizeof(tag_head) ); + + if(!tag_count) { + while( read_bytes(¤t, sizeof(tag_head)) == sizeof(tag_head) ) { + if(strncmp(current.signature, "$TAG$", 5)) + continue; + + // we found a tag, now look at it + tag_blocks++; + tags[tag_count++] = K64 * block_count + block_offset - sizeof(tag_head); + +// printk_info("Found tag at %08x block_count = %u\n", tags[tag_count-1], current.block_count); + + if(current.block_count >0) { + skip_bytes( current.block_count * sizeof(tag_head) ); + tag_blocks += current.block_count; + } + + } + } + + if(tag_count) { + rom_load_tag(0); + } else + rom_seek(0); + + return(tag_blocks); +} + +static int init_bytes(void) +{ + int i; + + block_count = 0; + block_offset = 0; + nvram = zkernel_start; + + printk_debug("%6d:%s() - zkernel_start:0x%08x " + "zkernel_mask:0x%08x\n", + __LINE__, __FUNCTION__, + zkernel_start, zkernel_mask); + + i = search_tags(); + + printk_info("init_bytes found %u tags\n", i); + + return 0; +} + +struct stream rom_stream = { + .init = init_bytes, + .init_tags = search_tags, + .get_tags = rom_get_tags, + .load_tag = rom_load_tag, + .read = read_bytes, + .skip = skip_bytes, + .fini = fini_bytes, +}; diff --git a/util/baremetal/elfImage.lds b/util/baremetal/elfImage.lds new file mode 100644 index 0000000000..a3f208f355 --- /dev/null +++ b/util/baremetal/elfImage.lds @@ -0,0 +1,71 @@ +/* This setup assumes you have at least a 16M machine + * The problem is that with 2GB of RAM you use nearly 23M + * of memory in the kernel page tables, and since 2.2 doesn't check + * where the initrd is placed before allocating memory this is a + * problem. With a 8M Ramdisk + 23M kernel that is 31M leaving + * little room for things to grow. + * With the limit at 112M (i.e. 0x00700000) we should be o.k.) + * + * If you need to change the amount of assumed memory. + * The uppper.LENGTH needs to change so that + * upper.LENGTH + upper.ORIGIN = MEMORY_SIZE + * and the computation just before ramdisk placing also should + * be corrected, to be: + * . = MEMORY_SIZE - ((ramdisk_data_end - ramdisk_data) + 4095) + * .ramdisk(ALIGN(4096)) + */ + +/* INCLUDE mkelfImage.lds */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +HEAPSIZE = DEFINED(HEAPSIZE) ? HEAPSIZE : 0x8000; + +ENTRY(main) +SECTIONS +{ +/* . = 0x10000 - (elf_note - elf_header); */ + . = 0x1000; + _text = .; /* Text and read-only data */ + .text . : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .rodata (.): { *(.rodata) } + .kstrtab (.): { *(.kstrtab) } + + + . = ALIGN(16); /* Exception table */ + _etext = .; /* End of text section */ + + .data (.): { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + __bss_start = .; /* BSS */ + .bss (.): { + *(.bss) + } + _ebss = .; + _heap = .; + .heap (.): { + . = HEAPSIZE; + } + _eheap = .; + _end = . ; + + _ram_seg = _text; + _eram_seg = _end; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +}