EMILE/second/load.c

199 lines
4.5 KiB
C
Raw Normal View History

2004-05-26 21:59:06 +00:00
/*
*
* (c) 2004,2005 Laurent Vivier <Laurent@lvivier.info>
2004-05-26 21:59:06 +00:00
*
*/
2005-12-02 19:05:36 +00:00
#define __NO_INLINE__
2004-05-26 21:59:06 +00:00
#include <stdio.h>
#include <malloc.h>
2005-11-22 23:17:31 +00:00
#include <elf.h>
2005-05-22 21:14:41 +00:00
#include <string.h>
2005-11-08 02:06:40 +00:00
#include <macos/types.h>
#include <macos/devices.h>
2005-11-22 23:17:31 +00:00
#include <libstream.h>
2005-11-08 02:06:40 +00:00
2005-12-02 19:05:36 +00:00
#include "console.h"
2004-07-12 21:32:44 +00:00
#include "bank.h"
#include "misc.h"
2005-11-22 23:17:31 +00:00
2004-05-26 21:59:06 +00:00
#include "load.h"
2005-11-22 23:17:31 +00:00
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
2005-12-02 19:05:36 +00:00
#define BAR_STEP 40
static int bar_read(stream_t *stream, char*buffer, int size,
int current, int total_size)
{
int read = 0;
int blksize = (total_size + BAR_STEP - 1) / BAR_STEP;
int ret;
2005-12-05 19:57:27 +00:00
console_cursor_restore();
printf(" %d %%", ((current + read) * 100 + total_size / 2) / total_size);
2005-12-02 19:05:36 +00:00
while (size)
{
if (blksize > size)
blksize = size;
ret = stream_read(stream, buffer, blksize);
read += ret;
if (ret != blksize)
break;
console_cursor_restore();
printf("#");
console_cursor_save();
printf(" %d %%", ((current + read) * 100 + total_size / 2) / total_size);
buffer += ret;
size -= ret;
}
console_cursor_restore();
printf(" %d %%", ((current + read) * 100 + total_size / 2) / total_size);
return read;
}
2005-11-22 23:17:31 +00:00
char* load_kernel(char* path, int bootstrap_size,
unsigned long *base, unsigned long *entry, unsigned long *size)
2004-05-26 21:59:06 +00:00
{
2005-11-22 23:17:31 +00:00
Elf32_Ehdr elf_header;
Elf32_Phdr *program_header;
int ret;
unsigned long min_addr, max_addr, kernel_size;
2004-12-03 00:19:02 +00:00
int i;
2005-11-22 23:17:31 +00:00
char *kernel;
stream_t *stream;
2005-12-02 19:05:36 +00:00
int read;
int to_read;
printf("Loading kernel ");
2005-11-22 23:17:31 +00:00
stream = stream_open(path);
if (stream == NULL)
return NULL;
2005-11-22 23:17:31 +00:00
stream_uncompress(stream);
2005-11-22 23:17:31 +00:00
ret = stream_read(stream, &elf_header, sizeof(Elf32_Ehdr));
if (ret != sizeof(Elf32_Ehdr))
error("Cannot read\n");
2005-11-22 23:17:31 +00:00
if (elf_header.e_machine != EM_68K)
{
2005-11-22 23:17:31 +00:00
printf( "Not MC680x0 architecture\n");
return NULL;
}
2005-11-22 23:17:31 +00:00
if (elf_header.e_type != ET_EXEC)
{
printf( "Not an executable file\n");
return NULL;
}
2005-11-22 23:17:31 +00:00
program_header = (Elf32_Phdr *)malloc(elf_header.e_phnum *
sizeof (Elf32_Phdr));
if (program_header == NULL)
{
printf( "Cannot allocate memory\n");
return NULL;
}
2005-11-22 23:17:31 +00:00
ret = stream_lseek(stream, elf_header.e_phoff, SEEK_SET);
2005-11-22 23:17:31 +00:00
ret = stream_read(stream, program_header, elf_header.e_phnum * sizeof(Elf32_Phdr));
2005-11-22 23:17:31 +00:00
min_addr = 0xffffffff;
max_addr = 0;
2005-12-02 19:05:36 +00:00
to_read = 0;
2005-11-22 23:17:31 +00:00
for (i = 0; i < elf_header.e_phnum; i++)
{
min_addr = (min_addr > program_header[i].p_vaddr) ?
program_header[i].p_vaddr : min_addr;
max_addr = (max_addr < program_header[i].p_vaddr + program_header[i].p_memsz) ?
program_header[i].p_vaddr + program_header[i].p_memsz: max_addr;
2005-12-02 19:05:36 +00:00
to_read += program_header[i].p_filesz;
2005-11-22 23:17:31 +00:00
}
if (min_addr == 0)
{
min_addr = PAGE_SIZE;
program_header[0].p_vaddr += PAGE_SIZE;
program_header[0].p_offset += PAGE_SIZE;
program_header[0].p_filesz -= PAGE_SIZE;
program_header[0].p_memsz -= PAGE_SIZE;
}
kernel_size = max_addr - min_addr;
*base = min_addr;
*entry = elf_header.e_entry;
*size = kernel_size;
kernel = (char*)malloc_contiguous(kernel_size + 4 + bootstrap_size);
kernel = (unsigned char*)(((unsigned long)kernel + 3) & 0xFFFFFFFC);
if (!check_full_in_bank((unsigned long)kernel, kernel_size))
error("Kernel between two banks, contact maintainer\n");
memset(kernel, 0, kernel_size);
2005-12-02 19:05:36 +00:00
read = 0;
console_cursor_save();
2005-11-22 23:17:31 +00:00
for (i = 0; i < elf_header.e_phnum; i++)
{
ret = stream_lseek(stream, program_header[i].p_offset, SEEK_SET);
2005-12-05 19:57:27 +00:00
if (ret != program_header[i].p_offset)
{
error("Cannot seek");
}
2005-12-02 19:05:36 +00:00
ret = bar_read( stream,
kernel + program_header[i].p_vaddr - PAGE_SIZE,
program_header[i].p_filesz,
read, to_read);
2005-12-02 01:19:51 +00:00
if (ret != program_header[i].p_filesz)
{
printf("Read %d instead of %d\n",
ret, program_header[i].p_filesz);
error("Cannot load");
}
2005-12-02 19:05:36 +00:00
read += ret;
2005-11-22 23:17:31 +00:00
}
2005-12-02 19:05:36 +00:00
putchar('\n');
2005-11-22 23:17:31 +00:00
ret = stream_close(stream);
2005-11-22 23:17:31 +00:00
return kernel;
}
2005-11-23 00:11:33 +00:00
2005-11-23 22:43:32 +00:00
char *load_ramdisk(char* path, unsigned long *ramdisk_size)
2005-11-23 00:11:33 +00:00
{
stream_t *stream;
char *ramdisk_start;
struct stream_stat stat;
2005-12-02 01:19:51 +00:00
int ret;
2005-11-23 00:11:33 +00:00
stream = stream_open(path);
if (stream == NULL)
return NULL;
stream_fstat(stream, &stat);
ramdisk_start = (char*)malloc_top(stat.st_size + 4);
ramdisk_start = (char*)(((unsigned long)ramdisk_start + 3) & 0xFFFFFFFC);
if (!check_full_in_bank((unsigned long)ramdisk_start, stat.st_size))
error("ramdisk between two banks, contact maintainer\n");
2005-12-02 19:05:36 +00:00
printf("Loading RAMDISK ");
2005-11-23 00:11:33 +00:00
2005-12-02 19:05:36 +00:00
console_cursor_save();
ret = bar_read(stream, ramdisk_start, stat.st_size, 0, stat.st_size);
putchar('\n');
2005-12-02 01:19:51 +00:00
if (ret != stat.st_size)
error("Cannot load");
2005-11-23 00:11:33 +00:00
stream_close(stream);
*ramdisk_size = stat.st_size;
return ramdisk_start;
}