Greetings,
This message got more involved than I intended. I'd best preface it! Most of the bolow message is potential policy in payloads. LinuxBIOS need not (and probably should not) implement it, but will need to facillitate, or at least accomodate it:
The fixups I'm now doing in bootselect seem to be working reasonably well, but certainly have issues to be addressed. To start, the top of RAM works well enough on the board I'm using, but that will have to be adjusted on a system that actually uses an SMA framebuffer. Also, it would definatly fail on a wierd system that has holes in memory near the top, but that will be fixed in the real production code (as opposed to the quick and dirty exploritory code I'm using now).
Currently, I'm doing the stack relocation with:
unsigned long int ramtop; unsigned long int free_ramtop;
int _main(void) { lbmem = get_lbmem();
DPRINTF("Got lbmem struct: %08x\n", (unsigned int) lbmem);
ramtop = find_ramtop(lbmem); DPRINTF("Top of RAM = %08x\n", ramtop);
__asm__ __volatile__( "movl %%ebp, %%eax\n" "subl %%esp, %%eax\n" "movl %0, %%esp\n" "movl %0, %%ebp\n" "pushl %%ebp\n" "subl %%eax, %%esp\n" :: "d" (ramtop));
// reserve a stack free_ramtop = ramtop - 0x8000;
DPRINTF("ramtop = %08x, free_ramtop = %08x\n", ramtop, free_ramtop); DPRINTF("Calling main\n");
return(main()); }
In reality, if _main returns, it will surely crash. So, _main should call main, then hard_reset.
This can remain inside the payloads, by moving _main into libbaremetal and checking for a setup signature before messing with the stack, or LinuxBIOS itself can do the initial setup and have the payloads just cooperate. Note that a payload that will not return can ignore the change other than avoiding stack overwrite.
One goal is to have baremetal share as much of the code with LinuxBIOS as possible. Much of it simply uses the source directly in the tree, a few source files (boot.c elfboot.c) are slightly modified copies from the tree, and linuxbios.c (modified) from etherboot.
One good approach would be for LinuxBIOS to move the stack in whatever function calls elfload. At that point, it will know as much as it ever will about areas to avoid. With that, the mods to elfboot and boot.c can be folded back in without incident. LinuxBIOS can handle return from the payload by either calling hard_reset, or trying the next stream pointer and calling hard_resset when it encounters a null pointer (I note that the linker scripts do support multiple streams, but the feature isn't used now).
Moving on to memory allocation, as I see it, there are several possible states for an address region:
1. reserved (non-existant, flash, or a device) 2. available (real memory) 3. in use, only wipe out if you will never return. 4. stack, only wipe out after making other arrangements and you will never return.
Case 3 may either be hierarchical (removed before returning), or persistant (consider a 'driver' payload that leaves function pointers and some code behind in a table when it returns). I'm not sure where the latter is going (or not), but it'd be nice to leave the option open.
I believe that the non-returning payloads out there now can ignore 3, and already do the right thing for 4, but they would need to either understand the additional flags in the memory table (to the extent that they realize that 3 and 4 are usable memory for them), or have 3 and 4 specified in some other structure.
One simple approach is a system wide variable that holds the highest address that isn't somehow spoken for, and make sure all case 3 and 4 memory allocations are made out of high RAM.
G'day, sjames
On 3 May 2003, Eric W. Biederman wrote:
steven james pyro@linuxlabs.com writes:
Greetings,
Looks like I've trodden on an unused code path, and found a bug. In arch/i386/boot/boot.c: jmp_to_elf_entry, the idea is to copy all of the running code (linuxbios, or a baremetal payload) to a bounce buffer, jump into the copy there, copy the bounce buffer of the target elf into place, and call it. Upon return, the process is reversed, so that (in theory) jmp_to_elf_entry returns and further processing can happen.
For some reason, the lines that subtract the adjustment from EAX, then jump to move execution back to the proper place was failing. I've patched it in the copy kept in util/baremetal/lib so that instead, it loads the eventual jmp target into ecx, then saves it away on the stack.
I'm surely missing something here, but the original goes into space while the simple save off is working. I suppose that's just because we've never tried to return to LinuxBIOS from a payload before.
That sounds correct. It was there for completeness rather than a real need. And I never did test it.
The baremetal version also skips adjusting ESP since I'm moving the stack out of the way first.
Ignore the // debugging stuff, that was just to see where things were going wrong (I'll be getting rid of that).
Eric, since you wrote that part, I wanted to run this by you before making any changes in LinuxBIOS itself.
I would not be surprised to learn that the returning to LinuxBIOS was not working.
For LinuxBIOS itself all we can do is call hard_reset like we do for the other weird cases. But for the baremetal tool kit there we can definitely do something interesting.
I will have to look at what you are looking at stack wise but I certainly think we should have a stack that is out of the way as well, and we cannot have that in LinuxBIOS until we actually know our final memory size. And that information is not know until late.
There is one glitch in the LinuxBIOS code. After thinking and looking at things and see what works most reliably. We should be passing the address of the parameter block with the standard C calling conventions (and on x86 this is on the stack). I have modified etherboot to do this. I have not gotten back to the LinuxBIOS code.
With respect to memory maps. That is one piece of information that we should pass both ways. Both in the LinuxBIOS table, and in the parameter block we pass to the loaded image.
This allows someone to find the real memory usage as well as to find what the bootloader thinks about the current situation. A memory map is something fundamental enough that the memory allocation will always be changing.
I need to take my that specifies things about ELF booting and do another version. But I have not gotten quite that far yet.
Eric
Linuxbios mailing list Linuxbios@clustermatic.org http://www.clustermatic.org/mailman/listinfo/linuxbios