arcload (0.5-7) 12_ELF64_on_M32

Summary

 loader/main.c |  256 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 196 insertions(+), 60 deletions(-)

    
download this patch

Patch contents

#! /bin/sh /usr/share/dpatch/dpatch-run
## 12_ELF64_on_M32.dpatch by  <jblache@debian.org>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Add support for loading ELF64 kernels on 32bit PROMs.
## DP: (some code shamelessly stolen from arcboot)

@DPATCH@
diff -urNad arcload-0.5~/loader/main.c arcload-0.5/loader/main.c
--- arcload-0.5~/loader/main.c	2007-09-11 16:17:27.000000000 +0000
+++ arcload-0.5/loader/main.c	2007-09-11 16:18:32.000000000 +0000
@@ -30,6 +30,17 @@
 // malloc pool size
 #define ARENA		1048576
 
+
+typedef union {
+	unsigned char e_ident[EI_NIDENT];
+	Elf32_Ehdr e32;
+	Elf64_Ehdr e64;
+} Elf_Ehdr;
+
+#ifdef M32
+INT is_elf64 = 1;
+#endif
+
 INT checkmemmap(ULONG elf_start, ULONG elf_size)
 {
 	MEMORYDESCRIPTOR *md;
@@ -84,84 +95,112 @@
 #endif
 }
 
