본문 바로가기

Programming/Linux_Kernel

kernel 초기화시 지켜야 할 Ram memory size align 단위


kernel 2.6.32

kernel 초기화시 각 영역별로 ram memory 를 잡게 됩니다.
이러한 메모리들은 bank 에 저장되어서 start_kernel 에서 bootmem_init 을 호출하여 초기화 하게 되지요.

조금 더 정확하게 적자면 다음과 같이 boot param 을 bootloader에서 kernel로 전달되게 되면

"meminfo=mem=80M mem=253M@0x40000000 mem=128M@0x50000000"

parse_cmdline 에서 early_mem 함수를 호출하여서 해당 구문을 해석하고 arm_add_memory 를 호출합니다.
arm_add_memory 는 bank 구조체에 해당 정보를 채우게 되지요.


    meminfo = (
    nr_banks = 0x3,
    bank = (
      (start = 0x30000000, size = 0x04FC0000, node = 0x0, highmem = 0x0),
      (start = 0x40000000, size = 0x0FD00000, node = 0x1, highmem = 0x0),
      (start = 0x50000000, size = 0x08000000, node = 0x2, highmem = 0x0),
      (start = 0x0, size = 0x0, node = 0x0, highmem = 0x0),
      (start = 0x0, size = 0x0, node = 0x0, highmem = 0x0),
      (start = 0x0, size = 0x0, node = 0x0, highmem = 0x0),
      (start = 0x0, size = 0x0, node = 0x0, highmem = 0x0),
      (start = 0x0, size = 0x0, node = 0x0, highmem = 0x0)))


이렇게 채워둔 bank 정보는 다음 함수 스택을 통해서 각각 ram영역 을 할당받게 됩니다.

start_kernel -> setup_arch -> paging_init -> bootmem_init -> bootmem_free_node -> free_area_init_node -> alloc_node_mem_map -> __alloc_bootmem_node -> ___alloc_bootmem_node -> alloc_bootmem_core

(남색으로 표시한 함수들은 다른 함수로 교체 될 수 있습니다.)

위의 bank정보는 3개의 메모리를 잡은 예제 입니다. 그중 첫번 째 node 는 17M 768KB 를 잡고 있습니다.
이럴경우 애러가 발생하게 되는데
printk 는 ram 초기화 이후에 정상동작하므로 Serial 상에서는 애러를 확인할 수 없습니다.
(이 부분에 대해서는 printk에서 사용하는 buffer 를 reserved area 로 변경하여서 초기 초기화 하는 방법등을 사용하면 좋을것 같습니다.)

애러는 실제 메모리를 mapping 하는 곳에서 발생하며 위치는 다음과 같습니다.

 bootmem_init() -> create_mapping() --> create_mapping()

void __init create_mapping(struct map_desc *md)
{
...
    addr = md->virtual & PAGE_MASK;                                       // addr = 0xC000 0000
    phys = (unsigned long)__pfn_to_phys(md->pfn);                   // phys = 0x3000 0000
length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK)); // length = 0x04FC 0000
...
if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
  printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
         "be mapped using pages, ignoring.\n",
         __pfn_to_phys(md->pfn), addr);
  return;
 }
...
alloc_init_section(pgd, addr, next, phys, type);
...
}


색션의 size 는 1M 이므로 그 이하 단위의 메모리를 할당하려고 하면 애러가 발생하고 실질적인 alloc 가 발생하지 않게됩니다.

bootloader 에서 넘기는 kernel param에 대해서 kernel document 에 보면 M와 k 단위까지 지원한다고 나와있는데 k단위를 사용한다면 이 부분에서 애러가 발생할듯 합니다.
이 부분이 모순되는데 왜 이렇게 구현되었는지는 조금 더 분석해 보아야 할것 같군요.

Test 결과 2.6.32 버전의 Kernel 에서는

meminfo=mem=81408K mem=253M@0x40000000 mem=128M@0x50000000

이렇게 셋팅했을때 위와 같은 문제로 인해서 부팅이 되지 않습니다. (81408K 는 19M 512K)
따라서 반드시 M 단위만 사용하시기 바랍니다.