저는 Linux가 I/O 공유 메모리를 관리하여 이를 사용하는 장치와 통신하는 방법에 대해 꽤 혼란스러워합니다.
내가 올바르게 이해했다면 Linux 커널은 0x100000(첫 번째 메가바이트 레거시 램 데이터를 피하고 연속 메모리 위치에 저장하기 위해)에서 매핑된 다음 보호 모드로 들어간 후 시작됩니다.
- 32비트 시스템에는 다음과 같은 매핑이 있습니다.
ZONE_NORMAL은 896MB 미만이어야 하므로 커널 선형 1GB와 물리적 896MB 간의 매핑이 항상 가능합니다. 지금은 ZONE_DMA를 무시합시다. (PCI가 이제 메모리의 모든 곳에서 DMA 전송을 사용할 수 있으므로 이것은 레거시 시스템에만 해당된다는 것을 읽었습니다.)
- 64비트 시스템에서 커널 선형 주소 공간은 PAGE_OFFSET= 0xffff810000000000부터 시작해야 합니다.
두 경우 모두 커널 공간의 주소가 PAGE_OFFSET보다 크면 ioremap 매핑을 참조해야 하며(페이지 매김을 통해 해결) PAGE_OFFSET보다 낮으면 간단한 NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET으로 해결할 수 있습니다. 이 올바른지?
보너스 질문: 커널이 실행 중이고 정리가 완료되면 커널이 여전히 물리적으로 0x100000부터 그 앞으로(첫 번째 GB 내에서) 상주합니까? 64비트 시스템에서도요?
답변1
PC에서 하드웨어 메모리 매핑된 IO 범위는 BIOS에 의해 3GiB에서 4GiB 사이의 물리적 메모리 주소에 할당됩니다. 드라이버가 메모리에 대한 액세스를 요청하면 커널은 이를 커널 가상 주소 공간 어딘가에 매핑합니다.
다른 두 질문 중 어느 것도 공유 메모리와 관련이 없는 것 같지만 다음과 같습니다.
두 경우 모두 커널 공간의 주소가 PAGE_OFFSET보다 크면 ioremap 매핑을 참조해야 하며(페이지 매김을 통해 해결) PAGE_OFFSET보다 낮으면 간단한 NEW_ADDRESS = OLD_ADDRESS - PAGE_OFFSET으로 해결할 수 있습니다. 이 올바른지?
정신적으로는 그렇습니다. 두 경우 모두 하드웨어는 페이지 테이블을 사용합니다.
답변2
귀하의 질문이 ioremap의 작동 방식과 같다고 생각하십시오.
vaddr = ioremap(paddr_io_mapped_device, 크기);
vaddr은 커널 공간의 가상 주소를 반환합니다. 커널은 가상 주소 범위(vaddr, 크기)에 대한 페이지 테이블 항목을 생성하고 이를 물리적 주소 paddr_io_shared_device에 매핑합니다. 따라서 가상 주소 범위에 액세스하면 io_mapped 장치 내부의 물리적 주소에 액세스하는 것과 같습니다.
중요한 것은 반환된 vaddr은 다음과 같습니다.캐시할 수 없음. 주소 범위를 읽고 쓸 때마다 캐시가 아닌 io_mapped 장치에서 읽기/쓰기가 됩니다.