Page 1 of 1
Physical mem alloc
Posted: Mon Feb 25, 2008 4:28 pm
by Beastie
hi,
I'm currently using a bitmap for my physical mem. allocation, I've a question regarding this.
Where should i put the bitmap, should i use a predefined region as 0x600000 or should i allocate it in the BSS, or should i dynamically search the mem. map and find out how much mem. I've then alloc. the space for the bitmap by hand and mark it as allocated later.
I know that Linux uses a buddy system but where it saves the allocator data ?????
Re: Physical mem alloc
Posted: Mon Feb 25, 2008 7:06 pm
by Jef
Beastie wrote:Where should i put the bitmap, should i use a predefined region as 0x600000 or should i allocate it in the BSS, or should i dynamically search the mem. map and find out how much mem. I've then alloc. the space for the bitmap by hand and mark it as allocated later.
At my OS i have put the memory manager map at 400000h.
While the initialization of memory manager (that must be at the very start of OS load, e.g. Just after entering PMode) i cleanup the memory map area (size 0FFFFFh) and then i set that this area is used.
After that the "my_malloc" can be called to allocate memory.
Just keep in mind that some other areas are already used (BIOS, VGA RAM, etc), so remember to "set" as allocated before memory manager init ends.
Posted: Sat Mar 01, 2008 5:19 pm
by Assembler
Hello,
Once before I had a conversation with Kirk McKusick regarding the design of a physical memory manager. Here is what he says:
I would recommend doing something similar to what the FreeBSD does.
At boot time you know the amount of physical memory available on the
machine. Deduct the amount dedicated to the kernel and allocate space
in the kernel's address space to describe the remaining memory.
FreeBSD allocates a vmpage structure to describe each page and a
base-and-bound bitmap to describe their allocation (which allows for
quick allocation lookup for first-best-fit). If you wish to pursue
this approach, I highly recommend that you read chapter 5 of my
textbook ``The Design and Implementation of the FreeBSD Operating
System.''
Kirk McKusick
Thanks.
Posted: Sat Mar 01, 2008 10:32 pm
by essial
I use GRUB to load my kernel, compile an gzip'd elf kernel, and have the linker set to load the kernel at 0x100000 (1meg). The kernel runs managed applications, so the kernel is mapped to all of ram. Here is my linker script:
Code: Select all
OUTPUT_FORMAT("elf32-i386")
ENTRY(_start)
phys = 0x00100000; /* 1 meg */
SECTIONS
{ .text phys : AT(phys)
{ code = .;
*(.text)
. = ALIGN(4096);
}
.data : AT(phys + (data - code))
{ data = .;
*(.data)
. = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{ bss = .;
*(.bss)
*(COMMON)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
When my memory manager starts up, I loop through the memory map grub provides me (which is most likely the same thing that you have). I have a fixed length table (16k worth) of information about what memory is mapped where. Each user-usable block of memory I encounter, I add an entry to that table. During the course of adding the record, I check the base address and length to determine if the kernel is located inside of that memory block. If it is, I do simple math to adjust the map to either end before, or start after the block (or disregard the block if it happens to be the exact same size). I do that by using the "end" and "phys" variables from my linker script:
Code: Select all
extern void* end;
extern void* phys;
...
// Adjust the memory block if it begins inside of the kernel block
if ( (MemBlock[i].Base >= (unsigned long)&phys) && (MemBlock[i].Base <= (unsigned long)&end) )
{
// This block starts inside of kernel memory, so first get the amount we must remove
unsigned long rAmt = MemBlock[i].Base - (unsigned long)&phys;
// Add the removed amount to the base, and subtract it from the length
MemBlock[i].Base += rAmt;
MemBlock[i].Length -= rAmt;
}
// Adjust the memory block if it ends inside of the kernel block
if ( ((MemBlock[i].Base+MemBlock[i].Length) >= (unsigned long)&phys) && ((MemBlock[i].Base+MemBlock[i].Length) <= (unsigned long)&end) )
{
// This block ends inside of kernel memory, so first get the amount we must truncate
unsigned long rAmt = (MemBlock[i].Base+MemBlock[i].Length)- (unsigned long)&end;
// Now we simply subtract it from the length of the map
MemBlock[i].Length -= rAmt;
}
After that point, I can use whatever memory I have in my table.
As far as your memory map table, you can either go my route, and use a constant array, or you can just have an array of maby 15 elements (just to be safe) to store the initial user memory, minus where the kernel is.
Posted: Mon Mar 03, 2008 1:42 am
by Ready4Dis
Physical memory manager... well, for memory that doesn't have to be contiguous (pretty much anyhing over 16mb if you plan on supporting ISA devices, if no ISA support is required or desired, you can just use things above 1mb or so). Anyways... in mine, I barely use any memory at all for storing the pages. I use a linked list type structure like so:
Each physical page has an entry pointing to the next physical page. I save the first page in the list in a variable. So, on allocation, I grab the page pointed to in the variable, read it's first 4-bytes (pointer to the next free page) and store it to my "first page" variable and hand the page off to whatever asked for it. On de-allocation, I simply write the first 4-bytes with the first page variable, and point the first page variable to the just reelased page. The benefit is, when all memory is allocated, I am using almost zero memory, even if nothing is allocated, I don't have to set any additional memory aside. I simply initialize it on boot-up, and let it run from then on out
. Now, for memory under 1mb I reserve for use with legacy devices and such, other than that. After receiving the memory table from the bios, I just loop through and mark each page as required.