/*
 * elf.c
 *
 * Copyright 2003, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 */


#include<types.h>
#include<lib.h>
#include<mm.h>
#include<fs.h>
#include<console.h>


enum{EI_NIDENT=16};

typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef int Elf32_Sword;
typedef unsigned int Elf32_Word;


/* ELF Header define valus */
enum{
	/* e_type */
	ET_REL=	1,		/* Relocatable file */
	ET_EXEC=2,		/* Executable file */
	ET_DYN=	3,		/* Shared object file */

	/* e_machine */
	EM_386=3,		/* Intel 80386 */

	/* Segment Types. */
	PT_LOAD=1,

	/* Program Header flag. */
	PF_X=1,
	PF_W=2,
	PF_R=4,
};

/* ELF Header */
typedef struct{
	unsigned char e_ident[EI_NIDENT];
	Elf32_Half e_type;					/* ファイルタイプ。 */
	Elf32_Half e_machine;				/* cpuアーキテクチャ。 */
	Elf32_Word e_version;
	Elf32_Addr e_entry;					/* エントリーメモリーアドレス。 */
	Elf32_Off e_phoff;					/* プログラムヘッダーファイルオフセット。 */
	Elf32_Off e_shoff;
	Elf32_Word e_flags;
	Elf32_Half e_ehsize;
	Elf32_Half e_phentsize;
	Elf32_Half e_phnum;					/* プログラムヘッダー数。 */
	Elf32_Half e_shentsize;
	Elf32_Half e_shnum;
	Elf32_Half e_shstrndx;
}Elf32_Ehdr;

/* Program Header */
typedef struct{
	Elf32_Word p_type;		/* セグメントタイプ。 */
	Elf32_Off p_offset;		/* ファイルオフセット。 */
	Elf32_Addr p_vaddr;		/* メモリーアドレス。 */
	Elf32_Addr p_paddr;
	Elf32_Word p_filesz;	/* セグメントロードファイルサイズ。 */
	Elf32_Word p_memsz;		/* セグメントメモリーサイズ。 */
	Elf32_Word p_flags;		/* セグメントフラグ。 */
	Elf32_Word p_align;
}Elf32_Phdr;


/*
 * ELFバイナリをロードする。
 * parameters : open file struct
 * return : エントリーアドレス or error=0
 */
uint loadElf(EXEC_FD *fd)
{
	Elf32_Ehdr *header;
	Elf32_Phdr *phead;
	uint entry_addr;
	int tmp,i;


	/* ヘッダを読み込む */
	if ((header = kmalloc(sizeof(Elf32_Ehdr))) == NULL)
		return 0;
	fd->offset=0;
	if (exec_read(fd,header,sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr))
		goto ERR;

	/* マジックナンバー確認 */
	if (memcmp("\177ELF",header->e_ident,4) != 0)
		goto ERR;						

	/* タイプ、cpu確認 */
	if ((header->e_type != ET_EXEC) || (header->e_machine != EM_386))
		goto ERR;

	/* ユーザーのテキストとデータページを開放する。 */
	releaseUserPage();

	/* プログラムヘッダーを読み込む。 */
	tmp = header->e_phnum * sizeof(Elf32_Phdr);				/* 全プログラムヘッダーサイズ。 */
	if ((phead = kmalloc(tmp)) == NULL)
		goto ERR;
	fd->offset = header->e_phoff;
	if (exec_read(fd,phead,tmp) != tmp)
		goto ERR2;

	/* プログラムのロード。 */
	for (i = 0; i < header->e_phnum; ++i)
		if ((phead[i].p_type == PT_LOAD) && (0 < phead[i].p_memsz))
		{
			fd->offset = phead[i].p_offset;
			if (loadBinary(fd,phead[i].p_memsz,phead[i].p_filesz,phead[i].p_vaddr,(phead[i].p_flags & PF_W)? LB_WR : LB_R) == -1)
				goto ERR2;
		}

	entry_addr = header->e_entry;

	kfree(phead);
	kfree(header);

	return entry_addr;

ERR2:
	kfree(phead);
ERR:
	kfree(header);

	return 0;
}
/*************************************************************************/
void test_elf(void *buf)
{
	printk("entry address=%x\n",((Elf32_Ehdr*)buf)->e_entry);
}
