From d1e063beb43e595680c65e3804d1f8ddff53373b Mon Sep 17 00:00:00 2001 From: Guido Guenther Date: Sat, 18 Nov 2006 23:48:07 +0100 Subject: Imported Debian version 0.3.8.8 --- ext2load/.cvsignore | 2 + ext2load/Makefile | 48 ++++ ext2load/arcboot.h | 26 ++ ext2load/conffile.c | 172 +++++++++++ ext2load/ext2io.c | 781 ++++++++++++++++++++++++++++++++++++++++++++++++++ ext2load/ld.script.in | 73 +++++ ext2load/loader.c | 564 ++++++++++++++++++++++++++++++++++++ 7 files changed, 1666 insertions(+) create mode 100644 ext2load/.cvsignore create mode 100644 ext2load/Makefile create mode 100644 ext2load/arcboot.h create mode 100644 ext2load/conffile.c create mode 100644 ext2load/ext2io.c create mode 100644 ext2load/ld.script.in create mode 100644 ext2load/loader.c (limited to 'ext2load') diff --git a/ext2load/.cvsignore b/ext2load/.cvsignore new file mode 100644 index 0000000..3f99037 --- /dev/null +++ b/ext2load/.cvsignore @@ -0,0 +1,2 @@ +ext2load +ld.script diff --git a/ext2load/Makefile b/ext2load/Makefile new file mode 100644 index 0000000..af19224 --- /dev/null +++ b/ext2load/Makefile @@ -0,0 +1,48 @@ +# +# Copyright 1999 Silicon Graphics, Inc. +# 2001-04 Guido Guenther +# + +SUBARCH ?= IP22 + +COMMONDIR = ../common + +E2FSINCLUDEDIR ?= /usr/include/ext2fs +E2FSLIBDIR ?= /usr/lib +EXT2LIB ?= $(E2FSLIBDIR)/libext2fs-nopic.a + +ARCINCLUDEDIR = ../arclib +ARCLIBDIR = ../arclib +ARCLIB = $(ARCLIBDIR)/libarc.a + +OBJECTS = loader.o ext2io.o conffile.o +LIBS = $(EXT2LIB) $(ARCLIB) +TARGETS = ext2load + +CFLAGS = -O2 -I$(COMMONDIR) -I$(ARCINCLUDEDIR) -I$(E2FSINCLUDEDIR) \ + -W -Wall -mno-abicalls -G 0 -fno-pic \ + -DSUBARCH=${SUBARCH} + +# uncomment for debugging +#CFLAGS+=-DDEBUG + +LD = ld +LDFLAGS = -N -T ld.script + +all: $(TARGETS) + +ext2load: $(OBJECTS) $(LIBS) ld.script ../common/subarch.h + rm -f $@ + $(LD) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS) + +ld.script: ld.script.in + $(MAKE) -C ../common SUBARCH=$(SUBARCH) print_loadaddr + LOADADDR=$$(../common/print_loadaddr $(SUBARCH)); \ + OUTPUTFORMAT=$$(../common/print_outputformat $(SUBARCH)); \ + sed -e "s/@@LOADADDR@@/$$LOADADDR/" \ + -e "s/@@OUTPUTFORMAT@@/$$OUTPUTFORMAT/" <$< >$@ + +install: + +clean: + rm -f $(TARGETS) *.a *.o tags ld.script diff --git a/ext2load/arcboot.h b/ext2load/arcboot.h new file mode 100644 index 0000000..e65dc8c --- /dev/null +++ b/ext2load/arcboot.h @@ -0,0 +1,26 @@ +/* + * Copyright 2001-03 Guido Guenther + */ + +#ifndef _ARCBOOT_H +#define _ARCBOOT_H + +#include + +/* loader.c */ +extern CHAR *OSLoadPartition; +extern CHAR *OSLoadFilename; +extern CHAR *OSLoadOptions; + +typedef enum { False = 0, True } Boolean; + +Boolean OpenFile(const char *partition, const char *filename, ext2_file_t* file); +void Fatal(const CHAR * message, ...); + +/* conffile.c */ +CHAR** ReadConfFile(char **partition, const char *filename, char* config); + +/* ext2io.c */ +extern int arc_do_progress; +void print_ext2fs_error(long status); +#endif /* _ARCBOOT_H */ diff --git a/ext2load/conffile.c b/ext2load/conffile.c new file mode 100644 index 0000000..518ccf1 --- /dev/null +++ b/ext2load/conffile.c @@ -0,0 +1,172 @@ +/* + * Copyright 2001-2004 Guido Guenther + * + * load arcboots configuration file and process the arguments + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "arcboot.h" +#include + +#define _PARM_LIMIT 32 + +static char *carray[_PARM_LIMIT+3]; /* 0 is the name, + 1 the boofile, ... + X is OSLoadOptions + X+1 ... _PARM_LIMIT are options given on the + command line */ + +CHAR** GetConfig(char* config, char* name) +{ + char *t, *start, *end; + int i; + + /* Loop on lines */ + while(*config != 0x0) { + + start=config; + + while(*config != 0xa && *config != 0x0) { + /* Delete comments */ + if (*config == '#') + *config=0x0; + config++; + } + + /* Did we stop at the end of a line ? */ + if (*config == 0xa) { + /* Terminate Line */ + *config=0x0; + config++; + } + + /* Skip leading spaces and tabs */ + while(*start == ' ' || *start == '\t') + start++; + + /* If the start of a line is the end - Next line */ + if (*start == 0x0) + continue; + + /* get the end pointer */ + end=&start[strlen(start)-1]; + + /* Delete spaces and tabs at the end of a line */ + while(*end == ' ' || *end == '\t') + *end--=0x0; + + if (strncmp("label=",start,6) == 0) { + /* If we found the right profile or want the first */ + if (carray[0]) + if (((strcmp(carray[0], name) == 0) && (strcmp(name, carray[0]) == 0))) { + return carray; + } + /* Reset image & append */ + carray[1]=carray[2]=0; + carray[0]=&start[6]; + } else if (strncmp("image=",start,6) == 0) { + carray[1]=&start[6]; + } else if (strncmp("append=",start,7) == 0) { + t=&start[7]; + /* Does append start with " */ + if (*t == '"') { + t++; + /* If so - append starts +1 */ + carray[2]=t; + /* Search ending quote */ + while(*t != '"' && *t != 0x0) + t++; + /* And delete */ + if (*t == '"') + *t=0x0; + } else + carray[2]=&start[7]; + t=carray[2]; + i=3; + while(i<_PARM_LIMIT && *t != 0x0) { + t++; + + if (*t == ' ' || *t == '\t') { + *t++=0x0; + if (*t != 0x0) + carray[i++]=t; + } + } + } + } + if (carray[0]) + if ((name == NULL) || + (strcmp(carray[0], name) == 0)) { + return carray; + } + /* Found nothing appropriate: */ + return NULL; +} + +CHAR** ReadConfFile(char** partition, const char *filename, char* label) +{ + ext2_file_t file; + unsigned size, num_read; + errcode_t status; + char *conf_file; + + if(!OpenFile( *partition, filename, &file )){ + /* OSLoadPartition seems to be wrong, but don't give up now */ + int npart,i; + char *part,*spart; + + /* the user wants to boot a file directly out of the filesystem + * don't try to fixup OSLoadPartition for him in this case */ + if(label[0] == '/') { + return False; + } + printf("Can't open configuration file. Trying other partitions\n\r"); + spart = ArcGetEnvironmentVariable("SystemPartition"); + if(! spart ) { + printf("Couldn't get SystemPartition, weird."); + return False; + } + part = strdup(spart); + npart = part[strlen(part)-2] - '0'; + for(i = 0; i < npart; i++) { + part[strlen(part)-2] = '0' + i; +#if DEBUG + printf("Trying %s\n\r", part); +#endif + /* we found it, good */ + if(OpenFile( part, filename, &file )) { + printf("Please adjust OSLoadPartition to %s\n\r", part); + *partition = part; + break; + } + } + if( i == npart ) + return False; + } + + size = ext2fs_file_get_size(file); + conf_file = malloc(size); + if( !conf_file ) { + printf("Can't read configuration file - not enough memory\n\r"); + return False; + } + status = ext2fs_file_read(file,(char*) conf_file, size, &num_read); + if( status ) { + print_ext2fs_error(status); + return False; + } + if( size != num_read ) { + printf("Wanted: %u, got %u bytes of configuration file\n\r", size, num_read); + return False; + } + return GetConfig(conf_file, label); +} diff --git a/ext2load/ext2io.c b/ext2load/ext2io.c new file mode 100644 index 0000000..ccb79b8 --- /dev/null +++ b/ext2load/ext2io.c @@ -0,0 +1,781 @@ +/* + * extio.c + * + * Copyright 1999 Silicon Graphics, Inc. + * 2001-2004 Guido Guenther + * + * Derived from e2fsprogs lib/ext2fs/unix_io.c + * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. + */ +/* #define ARC_IO_ALLOW_WRITE */ + +#include +#include +#include + +#include +#include +#include +#include + +/* + * All About the Cache + * + * Without this cache, reading is horribly slow - it can take 30-60 seconds + * (or even more) to read a kernel. While this is a bootloader and we only + * do it once, that's still a very long time for the user to sit there with + * nothing happening (a progress indicator has also been added). The + * read workload looks like this: reads of the inode and indirection blocks + * interleaved with single-block reads of what are essentially contiguous + * regions of data blocks. As a concrete example, we might see: + * + * 100, 200, 100, 201, 100, 202, 100, 101, 203, 100, 101, 204, ... + * + * Therefore we could simply cache the last 4 or so blocks and get an + * immediate 50-67% speedup with minimal waste. However, it's possible to + * do better - in fact, a lot better. The ARCS calls are so expensive that + * it's worthwhile also to try doing readahead. Unless the filesystem is + * horribly fragmented, this will up our hit ratio to at least 85% or so + * with just 16 cache blocks (in fact if the fs is 0% fragmented, we could + * see 99% hits on the indirection blocks and about 92% on the data blocks, + * or about 96% overall! - even 80% would be adequate however). + * + * We really have two caches: a traditional LRU single-block cache, and a + * readahead multiblock scatter/gather cache. They are however unified to + * speed lookup. CACHE_SIZE is the total number of cacheable blocks, and + * CACHE_SG_MAX is the maximum size of a s/g request. The overall + * implementation is based on the one in unix_io, but has a lot of changes + * to accomodate readahead. + * + * Lookup is straightforward: the cache is fully associative, so we do a + * linear search for the requested block number (it is only possible to + * search for one block at a time). Alloc requests are handled differently. + * We start with the age of the oldest block and work newer until we have + * enough blocks to satisfy the sg request. These blocks have their bufs + * point into the per-cache arc_sg_buf and the number of successfully allocated + * blocks is then returned after invalidating each allocated cache block and + * recording the block it will reference. A later call to fill_sg_blocks + * will perform a single read to fill the entire cache "line." + * + * When any sg cache block is reused, the sg cached data is first copied into + * the per-cache buffer for all sg cache blocks, and then all buffer pointers + * in the sg cache blocks are reset. Note that we only do this for the + * cache blocks we aren't going to immediately reuse. + * + * We don't have any reliable replacement for time(2), so instead we just use + * a monotonically increasing counter incremented by any function that looks + * into the cache. We do risk overflow, but if we do 2**32 cache lookups + * the machine has probably failed to do anything useful anyway. + * + * Important: there are two large simplifying assumptions here: + * (1) The filesystem is universally read-only. There are no other processes + * which can write to this filesystem on this or any remote system. + * (2) We are single-threaded. + * + * As such, we do not have code here to handle locking, coherency, or aliases. + * This is fine for a bootloader but dangerous in other situations. If + * ARC_IO_ALLOW_WRITE is enabled (it's off by default), then on any write will + * the cache will act as write-through, and the entire cache will be + * invalidated. This is the most naive correct implementation. If writing + * becomes an important task, this will need to be revisited; the unix_io + * writeback cache is a good starting point. + */ + +#define CACHE_SIZE 16 +#define CACHE_SG_MAX 12 + +#define CACHE_IS_SG(_cache) ((_cache)->buf != (_cache)->alloc_buf) + +struct arc_cache { + char *buf; + char *alloc_buf; + unsigned long block; + int last_use; + int in_use:1; +}; + +static struct arc_cache *sg_cblocks[CACHE_SG_MAX]; +static unsigned long virtual_time; + +struct arc_private_data { + int magic; + OPENMODE mode; + ULONG fileID; + struct arc_cache cache[CACHE_SIZE]; + char *arc_sg_buf; + unsigned long total_read; + unsigned long seek_pos; + int seek_pos_valid:1; +}; + +static void arc_progress(struct arc_private_data *, unsigned long); + +static errcode_t alloc_cache(io_channel, struct arc_private_data *); +static void free_cache(io_channel, struct arc_private_data *); +static void reset_one_cache(io_channel, struct arc_private_data *, + struct arc_cache *, int); +static void reset_sg_cache(io_channel, struct arc_private_data *, int); +static struct arc_cache *find_cached_block(io_channel, + struct arc_private_data *, unsigned long); +static int alloc_sg_blocks(io_channel, struct arc_private_data *, + unsigned long, int); +static errcode_t fill_sg_blocks(io_channel, struct arc_private_data *, int); + +static errcode_t raw_read_blk(io_channel, struct arc_private_data *, + unsigned long, int, char *); +static void mul64(unsigned long, int, LARGEINTEGER *); +static errcode_t arc_seek(io_channel, unsigned long); + +static errcode_t arc_open(const char *name, int flags, io_channel * channel); +static errcode_t arc_close(io_channel channel); +static errcode_t arc_set_blksize(io_channel channel, int blksize); +static errcode_t arc_read_blk + (io_channel channel, unsigned long block, int count, void *data); +static errcode_t arc_write_blk + (io_channel channel, unsigned long block, int count, const void *data); +static errcode_t arc_flush(io_channel channel); + +static struct struct_io_manager struct_arc_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "ARC PROM I/O Manager", + .open = arc_open, + .close = arc_close, + .set_blksize = arc_set_blksize, + .read_blk = arc_read_blk, + .write_blk = arc_write_blk, + .flush = arc_flush, +}; +io_manager arc_io_manager = &struct_arc_manager; + +int arc_do_progress = 0; + +static int hits, misses; + +static void +arc_progress(struct arc_private_data *priv, unsigned long count) +{ + int hitrate_w = (hits * 1000) / (hits + misses) / 10; + int hitrate_f = (hits * 1000) / (hits + misses) % 10; + + priv->total_read += count; + printf("\r%lx (cache: %u.%u%%)", priv->total_read, hitrate_w, + hitrate_f); + +#ifdef DEBUG + if ((hits + misses) % 100 == 0) + printf("hits: %u misses %u\n\r", hits, misses); +#endif +} + +/* + * Allocates memory for a single file's cache. + */ +static errcode_t +alloc_cache(io_channel channel, struct arc_private_data *priv) +{ + errcode_t status; + struct arc_cache *cache; + int i; + + for(i = 0, cache = priv->cache; i < CACHE_SIZE; i++, cache++) { + memset(cache, 0, sizeof (struct arc_cache)); + if ((status = ext2fs_get_mem(channel->block_size, + (void **) &cache->alloc_buf)) != 0) + return (status); + cache->buf = cache->alloc_buf; + } + + return (ext2fs_get_mem(channel->block_size * CACHE_SG_MAX, + (void **) &priv->arc_sg_buf)); +} + +/* + * Frees all memory associated with a single file's cache. + */ +static void +free_cache(io_channel channel, struct arc_private_data *priv) +{ + struct arc_cache *cache; + int i; + + for (i = 0, cache = priv->cache; i < CACHE_SIZE; i++, cache++) { + if (cache->alloc_buf) + ext2fs_free_mem((void **) &cache->alloc_buf); + memset(cache, 0, sizeof (struct arc_cache)); + } + + ext2fs_free_mem((void **) &priv->arc_sg_buf); +} + +/* + * Resets a cache block. If the cache block is a valid sg block, the contents + * will be copied from the sg buffer into the private buffer. For all blocks, + * the private buffer will be current. If discard is set, the block will + * also be invalidated. + */ +static void +reset_one_cache(io_channel channel, struct arc_private_data *priv, + struct arc_cache *cache, int discard) +{ + if (CACHE_IS_SG(cache) && discard == 0 && cache->in_use != 0) + memcpy(cache->alloc_buf, cache->buf, channel->block_size); + + if (discard != 0) + cache->in_use = 0; + + cache->buf = cache->alloc_buf; +} + +/* + * Resets all sg cache blocks. If a block is in the first + * alloc_count entries in sg_cblocks (meaning it has been allocated for + * immediate reuse) then also discards the contents. + */ +static void +reset_sg_cache(io_channel channel, struct arc_private_data *priv, + int alloc_count) +{ + struct arc_cache *cache; + int i, j, discard; + + for (i = 0, cache = priv->cache; i < CACHE_SIZE; i++, cache++) { + if (CACHE_IS_SG(cache)) { + discard = 0; + for (j = 0; j < alloc_count; j++) { + if (sg_cblocks[j] == cache) { + discard = 1; + break; + } + } + reset_one_cache(channel, priv, cache, discard); + } + } +} + +/* + * Read count blocks starting at block directly from channel into buf, which + * must be of size >= channel->block_size * count. No attempt is made to + * use or update any caches; however, if the last ARC read left the file + * pointer at the requested block, we avoid seeking. + */ +static errcode_t +raw_read_blk(io_channel channel, struct arc_private_data *priv, + unsigned long block, int count, char *buf) +{ + errcode_t status; + size_t length = 0; + + if (priv->seek_pos_valid == 0 || priv->seek_pos != block) { + status = arc_seek(channel, block); + priv->seek_pos = block + count; + } else { + status = 0; + } + /* If something fails, priv->seek_pos is bogus. */ + priv->seek_pos_valid = 0; + if (status == 0) { + length = (count < 0) ? -count : count * channel->block_size; + ULONG nread = 0; + + status = ArcRead(priv->fileID, buf, length, &nread); + if ((nread > 0) && (nread < length)) { + status = EXT2_ET_SHORT_READ; + memset(((char *) buf) + nread, 0, length - nread); + } + if (status != 0 && channel->read_error != NULL) { + status = (channel->read_error) + (channel, block, count, buf, length, nread, status); + } + } else { + status = EXT2_ET_BAD_BLOCK_NUM; + } + + if (status == 0) { + priv->seek_pos_valid = 1; + if (arc_do_progress != 0) + arc_progress(priv, (unsigned long) length); + } + + return (status); +} + +/* + * For the file associated with channel and priv, find block in the cache. + * In the case of a miss, return NULL. The last access "time" will be + * updated to refresh the LRU. Note that this is much different from the + * unix_io.c version of the same function; because our allocation step is + * far more complex to cover readahead, it is dealt with in alloc_sg_blocks. + */ +static struct arc_cache * +find_cached_block(io_channel channel, struct arc_private_data *priv, + unsigned long block) +{ + struct arc_cache *cache; + int i; + + ++virtual_time; + + for (i = 0, cache = priv->cache; i < CACHE_SIZE; i++, cache++) + if (cache->block == block) { + cache->last_use = virtual_time; + ++hits; + return (cache); + } + + ++misses; + return (NULL); +} + +/* + * Allocate a set of cache blocks whose buffers are contiguous. The cache + * blocks are found in sg_cblocks. The number of allocated blocks is the + * return value; a return value of 0 indicates an error. The cache blocks + * are not filled here; use fill_sg_blocks for that. + */ +static int +alloc_sg_blocks(io_channel channel, struct arc_private_data *priv, + unsigned long block, int count) +{ + struct arc_cache *cache, *oldest_cache; + int i, unused_count, age_mark; + + if (count > CACHE_SG_MAX) + count = CACHE_SG_MAX; + + ++virtual_time; + oldest_cache = NULL; + unused_count = 0; + + /* First use unused blocks, if any are available. */ + for (i = 0, cache = priv->cache; i < CACHE_SIZE && unused_count < count; + i++, cache++) { + if (cache->in_use == 0) { + sg_cblocks[unused_count++] = cache; + continue; + } + if (!oldest_cache || cache->last_use < oldest_cache->last_use) + oldest_cache = cache; + } + + /* If we don't have enough blocks yet, evict the LRUs. */ + if (unused_count < count) { + for (age_mark = oldest_cache->last_use; + unused_count < count && age_mark <= virtual_time; + age_mark++) { + for (i = 0, cache = priv->cache; + i < CACHE_SIZE && unused_count < count; + i++, cache++) { + if (cache->in_use == 0) + continue; + if (cache->last_use == age_mark) + sg_cblocks[unused_count++] = cache; + } + } + } + + /* + * At this point it's impossible not to have count blocks. However, + * even if we somehow don't, it's not fatal - perhaps someone + * decided to use some future lru timestamp to lock an entry or + * something. In this case, we just continue on, and make sure the + * caller knows we didn't allocate as much as was requested. + */ + + /* + * Now we set up the cache blocks. Their buffers need to be + * set to the sg buffer and they must be marked invalid (we will + * mark them valid once fill_sg_blocks fills them). + */ + reset_sg_cache(channel, priv, count); + + for (i = 0; i < count; i++) { + cache = sg_cblocks[i]; + cache->in_use = 0; + cache->block = block + i; + cache->buf = priv->arc_sg_buf + i * channel->block_size; + } + + return (count); +} + +/* + * Fill the first count cache blocks in sg_cblocks with contiguous data from + * the file. The block numbers are already stored in the cache metadata + * by a mandatory previous call to alloc_sg_blocks. This can fail if there + * is an i/o error. + */ +static errcode_t +fill_sg_blocks(io_channel channel, struct arc_private_data *priv, int count) +{ + errcode_t status; + int i; + + status = raw_read_blk(channel, priv, sg_cblocks[0]->block, count, + priv->arc_sg_buf); + + /* + * XXX Handle short read here: it may be that we've reached EOF and + * can mark some of the blocks valid. + */ + if (status == 0) { + for (i = 0; i < count; i++) { + sg_cblocks[i]->in_use = 1; + sg_cblocks[i]->last_use = virtual_time; + } + } + + return (status); +} + +/* + * Mark the entire contents of the cache invalid, and reset any sg blocks + * to private buffers. + */ +static void +cache_invalidate(io_channel channel, struct arc_private_data *priv) +{ + struct arc_cache *cache; + int i; + + for (i = 0, cache = priv->cache; i < CACHE_SIZE; i++, cache++) + reset_one_cache(channel, priv, cache, 1); +} + +static errcode_t +arc_open(const char *name, int flags, io_channel * pchannel) +{ + io_channel channel = NULL; + struct arc_private_data *priv; + errcode_t status; + + if (name == NULL) + return EXT2_ET_BAD_DEVICE_NAME; + + status = + ext2fs_get_mem(sizeof(struct struct_io_channel), + (void **) &channel); + + if (status == 0) { + memset(channel, 0, sizeof(struct struct_io_channel)); + + channel->name = NULL; + channel->private_data = NULL; + channel->magic = EXT2_ET_MAGIC_IO_CHANNEL; + channel->manager = arc_io_manager; + channel->block_size = 1024; + channel->read_error = NULL; + channel->write_error = NULL; + channel->refcount = 1; + + status = + ext2fs_get_mem(strlen(name) + 1, + (void **) &channel->name); + if (status == 0) { + strcpy(channel->name, name); + + status = + ext2fs_get_mem(sizeof(struct arc_private_data), + (void **) &priv); + if (status == 0) { + memset(priv, 0, + sizeof(struct arc_private_data)); + channel->private_data = priv; + priv->magic = EXT2_ET_BAD_MAGIC; + priv->mode = + (flags & IO_FLAG_RW) ? OpenReadWrite : + OpenReadOnly; + status = + ArcOpen((char *) name, priv->mode, + &priv->fileID); + if( status ) { + status = EXT2_ET_BAD_DEVICE_NAME; + } + } + } + } + + if (status == 0) + status = alloc_cache(channel, priv); + + if (status == 0) { + *pchannel = channel; + } else if (channel != NULL) { + if (channel->name != NULL) + ext2fs_free_mem((void **) &channel->name); + if (channel->private_data != NULL) + ext2fs_free_mem((void **) &channel->private_data); + ext2fs_free_mem((void **) &channel); + } + return status; +} + + +static errcode_t arc_close(io_channel channel) +{ + struct arc_private_data *priv; + errcode_t status = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + priv = (struct arc_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(priv, EXT2_ET_BAD_MAGIC); + + if (--channel->refcount == 0) { + status = ArcClose(priv->fileID); + free_cache(channel, priv); + if (channel->name != NULL) + ext2fs_free_mem((void **) &channel->name); + if (channel->private_data != NULL) + ext2fs_free_mem((void **) &channel->private_data); + ext2fs_free_mem((void **) &channel); + } + + return status; +} + + +static errcode_t arc_set_blksize(io_channel channel, int blksize) +{ + struct arc_private_data *priv; + errcode_t status; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + priv = (struct arc_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(priv, EXT2_ET_BAD_MAGIC); + + if (channel->block_size != blksize) { + channel->block_size = blksize; + free_cache(channel, priv); + if ((status = alloc_cache(channel, priv)) != 0) + return (status); + } + return 0; +} + +static void +mul64(unsigned long block, int blocksize, LARGEINTEGER *result) +{ + ULONG m1l = block & 0x0FFFF, m1h = (block >> 16) & 0x0FFFF; + ULONG m2l = blocksize & 0x0FFFF, m2h = (blocksize >> 16) & 0x0FFFF; + ULONG i1 = m1l * m2h, i2 = m1h * m2l; + + result->HighPart = + (m1h * m2h) + ((i1 >> 16) & 0x0FFFF) + ((i2 >> 16) & 0x0FFFF); + i1 = + (i1 & 0x0FFFF) + (i2 & 0x0FFFF) + + (((m1l * m2l) >> 16) & 0x0FFFF); + result->LowPart = ((i1 & 0x0FFFF) << 16) + ((m1l * m2l) & 0x0FFFF); + result->HighPart += (i1 >> 16) & 0x0FFFF; +} + +static errcode_t +arc_seek(io_channel channel, unsigned long block) +{ + struct arc_private_data *priv; + LARGEINTEGER position; + + priv = (struct arc_private_data *) channel->private_data; + mul64(block, channel->block_size, &position); + return ArcSeek(priv->fileID, &position, SeekAbsolute); +} + +/* + * Perform a cacheable read. First, the cache will be checked for an + * existing copy of the blocks. If present, they are copied into buf. + * Otherwise, we set up and execute a readahead, then copy the results into + * buf. The unix_io way is a little nicer; since it doesn't have readahead + * it knows that buf is always big enough in multicount scenarios and thus + * dispenses with the extra memcpy. There is an opportunity to improve this. + */ +static errcode_t +arc_read_blk(io_channel channel, unsigned long block, int count, void *buf) +{ + struct arc_private_data *priv; + errcode_t status = 0; + struct arc_cache *cache; + char *cbuf = (char *) buf; + int cb_alloc; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + priv = (struct arc_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(priv, EXT2_ET_BAD_MAGIC); + +#ifdef DEBUG + printf("req %lu id %lu count %u\n\r", block, priv->fileID, count); +#endif + + /* Odd-sized reads can't be cached. */ + if (count < 0) + status = raw_read_blk(channel, priv, block, count, cbuf); + + while (count > 0) { + if ((cache = find_cached_block(channel, priv, block)) == NULL) + break; +#ifdef DEBUG + printf("Cache hit on block %lu\n\r", block); +#endif + memcpy(cbuf, cache->buf, channel->block_size); + count--; + block++; + cbuf += channel->block_size; + } + + /* + * Cache miss. Although it could be that there's just a hole + * in the cache, it's far more likely and easier to handle + * that we've reached the end of a readahead blockset. Thus + * we just stop looking in the cache for the rest until after + * we do a readahead. We could try to put in some + * heuristics here to avoid trashing the cache unnecessarily + * for reads we expect are not part of a sequential set. + */ + while (count > 0) { +#ifdef DEBUG + printf("Cache miss on block %lu (readahead %u)\n\r", + block, CACHE_SG_MAX); +#endif + if ((cb_alloc = alloc_sg_blocks(channel, priv, block, + CACHE_SG_MAX)) == 0) { +#ifdef DEBUG + printf("%s\n\r", "Cache error: can't alloc any blocks"); +#endif + /* Cache is broken, so do the raw read. */ + cache_invalidate(channel, priv); + status = raw_read_blk(channel, priv, block, count, + cbuf); + break; + } + + if ((status = fill_sg_blocks(channel, priv, cb_alloc)) != 0) { +#ifdef DEBUG + printf("Cache error (status %lu at block %lu(%u)\n\r", + (unsigned long) status, block, count); +#endif + /* Cache is broken, so do the raw read. */ + cache_invalidate(channel, priv); + status = raw_read_blk(channel, priv, block, count, + cbuf); + break; + } + + if (cb_alloc >= count) { + memcpy(cbuf, priv->arc_sg_buf, + count * channel->block_size); + return (0); + } + + memcpy(cbuf, priv->arc_sg_buf, cb_alloc * channel->block_size); + count -= cb_alloc; + block += cb_alloc; + cbuf += cb_alloc * channel->block_size; + } + + return (status); +} + +static errcode_t +arc_write_blk (io_channel channel, unsigned long block, int count, + const void *buf) { + struct arc_private_data *priv; + errcode_t status; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + priv = (struct arc_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(priv, EXT2_ET_BAD_MAGIC); + + status = arc_seek(channel, block); +#ifdef ARC_IO_ALLOW_WRITE + cache_invalidate(channel, priv); + priv->seek_pos_valid = 0; + if (status == 0) { + size_t length = + (count < 0) ? -count : count * channel->block_size; + ULONG nwritten = 0; + + status = + ArcWrite(priv->fileID, (void *) buf, length, + &nwritten); + if ((nwritten > 0) && (nwritten < length)) + status = EXT2_ET_SHORT_WRITE; + if ((status != ESUCCESS) && (channel->write_error != NULL)) { + status = (channel->write_error) + (channel, block, count, buf, length, nwritten, status); + } + } +#endif /* ARC_IO_ALLOW_WRITE */ + + return status; +} + + +static errcode_t arc_flush(io_channel channel) +{ + struct arc_private_data *priv; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + priv = (struct arc_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(priv, EXT2_ET_BAD_MAGIC); + + return 0; +} + + +/* Hack in some stuff to make ext2fs library work */ +time_t time(time_t *t) +{ + return 0; +} + +/* We can get away with those two because libext2fs uses them only in + fileio.c for file size calculations, and the bootloader needs not + to read files >2GB (famous last words...). */ +unsigned long long __udivdi3(unsigned long long numerator, + unsigned long long denominator) +{ +// printf("ARGH! %s\n", __FUNCTION__); + return ((unsigned int)(numerator)) / ((unsigned int)(denominator)); +} + +unsigned long long __umoddi3(unsigned long long val, unsigned long long mod) +{ +// printf("ARGH! %s\n", __FUNCTION__); + return ((unsigned int)(val)) % ((unsigned int)(mod)); +} + +struct et_list { + struct et_list *next; + const struct error_table *table; +}; +struct et_list *_et_list = NULL; + +void com_err(const char *whoami, long error, const char *format, ...) +{ + printf("com_err called with %lu\n", error); +} + +const char *ext2fs_strerror(long error) +{ + struct et_list *list = _et_list; + + while (list != NULL) { + if ((error >= list->table->base) + && (error < (list->table->base + list->table->n_msgs))) { + return list->table->msgs[error - + list->table->base]; + } + + list = list->next; + } + return NULL; +} + +void print_ext2fs_error(long error) +{ + const char* msg; + + msg = ext2fs_strerror(error); + if(msg) + printf("ext2fs - %s\n\r", msg); + else + printf("ext2fs - unknown error (%lu)\n\r", error); + +} diff --git a/ext2load/ld.script.in b/ext2load/ld.script.in new file mode 100644 index 0000000..8c5bb3f --- /dev/null +++ b/ext2load/ld.script.in @@ -0,0 +1,73 @@ +OUTPUT_FORMAT("@@OUTPUTFORMAT@@") +OUTPUT_ARCH(mips) +ENTRY(_start) +SECTIONS +{ + /* XXX: place the loader after the kernel */ + . = @@LOADADDR@@; + + /* Read-only sections, merged into text segment: */ + .text : { + _ftext = .; + *(.text) + *(.rodata*) + } =0 + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(16); + + .data : { + _fdata = .; + *(.data) + CONSTRUCTORS + } + _gp = ALIGN(16) + 0x7ff0; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + PROVIDE (edata = .); + + __bss_start = .; + .sbss : { + *(.sbss) + *(.scommon) + } + .bss : { + _fbss = .; + *(.dynbss) + *(.bss .bss.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + __bss_stop = .; + _end = .; + PROVIDE (end = .); + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + *(.stab) + *(.stabstr) + *(.pdr) + *(.note) + *(.reginfo) + *(.options) + *(.MIPS.options) + *(.debug*) + *(.line) + *(.mdebug*) + *(.comment*) + *(.gptab*) + *(.note) + } +} diff --git a/ext2load/loader.c b/ext2load/loader.c new file mode 100644 index 0000000..45d1988 --- /dev/null +++ b/ext2load/loader.c @@ -0,0 +1,564 @@ +/* + * Copyright 1999, 2001 Silicon Graphics, Inc. + * Copyright 2001 Ralf Baechle + * 2001-04 Guido Guenther + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "arcboot.h" + +#include + +#define KSEG0ADDR(addr) (((addr) & 0x1fffffff) | 0x80000000) + +#define ANSI_CLEAR "\033[2J" +#define CONF_FILE "/etc/arcboot.conf" + +CHAR *OSLoadPartition = NULL; +CHAR *OSLoadFilename = NULL; +CHAR *OSLoadOptions = NULL; +static int is64=0; + + +typedef union { + unsigned char e_ident[EI_NIDENT]; + Elf32_Ehdr header32; + Elf64_Ehdr header64; +} Elf_Ehdr; + +static void Wait(const char *prompt) +{ + int ch; + + if (prompt != NULL) + puts(prompt); + + do { + ch = getchar(); + } while ((ch != EOF) && (((char) ch) != ' ')); +} + + +void Fatal(const CHAR * message, ...) +{ + va_list ap; + + if (message != NULL) { + printf("FATAL ERROR: "); + va_start(ap, message); + vprintf(message, ap); + va_end(ap); + } + + Wait("\n\r--- Press to enter ARC interactive mode ---"); + ArcEnterInteractiveMode(); +} + + +void InitMalloc(void) +{ + MEMORYDESCRIPTOR *current = NULL; + ULONG stack = (ULONG) ¤t; +#ifdef DEBUG + printf("stack starts at: 0x%lx\n\r", stack); +#endif + + current = ArcGetMemoryDescriptor(current); + if(! current ) { + Fatal("Can't find any valid memory descriptors!\n\r"); + } + while (current != NULL) { + /* + * The spec says we should have an adjacent FreeContiguous + * memory area that includes our stack. It would be much + * easier to just look for that and give it to malloc, but + * the Indy only shows FreeMemory areas, no FreeContiguous. + * Oh well. + */ + if (current->Type == FreeMemory) { + ULONG start = KSEG0ADDR(current->BasePage * PAGE_SIZE); + ULONG end = + start + (current->PageCount * PAGE_SIZE); +#if DEBUG + printf("Free Memory(%u) segment found at (0x%lx,0x%lx).\n\r", + current->Type, start, end); +#endif + + /* Leave some space for our stack */ + if ((stack >= start) && (stack < end)) + end = + (stack - + (STACK_PAGES * + PAGE_SIZE)) & ~(PAGE_SIZE - 1); + /* Don't use memory from reserved region */ + if ((start >= kernel_load[SUBARCH].base ) + && (start < (kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved ))) + start = kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved; + if ((end > kernel_load[SUBARCH].base) + && (end <= (kernel_load[SUBARCH].base + + kernel_load[SUBARCH].reserved ))) + end = kernel_load[SUBARCH].base; + if (end > start) { +#ifdef DEBUG + printf("Adding %lu bytes at 0x%lx to the list of available memory\n\r", + end-start, start); +#endif + arclib_malloc_add(start, end - start); + } + } + current = ArcGetMemoryDescriptor(current); + } +} + +int isEnvVar(const char* arg) +{ + unsigned int i; + + for (i = 0; i < NENTS(env_vars); i++) { + if(strncmp( env_vars[i], arg, strlen(env_vars[i]) ) == 0) + return 1; + } + return 0; +} + +int ProcessArguments(LONG argc, CHAR * argv[]) +{ + LONG arg; + CHAR *equals; + size_t len; + + /* save some things we need later */ + for (arg = 1; arg < argc; arg++) { + equals = strchr(argv[arg], '='); + if (equals != NULL) { + len = equals - argv[arg]; + if (strncmp(argv[arg], "OSLoadPartition", len) == 0) + OSLoadPartition = equals + 1; + if (strncmp(argv[arg], "OSLoadFilename", len) == 0) + OSLoadFilename = equals + 1; + if (strncmp(argv[arg], "OSLoadOptions", len) == 0) { + /* Copy options to local memory to avoid overwrite later */ + OSLoadOptions = strdup(equals + 1); + if (OSLoadOptions == NULL) + Fatal ("Cannot allocate memory for options string\n\r"); + } + } + } + /* + * in case the user typed "boot a b c" the argv looks like: + * scsi(0)..(8)/arcboot a b c OSLoadPartition=.. SystemPartition=.. + * argv: `0 `-1`-2`-3`-4 `-5 + * we're interested in a,b,c so scan the command line and check for + * each argument if it is an environment variable. We're using a fixed + * list instead of ArcGetEnvironmentVariable since e.g. the prom sets + * "OSLoadOptions=auto" on reboot but + * EnvironmentVariable("OSLoadOptions") == NULL + */ + for( arg = 1; arg < argc; arg++ ) { + if( isEnvVar(argv[arg])) { + return (arg-1); +#ifdef DEBUG + } else { + printf("%s is not an envVar\n\r", argv[arg]); +#endif + } + } + return 0; +} + +int LoadProgramSegments32(ext2_file_t file, Elf_Ehdr * header, void *segments) +{ + int idx; + int loaded = 0; + Elf32_Phdr* segment=(Elf32_Phdr*)segments; + errcode_t status; + size_t size; + + printf("Loading 32-bit executable\n\r"); + + for (idx = 0; idx < header->header32.e_phnum; idx++) { + if (segment->p_type == PT_LOAD) { + printf + ("Loading program segment %u at 0x%x, offset=0x%x, size = 0x%x\n\r", + idx + 1, KSEG0ADDR(segment->p_vaddr), + segment->p_offset, segment->p_filesz); + + status = + ext2fs_file_lseek(file, segment->p_offset, + EXT2_SEEK_SET, NULL); + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot seek to program segment\n\r"); + } + + arc_do_progress = 1; + status = ext2fs_file_read(file, + (void *) (KSEG0ADDR( + segment->p_vaddr)), + segment->p_filesz, NULL); + printf("\n\n\r"); /* Clear progress */ + arc_do_progress = 0; + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot read program segment\n\r"); + } + + size = segment->p_memsz - segment->p_filesz; + if (size > 0) { + printf + ("Zeroing memory at 0x%x, size = 0x%x\n\r", + (KSEG0ADDR(segment->p_vaddr + + segment->p_filesz)), size); + memset((void *) + (KSEG0ADDR(segment-> + p_vaddr + segment->p_filesz)), 0, size); + } + + loaded = 1; + } + + segment = + (Elf32_Phdr *) (((char *) segment) + + header->header32.e_phentsize); + } + + return loaded; +} + +int LoadProgramSegments64(ext2_file_t file, Elf_Ehdr * header, void *segments) +{ + int idx; + int loaded = 0; + Elf64_Phdr* segment=(Elf64_Phdr*)segments; + errcode_t status; + size_t size; + + is64=1; + printf("Loading 64-bit executable\n\r"); + + for (idx = 0; idx < header->header64.e_phnum; idx++) { + if (segment->p_type == PT_LOAD) { + printf ("Loading program segment %u at 0x%x, " + "offset=0x%lx %lx, size = 0x%lx %lx\n\r", + idx + 1, + (int)KSEG0ADDR(segment->p_vaddr), + (long)(segment->p_offset>>32), + (long)(segment->p_offset&0xffffffff), + (long)(segment->p_filesz>>32), + (long)(segment->p_filesz&0xffffffff)); + + status = + ext2fs_file_lseek(file, segment->p_offset, + EXT2_SEEK_SET, NULL); + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot seek to program segment\n\r"); + } + + arc_do_progress = 1; + status = ext2fs_file_read(file, + (void *) (KSEG0ADDR( + segment->p_vaddr)), + segment->p_filesz, NULL); + arc_do_progress = 0; + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot read program segment\n\r"); + } + + size = segment->p_memsz - segment->p_filesz; + if (size > 0) { + printf + ("Zeroing memory at 0x%lx, size = 0x%lx\n\r", + (KSEG0ADDR(segment->p_vaddr + + segment->p_filesz)), size); + memset((void *) + (KSEG0ADDR(segment-> + p_vaddr + segment->p_filesz)), 0, size); + } + + loaded = 1; + } + + segment = (Elf64_Phdr *) (((char *) segment) + + header->header64.e_phentsize); + } + + return loaded; +} + +void LoadProgramSegments(ext2_file_t file, Elf_Ehdr * header) +{ + int idx; + Boolean loaded = False; + void *segments; + size_t size; + errcode_t status; + + if (header->e_ident[EI_CLASS] == ELFCLASS32) + size = (size_t) (header->header32.e_phentsize * + header->header32.e_phnum); + else + size = (size_t) (header->header64.e_phentsize * + header->header64.e_phnum); + + if (size <= 0) + Fatal("No program segments\n\r"); + + segments = malloc(size); + if (segments == NULL) + Fatal("Cannot allocate memory for segment headers\n\r"); + else + printf("Allocated 0x%x bytes for segments\n\r",size); + + if (header->e_ident[EI_CLASS] == ELFCLASS32) { + status = ext2fs_file_lseek(file, + (ext2_off_t) header->header32.e_phoff, + EXT2_SEEK_SET, NULL); + } else { + status = ext2fs_file_lseek(file, + (ext2_off_t) header->header64.e_phoff, + EXT2_SEEK_SET, NULL); + } + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot seek to program segment headers\n\r"); + } + + status = ext2fs_file_read(file, segments, size, NULL); + if (status != 0) { + print_ext2fs_error(status); + Fatal("Cannot read program segment headers\n\r"); + } + + if(header->e_ident[EI_CLASS] == ELFCLASS32) + loaded = LoadProgramSegments32(file, header, segments); + else + loaded = LoadProgramSegments64(file, header, segments); + + if (!loaded) + Fatal("No loadable program segments found\n\r"); + + free(segments); +} + + +Elf64_Addr LoadKernelFile(ext2_file_t file) +{ + Elf_Ehdr header; + Elf64_Addr entry; + errcode_t status; + + status = + ext2fs_file_read(file, (void *) &header, sizeof(header), NULL); + if (status != 0) { + print_ext2fs_error(status); + Fatal("Can't read file header\n\r"); + } + + if (memcmp(&(header.e_ident[EI_MAG0]), ELFMAG, SELFMAG) != 0) + Fatal("Not an ELF file\n\r"); + + if (header.e_ident[EI_CLASS] != ELFCLASS32 && + header.e_ident[EI_CLASS] != ELFCLASS64) + Fatal("Not a 32-bit or 64-bit file\n\r"); + + if (header.e_ident[EI_DATA] != ELFDATA2MSB) + Fatal("Not a big-endian file\n\r"); + + if (header.e_ident[EI_VERSION] != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + + if (header.e_ident[EI_CLASS]==ELFCLASS32) { + if (header.header32.e_type != ET_EXEC) + Fatal("Not an executable file\n\r"); + + if (header.header32.e_machine != EM_MIPS) + Fatal("Unsupported machine type\n\r"); + + if (header.header32.e_version != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + + entry = (Elf64_Addr) header.header32.e_entry; + } else { + if (header.header64.e_type != ET_EXEC) + Fatal("Not an executable file\n\r"); + + if (header.header64.e_machine != EM_MIPS) + Fatal("Unsupported machine type\n\r"); + + if (header.header64.e_version != EV_CURRENT) + Fatal("Wrong ELF version\n\r"); + + entry = header.header64.e_entry; + } + + LoadProgramSegments(file, &header); + + return entry; +} + + +Boolean OpenFile(const char *partition, const char *filename, ext2_file_t* file) +{ + extern io_manager arc_io_manager; + ext2_filsys fs; + ext2_ino_t file_inode; + errcode_t status; + + initialize_ext2_error_table(); + + status = ext2fs_open(partition, 0, 0, 0, arc_io_manager, &fs); + if (status != 0) { + print_ext2fs_error(status); + return False; + } + + status = ext2fs_namei_follow + (fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename, &file_inode); + if (status != 0) { + print_ext2fs_error(status); + return False; + } + + status = ext2fs_file_open(fs, file_inode, 0, file); + if (status != 0) { + print_ext2fs_error(status); + return False; + } + return True; +} + +Elf64_Addr LoadKernel(const char *partition, const char *filename) +{ + ext2_file_t file; + + if(!OpenFile( partition, filename, &file )) + Fatal("Can't load kernel!\n\r"); + return LoadKernelFile(file); +} + +void printCmdLine(int argc, CHAR *argv[]) +{ + int i; + + for(i = 0; i < argc; i++ ) + printf("%u: %s\n\r", i, argv[i]); +} + +void _start64(LONG argc, CHAR * argv[], CHAR * envp[], + unsigned long long *addr) +{ + __asm__ __volatile__( + ".set push\n" + "\t.set mips3\n" + "\t.set noreorder\n" + "\t.set noat\n" + "\tld $1, 0($7)\n" + "\tjr $1\n" + "\t nop\n" + "\t.set pop"); +} + +void _start(LONG argc, CHAR *argv[], CHAR *envp[]) +{ + CHAR** nargv; + CHAR** params; + int nargc, nopt; + + Elf32_Addr kernel_entry32; + Elf64_Addr kernel_entry64; + + /* Print identification */ + printf(ANSI_CLEAR "\n\rarcsboot: ARCS Linux ext2fs loader " + __ARCSBOOT_VERSION__ "\n\n\r"); + + InitMalloc(); + + nopt = ProcessArguments(argc, argv); + +#if DEBUG + printf("Command line: \n\r"); + printCmdLine(argc, argv); +#endif + if (nopt) { /* the user typed s.th. on the commandline */ + OSLoadFilename = argv[1]; + } + + /* Fall back to "Linux" as default name. */ + if (OSLoadFilename == NULL) + OSLoadFilename = "Linux"; + + if (OSLoadPartition == NULL) + Fatal("Invalid load partition\n\r"); +#if DEBUG + printf("OSLoadPartition: %s\n\r", OSLoadPartition); + printf("OSLoadFilename: %s\n\r", OSLoadFilename); +#endif + /* + * XXX: let's play stupid for now: assume /etc/arcboot.conf + * is on OSLoadPartition + */ + if( !(params = ReadConfFile(&OSLoadPartition, CONF_FILE, OSLoadFilename))) { + printf("Couldn't find label: %s in %s.\n\r", OSLoadFilename, CONF_FILE); + printf("Will try to boot %s%s.\n\r", OSLoadPartition, OSLoadFilename); + nargc = argc; + nargv = argv; + } else { + int i; + OSLoadFilename = params[1]; + nargv = ¶ms[1]; /* nargv[0] is the labels name */ + for( nargc=0; nargv[nargc]; nargc++); /* count nargv argumnts */ + if(OSLoadOptions != NULL) { /* append OSLoadOptions if present */ + nargv[nargc] = OSLoadOptions; + nargc++; + } + /* append command line arguments */ + for(i = 2; i <= nopt; i++) { + nargv[nargc] = argv[i]; + nargc++; + } + } + printf("Loading %s from %s\n\r",(params) ? params[0] : OSLoadFilename, OSLoadPartition); + kernel_entry64 = LoadKernel(OSLoadPartition, OSLoadFilename); + kernel_entry32 = (Elf32_Addr) kernel_entry64; +#if DEBUG + printf("Command line after config file: \n\r"); + printCmdLine(nargc, nargv); + printf("Kernel entry: 0x%lx %lx\n\r", + (long)(kernel_entry64>>32),(long)(kernel_entry64&0xffffffff)); + Wait("\n\r--- Debug: press to boot kernel ---"); +#endif + if( kernel_entry64 ) { + if(is64==0){ + printf("Starting ELF32 kernel\n\r"); + ArcFlushAllCaches(); + ((void (*)(int argc, CHAR * argv[], CHAR * envp[])) + kernel_entry32)(nargc ,nargv, envp); + } else { + printf("Starting ELF64 kernel\n\r"); + ArcFlushAllCaches(); + _start64(nargc, nargv, envp, &kernel_entry64); + } + } else { + printf("Invalid kernel entry NULL\n\r"); + } + + /* Not likely to get back here in a functional state, but what the heck */ + Wait("\n\r--- Press to restart ---"); + ArcRestart(); +} -- cgit v1.2.3