diff -ur yaboot-1.3.14.orig/include/fs.h yaboot-1.3.14/include/fs.h --- yaboot-1.3.14.orig/include/fs.h 2010-08-03 15:28:29.886806113 -0500 +++ yaboot-1.3.14/include/fs.h 2010-08-03 15:47:40.274304966 -0500 @@ -44,6 +44,8 @@ unsigned int newpos); int (*close)( struct boot_file_t* file); + + unsigned int (*ino_size)(struct boot_file_t *file); }; extern const struct fs_t *fs_of; diff -ur yaboot-1.3.14.orig/include/prom.h yaboot-1.3.14/include/prom.h --- yaboot-1.3.14.orig/include/prom.h 2010-08-03 15:28:29.916805885 -0500 +++ yaboot-1.3.14/include/prom.h 2010-08-03 15:47:40.274304966 -0500 @@ -37,7 +37,7 @@ #define PROM_INVALID_HANDLE ((prom_handle)-1UL) #define BOOTDEVSZ (2048) /* iscsi args can be in excess of 1040 bytes */ #define TOK_ISCSI "iscsi" -#define PROM_CLAIM_MAX_ADDR 0x8000000 +#define PROM_CLAIM_MAX_ADDR 0x10000000 #define BOOTLASTSZ 1024 #define FW_NBR_REBOOTSZ 4 #define TOK_IPV6 "ipv6" @@ -89,6 +89,7 @@ /* memory */ void *prom_claim_chunk(void *virt, unsigned int size, unsigned int align); +void *prom_claim_chunk_top(unsigned int size, unsigned int align); void *prom_claim (void *virt, unsigned int size, unsigned int align); void prom_release(void *virt, unsigned int size); void prom_map (void *phys, void *virt, int size); diff -ur yaboot-1.3.14.orig/second/fs_ext2.c yaboot-1.3.14/second/fs_ext2.c --- yaboot-1.3.14.orig/second/fs_ext2.c 2010-08-03 15:28:29.916805885 -0500 +++ yaboot-1.3.14/second/fs_ext2.c 2010-08-03 15:47:40.274304966 -0500 @@ -54,6 +54,7 @@ static int ext2_seek( struct boot_file_t* file, unsigned int newpos); static int ext2_close( struct boot_file_t* file); +static unsigned int ext2_ino_size(struct boot_file_t *file); struct fs_t ext2_filesystem = { @@ -61,7 +62,8 @@ ext2_open, ext2_read, ext2_seek, - ext2_close + ext2_close, + ext2_ino_size, }; /* IO manager structure for the ext2 library */ @@ -565,6 +567,16 @@ return 0; } +static unsigned int ext2_ino_size(struct boot_file_t *file) +{ + struct ext2_inode ei; + + if (ext2fs_read_inode(fs, file->inode, &ei)) + return 0; + + return ei.i_size; +} + static errcode_t linux_open (const char *name, int flags, io_channel * channel) { io_channel io; diff -ur yaboot-1.3.14.orig/second/fs_of.c yaboot-1.3.14/second/fs_of.c --- yaboot-1.3.14.orig/second/fs_of.c 2010-08-03 15:28:29.896804336 -0500 +++ yaboot-1.3.14/second/fs_of.c 2010-08-03 15:47:40.274304966 -0500 @@ -44,7 +44,6 @@ #include "errors.h" #include "debug.h" -#define LOAD_BUFFER_POS 0x00000000 #define LOAD_BUFFER_SIZE 0x02000000 static int of_open(struct boot_file_t* file, @@ -58,6 +57,7 @@ struct partition_t* part, struct boot_fspec_t* fspec); static int of_net_read(struct boot_file_t* file, unsigned int size, void* buffer); static int of_net_seek(struct boot_file_t* file, unsigned int newpos); +static unsigned int of_net_ino_size(struct boot_file_t* file); struct fs_t of_filesystem = @@ -75,7 +75,8 @@ of_net_open, of_net_read, of_net_seek, - of_close + of_close, + of_net_ino_size, }; static int @@ -206,8 +207,7 @@ } - file->buffer = prom_claim_chunk((void *)LOAD_BUFFER_POS, - LOAD_BUFFER_SIZE, 0); + file->buffer = prom_claim_chunk_top(LOAD_BUFFER_SIZE, 0); if (file->buffer == (void *)-1) { prom_printf("Can't claim memory for TFTP download\n"); prom_close(file->of_device); @@ -284,6 +284,12 @@ return 0; } +static unsigned int +of_net_ino_size(struct boot_file_t* file) +{ + return file->len; +} + /* * Local variables: * c-file-style: "k&r" diff -ur yaboot-1.3.14.orig/second/prom.c yaboot-1.3.14/second/prom.c --- yaboot-1.3.14.orig/second/prom.c 2010-08-03 15:28:29.916805885 -0500 +++ yaboot-1.3.14/second/prom.c 2010-08-03 15:48:08.934304926 -0500 @@ -548,6 +548,23 @@ return((void*)-1); } +/* Start from top of memory and work down to get the needed space */ +void * +prom_claim_chunk_top(unsigned int size, unsigned int align) +{ + void *found, *addr; + for(addr=(void*)PROM_CLAIM_MAX_ADDR; addr >= (void *)size; + addr-=(0x100000/sizeof(addr))) { + found = call_prom("claim", 3, 1, addr, size, 0); + if (found != (void *)-1) { + prom_printf("claim of 0x%x at 0x%x returned 0x%x\n", size, (int)addr, (int)found); + return(found); + } + } + prom_printf("ERROR: claim of 0x%x in range 0x0-0x%x failed\n", size, PROM_CLAIM_MAX_ADDR); + return((void*)-1); +} + void * prom_claim (void *virt, unsigned int size, unsigned int align) { diff -ur yaboot-1.3.14.orig/second/yaboot.c yaboot-1.3.14/second/yaboot.c --- yaboot-1.3.14.orig/second/yaboot.c 2010-08-03 15:28:29.906805706 -0500 +++ yaboot-1.3.14/second/yaboot.c 2010-08-03 15:47:40.274304966 -0500 @@ -1211,25 +1211,33 @@ } else { #define INITRD_CHUNKSIZE 0x100000 - initrd_base = prom_claim(loadinfo.base+loadinfo.memsize, INITRD_CHUNKSIZE, 0); + unsigned int len = INITRD_CHUNKSIZE; + + /* We add a bit to the actual size so the loop below doesn't think + * there is more to load. + */ + if (file.fs->ino_size && file.fs->ino_size(&file) > 0) + len = file.fs->ino_size(&file) + 0x1000; + + initrd_base = prom_claim_chunk(loadinfo.base+loadinfo.memsize, len, 0); if (initrd_base == (void *)-1) { prom_printf("Claim failed for initrd memory\n"); initrd_base = 0; } else { - initrd_size = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_base); + initrd_size = file.fs->read(&file, len, initrd_base); if (initrd_size == 0) initrd_base = 0; initrd_read = initrd_size; initrd_more = initrd_base; - while (initrd_read == INITRD_CHUNKSIZE ) { /* need to read more? */ - initrd_want = (void *)((unsigned long)initrd_more+INITRD_CHUNKSIZE); - initrd_more = prom_claim(initrd_want, INITRD_CHUNKSIZE, 0); + while (initrd_read == len ) { /* need to read more? */ + initrd_want = (void *)((unsigned long)initrd_more+len); + initrd_more = prom_claim(initrd_want, len, 0); if (initrd_more != initrd_want) { prom_printf("Claim failed for initrd memory at %p rc=%p\n",initrd_want,initrd_more); prom_pause(); break; } - initrd_read = file.fs->read(&file, INITRD_CHUNKSIZE, initrd_more); + initrd_read = file.fs->read(&file, len, initrd_more); DEBUG_F(" block at %p rc=%lu\n",initrd_more,initrd_read); initrd_size += initrd_read; initrd_end = initrd_more+INITRD_CHUNKSIZE;