CRoemheld wrote:- In the screenshot in the OP you can see that at address 0x00100000 there's a free memory region. However, right now the length of this area changed, from 0x3FEF0000 to 0x07EE0000. Is this always random, depending on what address the memory hole in the upper memory is showing up?
Are you sure that you haven't reconfigured Bochs in the meantime. The hole, wherever it is, should not just eat so much remaining physical space. I am not sure if the layout is always consistent in practice, but it should roughly correspond to the physically (or virtually) available resources.
In this context, lets also clarify that the free memory reported by GRUB (derived from int 15, e820 for BIOS) is not entirely free. This is the memory that a PnP protected mode OS can use. But a PnP protected mode OS could reconfigure the memory mapped IO of the PCI devices to desirable non-conflicting addresses. One can still presume that for backward compatibility, the area between 0x500 and 0xA0000 is free for use by a real-mode boot-loader (edit: minus the EBDA area right below 0xA0000), and since GRUB has already switched you to protected mode, anything below 0xA0000 (minus the EBDA area) is free . One could also hope that the BIOS has tried to configure the MMIO devices either inside the 0xA0000 to 0x100000 range (for legacy VGA) or in spaces that are not reported by 0xe820. To cut the story short, mark the region 0xA0000 to 0x100000 as unavailable in your memory map, and prey that nothing breaks, until you have PnP facilities.
Edit: The modules and structures of GRUB itself are also not reflected in the memory map. So, you have to be careful not to overwrite them while you still need them. How you do this will depend on whether you plan to relocate them somewhere or to keep them around longer.
CRoemheld wrote:- The buddy allocator used in Linux uses a maximum order of 10, meaning the biggest available block would be 2^10 * 4096 Bytes = 4MiB in size. However, The first free memory area in lower memory has a size of 639KiB, and the free area in upper memory is 129920KiB in size. Would I need to split up the upper memory area into smaller blocks of 4 MiB and use multiple lists to keep track of the allocations? With point 1: if the size of free memory is not constant, how does the allocator change?
Even with the standard buddy system you will need multiple lists to keep track of the free blocks. But the idea here is not to limit the maximum block size or use separate allocator per memory range. Let me return to my primitive example.
This time suppose that the available memory range is for pages 3-13 (zero based, exclusive at the end, 12 is the last valid page). Let's denote a busy (allocated) buddy block of size X pages as BX, and a free budy block of size X pages as FX. Also, lets assume that your maximum buddy block is 16 pages in size. Essentially, you first need to create a maximally sized buddy block that covers the entire range with good alignment. In this case, we need one F16 block that covers the range 0-16. And then we have to break it up into configuration that covers the gaps with busy blocks. In this case the target configuration is B2,B1,F1,F4,F4,F1,B1,B2. As you can see, the allocator end up still managing the entire 16 pages, but now has marked the gaps on the two sides as busy blocks. If the gap is very big, in the trivial implementation, you could end up with a single B16. To track the state of the entire memory like this, you need one frame record per page frame, whether available or unavailable. If you can tolerate this inefficiency, good. If not, you have to make your page frame database a two-level structure, as I already mentioned in my posts. The first level will describe the memory in larger chunks, say 4MB (if you want to match the allocator's maximum block size), and will denote whether they contain usable memory or not. The second level will be a small per-chunk page frame database, only for chunks that have at least one available free frame (or some other threshold.)
You need to implement special allocation routine, e.g. that is parametrized by starting and ending address or something of the sorts (edit: so that you can direct it where to cut the "gap", allocating exactly that range), rather than just by desired block size. You also can give the unavailable blocks a special state if you like to distinguish them from normally allocated blocks.
P.S.: You could also simplify your life and admit to a little inefficiency by rounding all available memory to 4MB boundaries. For new systems, it is not such a great loss and you won't have to break partial blocks. You will still need to think about handling the large gaps with two-level structure, if you wish to support systems with very fragmented physical address space.
CRoemheld wrote:- I am also looking for code examples, because as of now I haven't found a shred of code or even tutorial which uses the buddy allocation system in connection with the free memory areas listed by the multiboot info structs mmap_* fields , but instead simply start allocating pages after the end of the kernel (by defining a variable in the linker script and access it via an external declared variable in C). So this point is the main objective of my question here: How to I setup a buddy allocator which uses the memory areas listed in the screenshot above and how does it deal with regions in memory, which are much larger than 2^10 * 4096 Bytes?
For this particular setup, I am not aware of any other public source aside from Linux. There may be others in the Unixes. But pointing you to the sources of a full blown OS would be a bad joke.