Help with mapping bits to pages in buddy memory allocator
Posted: Sun Mar 15, 2015 11:22 pm
Hi,
I've created my own buddy allocator with a bitmap, with each bit corresponding to a page block of particular size.
Since I map the whole 4GiB address space, logically the 1st bit would represent a 4GiB block, the next two bits will represent blocks of 2GiB, the next four bits will represent blocks of 1GiB and so on until we reach just single blocks of 4KiB (page size).
Getting the children of a bit would be as simple as noting the bit position, bitN, and:
leftNode = bitN * 2
rightNode =bitN * 2 + 1
Getting the parent of any bit would be bitN / 2.
In a sense, the whole bitmap would look like:
I can map unique physical addresses for each block of identical size, but because of the way this scheme is employed, the addresses will overlap, meaning that the same physical address can be returned, for example, for a 4KiB block or a 16KiB block. This is true especially for bit numbers that are power of 2 -- bits 1, 2, 4, 8, etc. will always point to the leftmost physical block, which is address 0. Bits 3, 6, 12, 24, etc. will also always point to the same block beginning at address 2GiB, but this block may be of any (valid) size!
A good example output would be:
As you can see, with this implementation the same address can point to a block of any size and I want to know how to get this block size so I can index into the bitmap and start merging buddies. But I've spent hours trying to figure out how to do this reverse mapping of finding the bit from the bitmap that corresponds to the address!
I don't have problems allocating any number of pages and I get unique addresses back, but I don't know how to index back into the bitmap once I have to free them!
Any ideas how to go about this?
I've created my own buddy allocator with a bitmap, with each bit corresponding to a page block of particular size.
Since I map the whole 4GiB address space, logically the 1st bit would represent a 4GiB block, the next two bits will represent blocks of 2GiB, the next four bits will represent blocks of 1GiB and so on until we reach just single blocks of 4KiB (page size).
Getting the children of a bit would be as simple as noting the bit position, bitN, and:
leftNode = bitN * 2
rightNode =bitN * 2 + 1
Getting the parent of any bit would be bitN / 2.
In a sense, the whole bitmap would look like:
Code: Select all
bit number: [1] [2 3] [4 5 6 7] [8 9 10 11 12 13 14 15] [16 ... etc.]
holds block: 4G 2G 1G 512M 256M - 4KiB
A good example output would be:
Code: Select all
(assume address 0 is valid and isn't considered NULL for the sake of the example)
allocate(1) -- allocate 1 page, returns address 0x00000000. Valid usable range is 0-4095 (0x00000000 - 0x00001000).
allocate(524288) -- allocate 512k pages (2GiB), returns address 0x80000000. Valid usable range is 0x80000000-0xFFFFFFFF.
free((uint32_t *)0) -- free address 0. Page is reclaimed and merged with its free buddies.
allocate(16) -- allocate 16 pages, returns address 0x00000000! Same address but now with a bigger usable range of 0-65535!
I don't have problems allocating any number of pages and I get unique addresses back, but I don't know how to index back into the bitmap once I have to free them!
Any ideas how to go about this?