-ULONG load_elf(CHAR *fname)
-{
-	BDEV file;
+
 #ifdef M32
-	Elf32_Ehdr hdr;
+Elf64_Addr load_elf32(Elf32_Ehdr *hdr, BDEV *file)
+{
 	Elf32_Phdr ph[N_PHDR];
-	ULONG elf_ehdr_size = sizeof(Elf32_Ehdr);
-	ULONG elf_phdr_size = sizeof(Elf32_Phdr);
-#else
-	Elf64_Ehdr hdr;
-	Elf64_Phdr ph[N_PHDR];
-	ULONG elf_ehdr_size = sizeof(Elf64_Ehdr);
-	ULONG elf_phdr_size = sizeof(Elf64_Phdr);
-#endif
 	INT i, j, nph = 0;
 	ULONG left, pos;
 	UCHAR *ptr;
 
-	/* Open */
-	if(bopen(&file, fname)) {
-		printf("Opening %s failed.\n\r", fname);
+	/* Not Relocatable? */
+	if(hdr->e_type != ET_EXEC) {
+		printf("ELF file is not executable.\n\r");
+		printf("Relocatable files are not supported, sorry.\n\r");
 		return 0;
 	}
 
-	printf("Loading %s...\n\r", fname);
-
-	/* Read ELF Header */
-	if(bread(&file, elf_ehdr_size, &hdr)<0) {
-		printf("Error reading ELF header.\n\r");
-		goto close;
+	/* Does the ELF have any Program Headers? */
+	if(hdr->e_phnum == 0) {
+		printf("ELF file contains no Program Headers.\n\r");
+		return 0;
 	}
 
-	/* Is is an ELF binary? */
-	if((hdr.e_ident[0] != 0x7f) || 
-	   (hdr.e_ident[1] != 'E')  || 
-	   (hdr.e_ident[2] != 'L')  ||
-	   (hdr.e_ident[3] != 'F'))
-	{
-		printf("ELF magic invalid.\n\r");
-		goto close;
+	/* Save LOAD headers */
+	for(i = 0; i < hdr->e_phnum; i++) {
+		bseek(file, (hdr->e_phoff + (i * hdr->e_phentsize)));
+		if(bread(file, sizeof(Elf32_Phdr), ph+nph)<0) {
+			printf("Can't read program header %u at 0x%x!\n\r", i, hdr->e_phoff + (i * hdr->e_phentsize));
+			return 0;
+		}
+
+		if(ph[nph].p_type != PT_LOAD)
+			continue;
+
+		nph++;
+		if(nph>=N_PHDR) {
+			printf("ELF file has too many LOAD headers (over N_PHDR).\n\r");
+			return 0;
+		}
 	}
 
-	/* 32 or 64 bit? */
-#ifdef M32
-	if(hdr.e_ident[EI_CLASS] != ELFCLASS32) {
-		printf("ELF file is not 32-bit.\n\r");
-#else
-	if(hdr.e_ident[EI_CLASS] != ELFCLASS64) {
-		printf("ELF file is not 64-bit.\n\r");
-#endif
-		goto close;
+	/* Was a LOAD header found? */
+	if(!nph) {
+		printf("ELF file contains no LOAD header.\n\r");
+		return 0;
 	}
 
-	/* Big Endian? */
-	if(hdr.e_ident[EI_DATA] != ELFDATA2MSB) {
-		printf("ELF file is not big-endian.\n\r");
-		goto close;
+	/* Realize LOAD headers */
+	for(i = 0; i < nph; i++) {
+		/* Check the Memory Map */
+		if(checkmemmap(vtophys(ph[i].p_vaddr), ph[i].p_memsz)) {
+			printf("File can't be loaded into current memory map.\n\r");
+			return 0;
+		}
+
+		/* Load the ELF into memory */
+		printf("Reading %u bytes... ", (ULONG)ph[i].p_filesz);
+		left = ph[i].p_filesz;
+		pos = 0;
+		ptr = (UCHAR *)ph[i].p_vaddr;
+		bseek(file, ph[i].p_offset);
+		while(left > 0) {
+			j = ((left > READBLOCK) ? READBLOCK : left);
+			if(bread(file, j, ptr)<0) {
+				printf("failed at %u!\n\r", (ULONG)pos);
+				return 0;
+			}
+			left -= j;
+			ptr += j;
+			pos += j;
+		}
+		printf("OK.\n\r");
+		ptr = (UCHAR *)(ph[i].p_vaddr + ph[i].p_filesz);
+		for(pos = ph[i].p_filesz; pos < ph[i].p_memsz; pos++)
+			*(ptr++) = 0;
 	}
 
+	return (Elf64_Addr) hdr->e_entry;
+}
+#endif /* M32 */
+
+Elf64_Addr load_elf64(Elf64_Ehdr *hdr, BDEV *file)
+{
+	Elf64_Phdr ph[N_PHDR];
+	INT i, j, nph = 0;
+	ULONG left, pos;
+	UCHAR *ptr;
+
 	/* Not Relocatable? */
-	if(hdr.e_ident[EI_DATA] != ET_EXEC) {
+	if(hdr->e_type != ET_EXEC) {
 		printf("ELF file is not executable.\n\r");
 		printf("Relocatable files are not supported, sorry.\n\r");
-		goto close;
+		return 0;
 	}
 
 	/* Does the ELF have any Program Headers? */
-	if(hdr.e_phnum == 0) {
+	if(hdr->e_phnum == 0) {
 		printf("ELF file contains no Program Headers.\n\r");
-		goto close;
+		return 0;
 	}
 
 	/* Save LOAD headers */
-	for(i = 0; i < hdr.e_phnum; i++) {
-		bseek(&file, (hdr.e_phoff + (i * hdr.e_phentsize)));
-		if(bread(&file, elf_phdr_size, ph+nph)<0) {
-			printf("Can't read program header %u at 0x%x!\n\r", i, hdr.e_phoff + (i * hdr.e_phentsize));
-			goto close;
+	for(i = 0; i < hdr->e_phnum; i++) {
+		bseek(file, (hdr->e_phoff + (i * hdr->e_phentsize)));
+		if(bread(file, sizeof(Elf64_Phdr), ph+nph)<0) {
+			printf("Can't read program header %u at 0x%x!\n\r", i, hdr->e_phoff + (i * hdr->e_phentsize));
+			return 0;
 		}
 
 		if(ph[nph].p_type != PT_LOAD)
@@ -170,14 +209,14 @@
 		nph++;
 		if(nph>=N_PHDR) {
 			printf("ELF file has too many LOAD headers (over N_PHDR).\n\r");
-			goto close;
+			return 0;
 		}
 	}
 
 	/* Was a LOAD header found? */
 	if(!nph) {
 		printf("ELF file contains no LOAD header.\n\r");
-		goto close;
+		return 0;
 	}
 
 	/* Realize LOAD headers */
@@ -185,34 +224,96 @@
 		/* Check the Memory Map */
 		if(checkmemmap(vtophys(ph[i].p_vaddr), ph[i].p_memsz)) {
 			printf("File can't be loaded into current memory map.\n\r");
-			goto close;
+			return 0;
 		}
 
 		/* Load the ELF into memory */
 		printf("Reading %u bytes... ", (ULONG)ph[i].p_filesz);
 		left = ph[i].p_filesz;
 		pos = 0;
+#ifdef M32
+		ptr = (UCHAR *)(Elf32_Addr)ph[i].p_vaddr;
+#else
 		ptr = (UCHAR *)ph[i].p_vaddr;
-		bseek(&file, ph[i].p_offset);
+#endif
+		bseek(file, ph[i].p_offset);
 		while(left > 0) {
 			j = ((left > READBLOCK) ? READBLOCK : left);
-			if(bread(&file, j, ptr)<0) {
+			if(bread(file, j, ptr)<0) {
 				printf("failed at %u!\n\r", (ULONG)pos);
-				goto close;
+				return 0;
 			}
 			left -= j;
 			ptr += j;
 			pos += j;
 		}
 		printf("OK.\n\r");
+#ifdef M32
+		ptr = (UCHAR *)(Elf32_Addr)(ph[i].p_vaddr + ph[i].p_filesz);
+#else
 		ptr = (UCHAR *)(ph[i].p_vaddr + ph[i].p_filesz);
+#endif
 		for(pos = ph[i].p_filesz; pos < ph[i].p_memsz; pos++)
 			*(ptr++) = 0;
 	}
 
+	return hdr->e_entry;
+}
+
+Elf64_Addr load_elf(CHAR *fname)
+{
+	BDEV file;
+	Elf_Ehdr hdr;
+	Elf64_Addr kentry;
+
+	/* Open */
+	if(bopen(&file, fname)) {
+		printf("Opening %s failed.\n\r", fname);
+		return 0;
+	}
+
+	printf("Loading %s...\n\r", fname);
+
+	/* Read ELF Header */
+	if(bread(&file, sizeof(hdr), &hdr)<0) {
+		printf("Error reading ELF header.\n\r");
+		goto close;
+	}
+
+	/* Is is an ELF binary? */
+	if((hdr.e_ident[0] != 0x7f) || 
+	   (hdr.e_ident[1] != 'E')  || 
+	   (hdr.e_ident[2] != 'L')  ||
+	   (hdr.e_ident[3] != 'F'))
+	{
+		printf("ELF magic invalid.\n\r");
+		goto close;
+	}
+
+	/* Big Endian? */
+	if(hdr.e_ident[EI_DATA] != ELFDATA2MSB) {
+		printf("ELF file is not big-endian.\n\r");
+		goto close;
+	}
+
+	/* 32 or 64 bit? */
+	if(hdr.e_ident[EI_CLASS] == ELFCLASS64) {
+		kentry = load_elf64(&hdr.e64, &file);
+	}
+#ifdef M32
+	else if(hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+		is_elf64 = 0;
+		kentry = load_elf32(&hdr.e32, &file);
+	}
+#endif
+	else {
+		printf("ELF file cannot be loaded.\n\r");
+		goto close;
+	}
+
 	bclose(&file);
 
-	return hdr.e_entry;
+	return kentry;
 
 /* Failed to do something, close and return */
 close:
@@ -220,6 +321,7 @@
 	return 0;
 }
 
+
 #ifdef M64
 unsigned fixup_trampolines_data[]={
 	0x03e00821, 0x04110001, 0x00000000, 0xdfe30014,
@@ -248,12 +350,31 @@
 		       "Patched %u occurrences of the wrong trampoline.\n"
 		       "-- WARNING --\n", stat);
 }
-#endif
+#endif /* M64 */
+
+#ifdef M32
+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");
+}
+#endif /* M32 */
 
 void __start(void);
 LONG main(INT argc, CHAR **argv, CHAR **envp)
 {
-	ULONG entry;
+	Elf64_Addr entry;
+#ifdef M32
+	Elf32_Addr entry32 = (Elf32_Addr)entry;
+#endif
 	VOID (*kernel_entry)(INT argc, CHAR **argv, CHAR **envp);
 
 	char *system;
@@ -318,10 +439,25 @@
 	if(!entry)
 		return 1;
 
+#ifdef M32
+	if(!is_elf64) {
+		kernel_entry = (VOID(*)(INT, CHAR **, CHAR **))entry32;
+
+		printf("Entering 32bit kernel.\n\r");
+		ArcFlushAllCaches();
+		kernel_entry(append_count, append, envp);
+	} else {
+		printf("Entering 64bit kernel.\n\r");
+		ArcFlushAllCaches();
+		_start64(append_count, append, envp, &entry);
+	}
+#else
 	kernel_entry = (VOID(*)(INT, CHAR **, CHAR **))entry;
 
 	printf("Entering kernel.\n\r");
+	ArcFlushAllCaches();
 	kernel_entry(append_count, append, envp);
+#endif
 	return 0;
 }