The Cell architecture uses a technique known as Logical Partioning to execute and isolate different OS regions to prevent them from interfering with one another. Testing using Hypervisor calls such as lv1_allocate_memory and lv1_map_device_mmio_region has revealed the algorithm used to calculate the addresses of logical partition regions. This knowledge could prove useful when examining regions allocated by the Hypervisor as the logical partition address can be used to determine the size of the allocated region and indicate with respect to the uptime of the OS as to when the allocation took place.
A logical partition address is derived from the requested region size and a counter that is incremented with each allocation. The address itself comprises two parts, the Base and the Counter.
Address = 0xbbccccccc000, where bb = Base and ccccccc = Counter
Allocating consecutive regions of the same size returns a consistent pattern of addresses - each is offset from the previous by the size of the region rounded up to the nearest power of two. Furthermore, allocating regions of differing sizes results in addresses that indicate that the allocation algorithm is based upon an incrementing counter multiplied by the rounded region size.
Addresses are not (initially) reused, as freeing a region before the next allocation of the same size returns the next address in the sequence. Interestingly, when the upper limit of an address region is reached (e.g. 0x33fffffff000 for 0×1000 byte allocations) the address rolls back to the initial base address (e.g. 0×300000000000), though the addresses of any regions that have not been released are NOT reused, suggesting that the algorithm also keeps track of allocated regions.
The address base is determined by the size of the allocated region:
| Region Size | Base |
|---|---|
| 0×1000 | 0×30 - 0×33 |
| 0×2000 | 0×34 - 0×37 |
| 0×3000 - 0×4000 | 0×38 - 0x3b |
| 0×5000 - 0×8000 | 0x3c - 0x3f |
| 0×9000 - 0×10000 | 0×40 - 0×43 |
| 0×11000 - 0×20000 | 0×44 - 0×47 |
| 0×21000 - 0×40000 | 0×48 - 0x4b |
| 0×41000 - 0×80000 | 0x4c - 0x4f |
| 0×81000 - 0×100000 | 0×50 - 0×53 |
| 0×101000 - 0×200000 | 0×54 - 0×57 |
| 0×201000 - 0×400000 | 0×58 - 0x5b |
| 0×401000 - 0×800000 | 0x5c - 0x5f |
| 0×801000 - 0×1000000 | 0×60 - 0×63 |
| 0×1001000 - 0×2000000 | 0×64 - 0×67 |
| 0×2001000 - 0×4000000 | 0×68 - 0x6b |
| 0×4001000 - 0×8000000 | 0x6c - 0x6f |
| 0×8001000 - 0×10000000 | 0×70 - 0×73 |
The allocator also appears to be memory agnostic - addresses for DDR allocation are in sequence with XDR allocations.
Here is a simple calculator that can convert between size and counter values to addresses and vice versa.
Note that the calculator does not perform any error checking for invalid values and will generate incorrect values for rolled over addresses (though is not very likely that these will occur in regular usage). The code is slightly convoluted as Javascript does not handle 64 bit numbers well.