2013-07-11 2 views
1

리눅스를 처음 사용하고 Linux가 avaible Physical Mmeory에 대해 알게 된 방법에 대해 알고 있습니다. BIOS 시스템 콜 int 0x15가 있으며 E20 메모리 맵을 제공합니다.EFI 메모리 맵을 E820 맵으로 변환

이제 EFI 메모리 맵을 E820 메모리 맵으로 변환하는 데 대한 정의가있는 코드 조각을 찾습니다. 위의 내용은 무엇입니까 ??

그것은 기저의 마더 보드의 펌웨어는 EFI를 기반으로 의미하지만,이 코드는 86에서 실행하기 때문에 우리는 그렇다면 E820 메모리 맵

로 변환 할 필요가, 86 만 E820의 메모리 맵에 대해 알고합니까?

E820과 EFI 메모리 맵의 차이점은 무엇입니까 ??

앞으로도 자세한 답변을 찾으십시오.

답변

5

두 경우 모두 실제로 꽂혀있는 메모리 (및 얼마)를 감지 할 책임이있는 펌웨어 (BIOS 또는 EFI)와이 정보를 알아야하는 운영 체제가 입니다 형식은입니다.

는 기저의 마더 보드의 펌웨어는 EFI를 기반으로하지만,이 코드는 86에서 실행하기 때문에 우리가 E820 메모리 맵으로 변환 할 필요가 의미

여기에 귀하의 혼란은 EFI 및 x86 호환되지 않는 점이다 - 그들은 때로 믿을 수 '티. EFI 펌웨어에는 사용 가능한 메모리보고를위한 자체 메커니즘이 있습니다. 특히 ExitBootServices을 호출하기 전에 GetMemoryMap 부팅 서비스를 사용하여 펌웨어에서 메모리 맵을 검색 할 수 있습니다. 그러나 비판적으로이 메모리 맵은 EFI 펌웨어가 E820이 아니라보고하고자하는 형식 (EFI_MEMORY_DESCRIPTOR)으로되어 있습니다. 이 시나리오에서는 필요한 정보가 이미 있으므로 int 15h도 시도하지 않습니다.

Linux 커널이 x86 아키텍처에서 메모리의 내부 표현으로 E820 형식을 사용하는 것으로 의심됩니다. 그러나 EFI를 부팅 할 때 커널은 EFI 펌웨어 부트 서비스를 사용해야하지만 E820 형식으로 돌아 오는 응답을 변환하도록 선택합니다.

작성하고있는 커널에는 필요하지 않습니다. 당신은 단순히 메모리가 매핑되는 방법을 알아야합니다.

일부 부트 로더가이 정보를 제공하는 경우도 있습니다 (예 : GRUB). 멀티 부트 스펙의 일부는 커널에이 정보를 제공해야한다는 것을 부트 로더에게 지시 할 수있게합니다.

더 많은 정보를 원하면 osdev wiki에는 코드 샘플 등이 있습니다. grub에서 메모리 맵을 가져 오는 관련 섹션은 here입니다.

또한 포인트는 :

OS는 여러 가지 이유로 곳 매핑되는 어떤 메모리 이해할 필요가있다. 하나는 펌웨어 서비스가 상주하는 물리적 메모리 사용을 피하는 것이고 다른 하나는 CPU와 메모리를 공유하는 장치와의 통신을위한 것입니다. 비디오 버퍼는 이것의 일반적인 예입니다.

둘째, EFI에서 메모리 맵을 나열하는 것이 그리 어렵지 않습니다.아직 발견하지 못했다면, 펌웨어가 포함 된 UEFI 쉘은 메모리 맵을 표시하는 명령이 memmap입니다. 직접 구현하려는 경우 다음과 같이 빠르고 간단하게 수행 할 수 있습니다.

