2011年7月26日 星期二

[Linux Kernel] Allocate memory buffer whose starting address is aligned with the specific memory size

撰寫裝置驅動程式時, 常常會因為硬體需求, 需配置一塊記憶體空間用來映射至硬體的I/O或記憶體空間, 且此已配置記憶體空間的起始位址往往都必須對齊某一固定大小的記憶體。舉例來說,欲配置4906位元的記憶體空間,且起始位址需對齊16位元。底下為C語言範例程式。

void *memory_align(unsigned int size, unsigned int aligned_size)

{
void *ptr;

unsigned int mask = ~(aligned_size -1);

if((ptr = malloc(sizeof(size + (aligned_size - 1)))) == NULL) {
perror("memory allocation failed");
return NULL;
}

ptr = (void *) ((unsigned int) (ptr + (aligned_size - 1)) & mask);

return ptr;
}


unsigned int mask = ~(aligned_size -1);
此mask變數為位元遮罩, 假設aligned_size=16, 則mask=0xFFFFFFF0

ptr = malloc(sizeof(size + (aligned_size - 1)))
由於我們欲讓所配置的記憶體起始位址對齊aligned_size, 所以需向系統配置size+(aligned_size - 1)大小的記憶體空間

ptr = (void *) ((unsigned int) (ptr + (aligned_size - 1)) & mask);
把所配置的記憶體起始位址加上(aligned_size - 1),然後跟mask變數做位元遮罩,如此便能取得正確的記憶體起始位址

下圖為詳細範例計算