3.4.2 아키텍처별 설정(二): 메모리 초기화 단계
메모리에 불러왔고 초기화된 어셈블리 프로그램 부분이 실행된 후에 메모리는 시스템에 특정한 절차를 수행해야 합니까?그림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);
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.