EFI_STATUS EFIAPI PrintMemoryMap(EFI_SYSTEM_TABLE* SystemTable) 
{ 
    EFI_STATUS status = EFI_SUCCESS; 
    UINTN MemMapSize = sizeof(EFI_MEMORY_DESCRIPTOR)*16; 
    UINTN MemMapSizeOut = MemMapSize; 
    UINTN MemMapKey = 0; UINTN MemMapDescriptorSize = 0; 
    UINT32 MemMapDescriptorVersion = 0; 
    UINTN DescriptorCount = 0; 
    UINTN i = 0; 
    uint8_t* buffer = NULL; 
    EFI_MEMORY_DESCRIPTOR* MemoryDescriptorPtr = NULL; 

    do 
    { 
     buffer = AllocatePool(MemMapSize); 
     if (buffer == NULL) break; 

     status = gBS->GetMemoryMap(&MemMapSizeOut, (EFI_MEMORY_DESCRIPTOR*)buffer, 
      &MemMapKey, &MemMapDescriptorSize, &MemMapDescriptorVersion); 

     Print(L"MemoryMap: Status %x\n", status); 
     if (status != EFI_SUCCESS) 
     { 
      FreePool(buffer); 
      MemMapSize += sizeof(EFI_MEMORY_DESCRIPTOR)*16; 
     } 
    } while (status != EFI_SUCCESS); 

    if (buffer != NULL) 
    { 
     DescriptorCount = MemMapSizeOut/MemMapDescriptorSize; 
     MemoryDescriptorPtr = (EFI_MEMORY_DESCRIPTOR*)buffer; 

     Print(L"MemoryMap: DescriptorCount %d\n", DescriptorCount); 

     for (i = 0; i < DescriptorCount; i++) 
     { 
      MemoryDescriptorPtr = (EFI_MEMORY_DESCRIPTOR*)(buffer + (i*MemMapDescriptorSize)); 
      Print(L"Type: %d PhsyicalStart: %lx VirtualStart: %lx NumberofPages: %d Attribute %lx\n", 
       MemoryDescriptorPtr->Type, MemoryDescriptorPtr->PhysicalStart, 
       MemoryDescriptorPtr->VirtualStart, MemoryDescriptorPtr->NumberOfPages, 
       MemoryDescriptorPtr->Attribute); 
     } 
     FreePool(buffer); 
    } 

    return status; 
} 

이것은 비교적 간단합니다. GetMemoryMap은 충분히 큰 버퍼를 전달하지 않으면 몹시 불평하므로 충분한 공간이 확보 될 때까지 버퍼 크기를 계속 증가시킵니다. 그런 다음 루프를 만들고 인쇄합니다. 실제로 sizeof(EFI_MEMORY_DESCRIPTOR)은 출력 버퍼의 구조체 사이의 차이가 아니라는 점에 유의하십시오. 위의 반환 된 크기 계산을 사용하십시오. 그렇지 않으면 실제 크기보다 훨씬 큰 테이블로 끝납니다 (주소 공간이 모두 잘못 보입니다) .

이 표에서 E820을 사용하여 일반적인 형식을 결정하는 것은 대단히 어렵지 않습니다.

+0

Antony에게 상세한 답변을 주셔서 감사합니다. 커플에게 묻고 싶습니다. 커널이 메모리 맵에 대해 알고 있어야하는 이유는 무엇입니까? "부트 로더는이 메모리 맵 지식이 필요하며 세부 사항을 알려줄 수 있습니까?" 위의 라인은 무엇을 의미합니까? –

+1

@AmitSinghTomar 일부는 펌웨어 (예 : 비디오)에서 사용 중이기 때문에 운영 체제는 (실제) 메모리 맵을 이해해야합니다. 메모리, acpi, SMM 모드 코드. 불행하게도, OS는 이것에 관해서 아무 것도 할 수 없지만, 쓰기를 피할 필요가있다 .Grub은 메모리 맵을 획득하여 커널에 넘길 수있다. 커널은 그것을해야만한다. 이것은 스스로 int 15h를 발행 할 필요없이 메모리 맵을 얻는 편리한 방법이다. –

+0

리눅스 커널 nel은 http://blog.fpmurphy.com/2012/08/uefi-memory-v-e820-memory.html을 참조하십시오. –

관련 문제