Page 1 of 1
Writing to Address 0x104000
Posted: Tue Oct 09, 2012 8:06 pm
by mmurfin87
I'm trying to create a stack of free physical memory pages from the multiboot memory map, and it works fine until I get to address 0x00104000 when, without further ado, bochs resets. I take the map and for every valid page address I call FreeFrame on it.
Code: Select all
UInt32 i = multibootHeader->mmap_addr;
while (i < multibootHeader->mmap_addr + multibootHeader->mmap_length)
{
struct MultibootMMapEntry *me = (struct MultibootMMapEntry*)i;
// Does this entry specify usable RAM?
if (me->type == 1)
{
// For every page in this entry, add to the free page stack.
for (UInt32 j = (me->base_addr_low & 0xFFFFF000) + 0x1000; j <= me->base_addr_low + me->length_low - 0x1000; j += 0x1000)
FreeFrame(j);
}
i += me->size + sizeof(UInt32);
}
FreeFrame() writes the current frameStackTop address to the very first 4 bytes of the page frame, then sets frameStackTop to the frame address itself. I'm using this structure to form a stack
Code: Select all
unsigned int *frameStackTop = 0;
void FreeFrame(unsigned int frame)
{
frame &= 0xFFFFF000;
*(unsigned int*)frame = (unsigned int)frameStackTop;
frameStackTop = (unsigned int*)frame;
}
So far, testing in bochs has consistently given me two chunks of memory: 0x00000000 - 0x0009F000, and 0x00100000 - 0x01FF0000. The code above works fine for the first chunk, but whenever I start on the second chunk, it runs up to 0x00103000 just fine, then something goes haywire and bochs resets.
Is there anything simple I'm overlooking here?
Re: Writing to Address 0x104000
Posted: Tue Oct 09, 2012 10:15 pm
by Brendan
Hi,
mmurfin87 wrote:Is there anything simple I'm overlooking here?
Which area of memory contains the code that is freeing (and writing to) memory at 0x00100000?
Cheers,
Brendan
Re: Writing to Address 0x104000
Posted: Tue Oct 09, 2012 11:15 pm
by zhiayang
Brendan wrote:Hi,
Which area of memory contains the code that is freeing (and writing to) memory at 0x00100000?
Cheers,
Brendan
Apologies for barging in, but I seem to have the same problem.
Brendan: How would I find out what address I'm currently executing at? (I'm under the impression that your rhetorical question is meant to tell me that I shouldn't write to where I am executing)
Using objdump -x, I know that according to the 'SYMBOL TABLE:', my kmain() function is at 0x00000BEB.
Also, mmurfin87: you may want to run objdump on your object file (if you're using ELF), because I got:
Code: Select all
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .eh_frame 000004dc 00103000 00103000 00004000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .data 00000b20 001034e0 001034e0 000044e0 2**5
CONTENTS, ALLOC, LOAD, DATA
3 .bss 0000546c 00104000 00104000 00005000 2**5
ALLOC
Which suggests something along the lines of overwriting .eh_frame (pardon me, but what is that?), the data and BSS sections. (I'm under the impression that that's all bad).
Not to mention that both .eh_frame and .data are READONLY...
EDIT: Changing the entry point of my loader, I find that it doesn't crash anymore. However,
1. I don't think that's actually a solution, is it?
2. If GRUB places the modules directly after where it loads the kernel (it appears to at any rate), is there a way to specify that address where the modules are placed?
Re: Writing to Address 0x104000
Posted: Tue Oct 09, 2012 11:31 pm
by bluemoon
Basically there is 2 approaches(or more):
1. By define it. You assign hardcode address range in your linker script, say, enclose the code+data+bss with kstart/kend, and avoid overwrite/reuse that range upon initialization.
2. By getting the IP and calculate such range. You may get current IP by call/pop - calculate the range from the current IP is a bit tricky but you got the idea.
My kernel uses method one for simplicity.
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 5:34 am
by zhiayang
bluemoon wrote:Basically there is 2 approaches(or more):
1. By define it. You assign hardcode address range in your linker script, say, enclose the code+data+bss with kstart/kend, and avoid overwrite/reuse that range upon initialization.
2. By getting the IP and calculate such range. You may get current IP by call/pop - calculate the range from the current IP is a bit tricky but you got the idea.
My kernel uses method one for simplicity.
Well I don't understand what you mean in (1).
Right now the segments (code, data and bss) all start at after the kernel, which is at 0x00100000. That might explain why it's probably trying to overwrite something important.
But by hardcoding the address, you impose a minimum amount of RAM on the hardware, right?
Also: The way I'm going, my module is a stage2 which is supposed to load from FS the actual kernel, which is going to be higher-half. So I don't really want to keep shuffling memory around;
If I set the entry point higher, I'll have to move the module to 2MB (that's the entry point). If I execute the stage2 from where it is, I'll possibly be having problems, since the kernel is supposed to be somewhere there.
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 5:46 am
by Combuster
requimrar wrote:But by hardcoding the address, you impose a minimum amount of RAM on the hardware, right?
Only for the idiots that link higher than 1M as well as refusing to use virtual memory management. Otherwise the memory needed just equals the size of the blobs in memory.
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 7:15 am
by zhiayang
Combuster wrote:requimrar wrote:But by hardcoding the address, you impose a minimum amount of RAM on the hardware, right?
Only for the idiots that link higher than 1M as well as refusing to use virtual memory management. Otherwise the memory needed just equals the size of the blobs in memory.
I'm sorry, but GRUB doesn't support linking below 1M. So there.
As for using VM, I need some clarifications:
If I enable PAE paging now, how do I make use of the full memory address (not that there actually will be any machine with more than 64GB)? Do I simply set up a new PDPT with more entries, then load CR3 with it's (new) address?
Also I'm just trying to make this work; I don't need anything overly fancy just yet.
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 8:03 am
by mmurfin87
Brendan wrote:Which area of memory contains the code that is freeing (and writing to) memory at 0x00100000?
You hit the nail on the head. It was overwriting parts of my kernel! I had though grub would not inlclude memory where my kernel resides in the map. I see now that was a stupid assumption; of course i'm going to want to consider the memory my kernel consumes as "free".
I put a check in my code to prevent overwriting the kernel and it works perfectly now. Thanks!
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 9:39 am
by Brendan
Hi,
mmurfin87 wrote:Brendan wrote:Which area of memory contains the code that is freeing (and writing to) memory at 0x00100000?
You hit the nail on the head. It was overwriting parts of my kernel! I had though grub would not include memory where my kernel resides in the map. I see now that was a stupid assumption; of course i'm going to want to consider the memory my kernel consumes as "free"
The kernel's code is not the only thing you have to worry about. The kernel, any extra modules loaded by the boot loader, the multi-boot information table itself, plus anything "pointed to" by the multi-boot information table (including the memory map itself, VBE info, etc); are all marked as "free" in the memory map.
The kernel will be at 0x00100000 as this address is specified by the multi-boot specification and it should be easy for the kernel to determine how large it is. Everything else may be anywhere else (and may be scattered "randomly" all over the place), as the multi-boot specification doesn't say anything about where they could be. This means that (until you've made sure things are safe) you can't use any RAM marked as "free" in the memory map without the risk trashing something you rely on later; and (until you've made sure things are safe) the only RAM that you can safely write to is RAM in the kernel's ".bss" area.
The first thing your kernel has to do is setup a stack in it's own ".bss" area (to make sure your stack doesn't trash anything). Then, for any data that you will need later; you can either copy it to a safe place in the kernel's ".bss" area, or avoid it when initialising your memory management.
For example; you might copy/store any information from the multi-boot information tables you need into your ".bss" (including the memory map); then change areas that are still in use (by your kernel and any extra modules) from "free" to "in use" in (your copy of) the memory map; then use your own memory map to initialise your memory management.
Cheers,
Brendan
Re: Writing to Address 0x104000
Posted: Wed Oct 10, 2012 5:42 pm
by Kazinsal
requimrar wrote:I'm sorry, but GRUB doesn't support linking below 1M. So there.
Probably because there's a bunch of memory holes below 1M. IVT, BDA, EBDA, everything between 640K and 1M... You get 638.75 KB at best, and that's assuming the machine's old enough to not have an EBDA (which is /generally/ 1KB, but I've used AMI BIOSes where it's a whopping 16 KB). Not really a whole lot of room for a decently sized kernel.
Re: Writing to Address 0x104000
Posted: Thu Oct 11, 2012 12:18 am
by zhiayang
Blacklight wrote:requimrar wrote:I'm sorry, but GRUB doesn't support linking below 1M. So there.
Probably because there's a bunch of memory holes below 1M. IVT, BDA, EBDA, everything between 640K and 1M... You get 638.75 KB at best, and that's assuming the machine's old enough to not have an EBDA (which is /generally/ 1KB, but I've used AMI BIOSes where it's a whopping 16 KB). Not really a whole lot of room for a decently sized kernel.
Well there we go.
Re: Writing to Address 0x104000
Posted: Thu Oct 11, 2012 3:55 am
by egos
GRUB 2 (I was using 1.98 for testing) can load kernel into base memory but it doesn't control size of the kernel. It can't load large kernel (not only exceeding EBDA base but and smaller). Instead a fault happens. Because of it and because legacy GRUB doesn't support such loading I use load_addr 0x100000 and then relocate kernel image to its native starting position at 0x8000. By the way, mboot from syslinux package is loading kernel into base memory perfectly.