3.4.2 아키텍처별 설정(二): 메모리 초기화 단계

14174 단어
초기화 단계
메모리에 불러왔고 초기화된 어셈블리 프로그램 부분이 실행된 후에 메모리는 시스템에 특정한 절차를 수행해야 합니까?그림3-12는 각 조작의 코드 흐름도를 보여 준다.
 
start_kernel
->setup_arch
  ->machine_specific_memory_setup
  ->setup_memory
  ->paging_init
    -> free_area_init
      ->free_area_init_node
(1) 우선 machine 호출specific_memory_setup(3.18.3 버전은 setup arch에서 직접 완성되었고machine specific memory setup을 취소했습니다. 이 함수는 2.6.24 참조할 수 있는 체인 테이블을 만들었습니다. 시스템이 메모리와 빈 메모리를 차지하는 것을 포함합니다.IA-32 가족의 각 하위 체계 구조에서 이 정보를 얻는 방식이 약간 다르기 때문에 내부 핵은 기계에 특정한 함수를 제공하고include/asm-x86/mach-type/setup에 정의한다.c에서 type은default,voyager,visws일 수 있습니다.여기서는default의 상황만 토론합니다.
BIOS에서 제공하는 매핑은 이러한 상황에서 사용되는 각 메모리 영역을 보여줍니다. 시스템이 시작될 때 찾은 메모리 영역은 커널 함수 printmemory_맵 표시.
static void __init print_memory_map(void)
{
        int i;
        const int field = 2 * sizeof(unsigned long);
 
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                printk(KERN_INFO " memory: %0*Lx @ %0*Lx ",
                       field, (unsigned long long) boot_mem_map.map[i].size,
                       field, (unsigned long long) boot_mem_map.map[i].addr);
 
                switch (boot_mem_map.map[i].type) {
                case BOOT_MEM_RAM:
                        printk(KERN_CONT "(usable)
"); break; case BOOT_MEM_INIT_RAM: printk(KERN_CONT "(usable after init)
"); break; case BOOT_MEM_ROM_DATA: printk(KERN_CONT "(ROM data)
"); break; case BOOT_MEM_RESERVED: printk(KERN_CONT "(reserved)
"); break; default: printk(KERN_CONT "type %lu
", boot_mem_map.map[i].type); break; } } }

인쇄된 정보는 다음과 같습니다.
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009c7ff] usable
[    0.000000] BIOS-e820: [mem 0x000000000009c800-0x000000000009ffff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000001fffffff] usable
[    0.000000] BIOS-e820: [mem 0x0000000020000000-0x00000000200fffff] reserved
[    0.000000] BIOS-e820: [mem 0x0000000020100000-0x000000006d590fff] usable
[    0.000000] BIOS-e820: [mem 0x000000006d591000-0x000000006d5c0fff] reserved
[    0.000000] BIOS-e820: [mem 0x000000006d5c1000-0x000000006d5d0fff] ACPI data
[    0.000000] BIOS-e820: [mem 0x000000006d5d1000-0x000000006d715fff] ACPI NVS
[    0.000000] BIOS-e820: [mem 0x000000006d716000-0x000000006da79fff] reserved
[    0.000000] BIOS-e820: [mem 0x000000006da7a000-0x000000006da7afff] usable
[    0.000000] BIOS-e820: [mem 0x000000006da7b000-0x000000006dabcfff] reserved
[    0.000000] BIOS-e820: [mem 0x000000006dabd000-0x000000006dc2afff] usable
[    0.000000] BIOS-e820: [mem 0x000000006dc2b000-0x000000006dff9fff] reserved
[    0.000000] BIOS-e820: [mem 0x000000006dffa000-0x000000006dffffff] usable
[    0.000000] BIOS-e820: [mem 0x00000000e00f8000-0x00000000e00f8fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000fed01000-0x00000000fed01fff] reserved
[    0.000000] BIOS-e820: [mem 0x00000000ffb00000-0x00000000ffffffff] reserved
BIOS가 정보를 제공하지 않으면 커널 자체에서 테이블을 생성하여 0-640KB 및 1MB 이전의 메모리를 사용 가능한 것으로 표시합니다.
(2) 내부 핵 다음 호출parsecmd_early(이것은 3.18.3에서 대체되고 setup arch에서 직접 실현되며 2.6.24) 분석 명령줄을 참조할 수 있습니다. 주로 mem=xxx,highmem=xxx 또는memmap=xxxx와 같은 매개 변수를 주목합니다.커널에서 계산된 값 또는 BIOS에서 제공한 값이 정확하지 않으면 관리자는 사용 가능한 메모리의 수를 수정하거나 수동으로 메모리 영역을 지정할 수 있습니다.이 옵션은 오래된 컴퓨터에만 적용됩니다.Highmem- 감지된 하이엔드 메모리 영역의 길이를 수정할 수 있습니다.그것은 메모리가 매우 큰 컴퓨터에 사용되어 사용 가능한 메모리의 수량을 제한할 수 있다. 왜냐하면 큰 메모리는 때때로 성능을 떨어뜨릴 수 있기 때문이다.
(3) 다음 주요 단계는 setupmemory에서 실행됩니다.주요 기능
A. 사용 가능한 물리적 메모리 수 결정
B. bootmem 분배기 초기화
C. 첫 번째 사용자 공간 프로세스를 실행하는 데 필요한 최초의 RAM 디스크와 같은 다양한 메모리 영역을 할당합니다.
setup_memory(void *kernel_end)
{
        struct memclust_struct * cluster;
        struct memdesc_struct * memdesc;
        unsigned long start_kernel_pfn, end_kernel_pfn;
        unsigned long bootmap_size, bootmap_pages, bootmap_start;
        unsigned long start, end;
        unsigned long i;
 
        /* Find free clusters, and init and free the bootmem accordingly.  */
        memdesc = (struct memdesc_struct *)
          (hwrpb->mddt_offset + (unsigned long) hwrpb);
 
        for_each_mem_cluster(memdesc, cluster, i) {
                printk("memcluster %lu, usage %01lx, start %8lu, end %8lu
", i, cluster->usage, cluster->start_pfn, cluster->start_pfn + cluster->numpages); /* Bit 0 is console/PALcode reserved. Bit 1 is non-volatile memory -- we might want to mark this for later. */ if (cluster->usage & 3) continue; end = cluster->start_pfn + cluster->numpages; if (end > max_low_pfn) max_low_pfn = end; } /* * Except for the NUMA systems (wildfire, marvel) all of the * Alpha systems we run on support 32GB of memory or less. * Since the NUMA systems introduce large holes in memory addressing, * we can get into a situation where there is not enough contiguous * memory for the memory map. * * Limit memory to the first 32GB to limit the NUMA systems to * memory on their first node (wildfire) or 2 (marvel) to avoid * not being able to produce the memory map. In order to access * all of the memory on the NUMA systems, build with discontiguous * memory support. * * If the user specified a memory limit, let that memory limit stand. */ if (!mem_size_limit) mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT; if (mem_size_limit && max_low_pfn >= mem_size_limit) { printk("setup: forcing memory size to %ldK (from %ldK).
", mem_size_limit << (PAGE_SHIFT - 10), max_low_pfn << (PAGE_SHIFT - 10)); max_low_pfn = mem_size_limit; } /* Find the bounds of kernel memory. */ start_kernel_pfn = PFN_DOWN(KERNEL_START_PHYS); end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end)); bootmap_start = -1; try_again: if (max_low_pfn <= end_kernel_pfn) panic("not enough memory to boot"); /* We need to know how many physically contiguous pages we'll need for the bootmap. */ bootmap_pages = bootmem_bootmap_pages(max_low_pfn); /* Now find a good region where to allocate the bootmap. */ for_each_mem_cluster(memdesc, cluster, i) { if (cluster->usage & 3) continue; start = cluster->start_pfn; end = start + cluster->numpages; if (start >= max_low_pfn) continue; if (end > max_low_pfn) end = max_low_pfn; if (start < start_kernel_pfn) { if (end > end_kernel_pfn && end - end_kernel_pfn >= bootmap_pages) { bootmap_start = end_kernel_pfn; break; } else if (end > start_kernel_pfn) end = start_kernel_pfn; } else if (start < end_kernel_pfn) start = end_kernel_pfn; if (end - start >= bootmap_pages) { bootmap_start = start; break; } } if (bootmap_start == ~0UL) { max_low_pfn >>= 1; goto try_again; } /* Allocate the bootmap and mark the whole MM as reserved. */ bootmap_size = init_bootmem(bootmap_start, max_low_pfn); /* Mark the free regions. */ for_each_mem_cluster(memdesc, cluster, i) { if (cluster->usage & 3) continue; start = cluster->start_pfn; end = cluster->start_pfn + cluster->numpages; if (start >= max_low_pfn) continue; if (end > max_low_pfn) end = max_low_pfn; if (start < start_kernel_pfn) { if (end > end_kernel_pfn) { free_bootmem(PFN_PHYS(start), (PFN_PHYS(start_kernel_pfn) - PFN_PHYS(start))); printk("freeing pages %ld:%ld
", start, start_kernel_pfn); start = end_kernel_pfn; } else if (end > start_kernel_pfn) end = start_kernel_pfn; } else if (start < end_kernel_pfn) start = end_kernel_pfn; if (start >= end) continue; free_bootmem(PFN_PHYS(start), PFN_PHYS(end) - PFN_PHYS(start)); printk("freeing pages %ld:%ld
", start, end); } /* Reserve the bootmap memory. */ reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size, BOOTMEM_DEFAULT); printk("reserving pages %ld:%ld
", bootmap_start, bootmap_start+PFN_UP(bootmap_size)); #ifdef CONFIG_BLK_DEV_INITRD initrd_start = INITRD_START; if (initrd_start) { initrd_end = initrd_start+INITRD_SIZE; printk("Initial ramdisk at: 0x%p (%lu bytes)
", (void *) initrd_start, INITRD_SIZE); if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) { if (!move_initrd(PFN_PHYS(max_low_pfn))) printk("initrd extends beyond end of memory " "(0x%08lx > 0x%p)
disabling initrd
", initrd_end, phys_to_virt(PFN_PHYS(max_low_pfn))); } else { reserve_bootmem(virt_to_phys((void *)initrd_start), INITRD_SIZE, BOOTMEM_DEFAULT); } } #endif /* CONFIG_BLK_DEV_INITRD */ }

                                                                                                                     
(4)paging_IA-32 컴퓨터에서는 기본적으로 페이지가 비활성화되어 있기 때문에, 컴퓨터가 PAE를 컴파일하고 프로세서가 Execute Disable Protection을 지원할 경우 이 기능을 사용합니다.페이지탭 호출을 통해init, 이 함수는 내장 주소 공간에 직접 비치는 물리적 메모리를 초기화합니다.로우엔드 메모리의 모든 페이지 프레임이 PAGE 에 직접 매핑됨OFFSET 위의 가상 메모리 영역이것은 내부 핵이 페이지 테이블을 처리하지 않아도 상당 부분의 사용 가능한 메모리를 찾을 수 있게 한다.
void __init paging_init(void)
{
        unsigned long zones_size[MAX_NR_ZONES] = {0, };
        unsigned long dma_pfn, high_pfn;
 
        dma_pfn = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
        high_pfn = max_pfn = max_low_pfn;
        
        if (dma_pfn >= high_pfn)
                zones_size[ZONE_DMA] = high_pfn; 
        else {
                zones_size[ZONE_DMA] = dma_pfn;
                zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
        }
        
        /* Initialize mem_map[].  */
        free_area_init(zones_size);
 
        /* Initialize the kernel's ZERO_PGE. */
        memset((void *)ZERO_PGE, 0, PAGE_SIZE);
}

(5)Zone_sizes_init(3.18.3에 존재하지 않음,paging init에 통합됨), 시스템의 모든 결점 pgdat 초기화t의 실례.우선 add 사용active_range, 사용 가능한 물리 메모리에 대해 비교적 간단한 목록을 만듭니다.아키텍처와 무관한 함수freearea_init_des는 다음에 이 정보를 사용하여 완비된 내부 핵 데이터 구조를 구축합니다.이것은 내부 핵이 실행될 때 페이지 프레임을 관리하는 매우 중요한 절차이다.
void __init free_area_init(unsigned long *zones_size)
{       
        free_area_init_node(0, zones_size,
                        __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL);
}  
void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
                unsigned long node_start_pfn, unsigned long *zholes_size)
{
        pg_data_t *pgdat = NODE_DATA(nid);
        unsigned long start_pfn = 0;
        unsigned long end_pfn = 0;
 
        /* pg_data_t should be reset to zero when it's allocated */
        WARN_ON(pgdat->nr_zones || pgdat->classzone_idx);
 
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
        printk(KERN_INFO "Initmem setup node %d [mem %#010Lx-%#010Lx]
", nid, (u64) start_pfn << PAGE_SHIFT, (u64) (end_pfn << PAGE_SHIFT) - 1); #endif calculate_node_totalpages(pgdat, start_pfn, end_pfn, zones_size, zholes_size); alloc_node_mem_map(pgdat); #ifdef CONFIG_FLAT_NODE_MEM_MAP printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx
", nid, (unsigned long)pgdat, (unsigned long)pgdat->node_mem_map); #endif free_area_init_core(pgdat, start_pfn, end_pfn, zones_size, zholes_size); }

좋은 웹페이지 즐겨찾기