Subject: Moving kernel_entry to LOADADDR

From: Gerald Champagne <[email-masked]>
Date: Thu, 18 Oct 2001 19:58:58 -0500

I'm planning to work with a very minimal boot loader, and I'd like
to hard-code a jump to kernel_entry in my boot loader.  I got tired
of having kernel_entry moving around, so I just moved it to the top
of head.S, just afte the ".fill 0x280".  That places kernel_entry at
the same place every time.  It's always at LOADADDR+0x280.

But wait a minute... the 0x280 is there to leave room for the exception
vectors.  Doesn't that only make sense if LOADADDR=0x80000000?  Isn't
this allocating the space for the exception vectors twice?  Why not
remove the .fill, then the kernel entry point will always be exactly
LOADADDR?  This would break any configuration that has LOADADDR=0x80000000,
but the only configuration like that is CONFIG_ALGOR_P4032, and that could
easily be modified to LOADADDR=0x80000280 to get the same effect.

I also removed the .fill, and now kernel_entry is always exactly LOADADDR,
and that makes my bootloader easier to maintain.

Is this worth changing in cvs, or did I miss something?

Thanks.

Gerald

---

From: Geoffrey Espin <[email-masked]>
Date: Thu, 18 Oct 2001 18:13:22 -0700

Gerald,

> the same place every time.  It's always at LOADADDR+0x280.

Don't know about all .fill & exception vecs... the trick I use in
my (vr)boot loader...

KERNEL_ENTRY=$(shell awk '/kernel_entry/{print "0x" $$1}' $(LINUX_SRC)/System.map)
CFLAGS+=-DKERNEL_ENTRY=$(KERNEL_ENTRY)

And compile boot.S or whatever your bootloader is.

But a fixed, well-known offset can't be a bad thing either.

Geoff
-- 
Geoffrey Espin [email-masked]

---

From: "Gleb O. Raiko" <[email-masked]>
Date: Fri, 19 Oct 2001 11:31:12 +0400

> Is this worth changing in cvs, or did I miss something?

Embed your kernel in your own bootloader, load the bootloader from fixed
addr. In the bootloader move the kernel at any location you want and
jump to the kernel entry. The kernel entry is known at compile time, so
you can teach the bootloader. This way you won't disturb others.

Regards,
Gleb.

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Fri, 19 Oct 2001 15:20:33 +0200 (MET DST)

> Is this worth changing in cvs, or did I miss something?

 How about just getting it from the ELF header?  It's trivial.

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: [email-masked], PGP key available        +

---

From: Mike McDonald <[email-masked]>
Date: Fri, 19 Oct 2001 08:11:40 -0700

>Date: Fri, 19 Oct 2001 15:20:33 +0200 (MET DST)
>From: "Maciej W. Rozycki" <[email-masked]>
>To: Gerald Champagne <[email-masked]>
>Subject: Re: Moving kernel_entry to LOADADDR
>

  Because a bare bones bootloader may not know anything about ELF. The
simplest solution is to just stick a "jmp start_kernel" at LOADADDR
right before the fill. Then the load address and the entry point are
the same. Once the exception vectors get loaded, they'll overwrite the
jmp, so no space is wasted and none of the LOADADDRs have to be
changed.

  Mike McDonald
  [email-masked]

---

From: Gerald Champagne <[email-masked]>
Date: Fri, 19 Oct 2001 10:18:48 -0500

> jmp, so no space is wasted and none of the LOADADDRs have to be

That was my thinking.

Except the fill has nothing to do with exception vectors any more.  It
looks like at one time LOADADDR was always 0x8000_0000.  Now that it's
set to something else, the fill just leaves a hole for no reason.  That's
why I recommend removing it regardless of whether there's a use for my
idea.

With the fill is gone, and since the kernel is not normally placed
at 0x8000_0000, I suggest just moving kernel_entry to the top of head.S
instead of putting a jump at the top of the file.

Also, compile tricks won't work (at least in my case).  Normally the bootloader
and the kernel are in two memories, often programmed in different ways.  For
example, a system normally has rom at the boot address at 0x1fc0_0000, ram at
0x8000_0000, and some other memory (flash, hard disk, whatever) storing a kernel
(or kernels) somewhere else.  Any compile time tricks require the boot rom to be
reprogrammed when the kernel changes.  That's part of what I wanted to avoid.

Gerald

---

From: Justin Carlson <[email-masked]>
Date: 19 Oct 2001 11:21:41 -0400

> jmp, so no space is wasted and none of the LOADADDRs have to be

This may be true, but grokking ELF far enough to find e_entry just a
matter of looking at a fixed offset into the kernel image.  Problems
that require bootloaders to be simpler than that are pretty rare...

-Justin

---

From: Mike McDonald <[email-masked]>
Date: Fri, 19 Oct 2001 08:56:04 -0700

>From: Justin Carlson <[email-masked]>
>To: [email-masked]
>Date: 19 Oct 2001 11:21:41 -0400
>

  But they do exist, especially in the embedded world. For instance,
I've run linux with boot loader out of a 1MB flash into 8MB of RAM. 
(VR4121 based system.) The kernel image stored in the flash had to be
a compressed raw memory image inorder to fit in the flash.  (The flash
also had to have room to the initrd.) Adding ELF headers to the image
would probably have pushed the size over the limit.

  Mike McDonald
  [email-masked]

---

From: Florian Lohoff <[email-masked]>
Date: Wed, 24 Oct 2001 13:16:11 +0200

> the same place every time.  It's always at LOADADDR+0x280.

Dont do this - Its easy to decode the elf stuff:

Basically this is the code needed to relocate the elf chunks
and return the entry point. I might have corrupted it a bit due to stripping
unneeded bits but you will get the point. This code even clears bss
chunk which the kernel will do itself again.

	Elf32_Ehdr	*fhdr = fb;
	Elf32_Shdr	*shdr;	
	int		i;

	if (fhdr->e_machine != EM_MIPS) {
		printf("No Mips ELF\n");
		return(0);	
	}

	fhdr=(void *) KSEG1ADDR(fb);

	shdr=fb + fhdr->e_shoff;

	for(i=0;i<fhdr->e_shnum;i++,shdr++) {

		if (shdr->sh_size <= 0) 
			continue;

		if (shdr->sh_type == SHT_PROGBITS) {
			memcpy((void *) KSEG1ADDR(shdr->sh_addr),
				KSEG1ADDR(fb + shdr->sh_offset),
				shdr->sh_size);
		} else if (shdr->sh_type == SHT_NOBITS) {
			memset((void *) KSEG1ADDR(shdr->sh_addr), 0x0, shdr->sh_size);
		}
	}
	return((void *) fhdr->e_entry);

-- 
Florian Lohoff                  [email-masked]             +49-5201-669912
Nine nineth on september the 9th              Welcome to the new billenium