이전 기사에서는 RISC-V Linux 시작을 위한 페이지 테이블 생성을 분석했습니다. RISC-V Linux 항목 주소는 2M 정렬되어야 한다고 언급되었습니다. 오늘은 2M 정렬 문제를 해결하는 방법에 대해 이야기하겠습니다. 메모리의 일부를 최적화합니다.
참고: 이 기사는 linux5.10.111 커널을 기반으로 합니다.
각 칩이 공장에서 출고될 때 해당 부트롬은 칩 내부에 굳어져 있다고 가정합니다. bootrom은 0x0, 즉 위와 같습니다. 전원을 켜면 프로그램은 주소 0x0에서 실행됩니다.
RISC-V Linux를 시작하기 전에 먼저 opensbi를 실행해야 하므로 opensbi는 0x0
处,这样芯片上电后,就会从0x0
地址处执行opensbi。在opensbi运行完后,会跳转到opensbi运行地址偏移2M的位置去执行下一级boot(这里下一级boot是kernel),即跳转到0x200000
地址处运行kernel,因此应该把kernel放到内存的0x200000
주소에 배치되어야 합니다.
메모리 분포 다이어그램은 다음과 같습니다.
커널의 경우 시작 시 자체 커널에서 주소를 로드합니다(예: 0x200000
) 페이지 테이블 매핑을 설정하기 시작합니다. 물리적 메모리에 대해 페이지 테이블 매핑이 설정되어야 나중에 해당 메모리에 액세스할 수 있습니다. 커널은 주소 앞에 2M 메모리를 로드합니다(예: 0x0 - 0x200000
)은 커널에 의해 무시되며 이 2M 메모리에 대한 페이지 테이블이 설정되지 않습니다. 즉, 커널은 이 2M 메모리에 액세스할 수 없습니다. 0x200000
)开始建立页表映射,只有对物理内存建立了页表映射,后面才能访问这些内存。而kernel加载地址前面的2M内存(即0x0 - 0x200000
)将被kernel忽略,不会对这2M内存建立页表,即kernel无法访问这2M内存。
在QEMU上RISC-V Linux的启动信息:
但opensbi实际不需要使用2M这么大的范围,默认是512KB
,opensbi的pmp会保护这512KB
内存,不让其他程序访问。
因此在Kernel和opensbi之间会存在1.5M
512KB
, opensbi의 pmp는 이것을 보호합니다512KB
메모리, 다른 프로그램에서 액세스할 수 없습니다.
1.5M
메모리 간격 및 메모리 공백의 이 부분은 프로그램에서 사용되지 않으므로 메모리 낭비가 발생합니다. 그러면 커널이 메모리의 이전 부분을 사용하도록 하는 방법은 무엇입니까?
최적화 계획
이 2M 메모리를 최적화하기 위한 두 가지 계획이 있습니다: 🎜🎜🎜옵션 1🎜: opensbi를 메모리 끝에 넣고 커널 항목 주소는 여전히 2M 정렬을 유지합니다. 🎜🎜🎜옵션 2🎜: Opensbi는 여전히 메모리 시작 부분에 배치됩니다. 커널 소스 코드를 수정하고 2M 정렬 제한을 해제하면 커널 주소를 앞으로 이동할 수 있습니다. 🎜
opensbi를 메모리 끝에 두었고 커널 항목 주소는 여전히 2M 정렬을 유지합니다.
즉, 커널은 메모리 앞쪽에 배치되고, opensbi는 뒤쪽에 배치됩니다.
예를 들어 커널은 메모리의 0x0
地址处,opensbi放到内存的0x10000000
地址处。这样kernel前面就不会有预留内存,只不过这样需要修改bootrom的地址,将地址从0x0
修改为0x0x10000000
。这种方案只适合芯片还没出厂前,因为用户无法修改bootrom的地址,芯片出厂后,bootrom地址是固定的,假设bootrom地址为0x0
,那么芯片上电后,就会从0x0
开始运行程序,所以opensbi必须放到0x0
주소에 배치되므로 커널은 2M만큼 오프셋됩니다.
또한 RISC-V Linux의 커널 소스 코드를 수정하여 2M 정렬 제한을 해제할 수도 있습니다. setup_vm ()
함수를 사용하여 원래 두 번째 수준 페이지 테이블을 세 번째 수준 페이지 테이블로 변경하여 커널 항목 주소를 4K로만 정렬하면 커널이 앞으로 이동하여 전면 메모리를 사용합니다. setup_vm()
函数中,将原来的二级页表改为三级页表,这样kernel入口地址只需要4K对齐,因此就能将kernel往前挪,从而利用前面的内存。
路径:arch/riscv/mm/init.c
코드 수정
원래 2M 정렬 검사에 주석을 추가하세요.
두 번째 수준 페이지 테이블에서 세 번째 수준 페이지 테이블로 커널의 첫 번째 2M 페이지 테이블 매핑을 변경합니다.
//新增一个PTE pte_t trampoline_pte[PTRS_PER_PTE] __page_aligned_bss; create_pgd_mapping(trampoline_pg_dir,PAGE_OFFSET, (uintptr_t)trampoline_pmd,PGDIR_SIZE,PAGE_TABLE); create_pmd_mapping(trampoline_pmd,PAGE_OFFSET, (uintptr_t)trampoline_pte,PMD_SIZE,PAGE_TABLE); end_va = PAGE_OFFSET + PMD_SIZE; for (va = PAGE_OFFSET; va < end_va; va += PAGE_SIZE) { create_pte_mapping(trampoline_pte,PAGE_OFFSET, load_pa + (va - PAGE_OFFSET), PAGE_SIZE,PAGE_KERNEL_EXEC); }
전체 커널의 페이지 테이블 매핑이 2단계 페이지 테이블에서 3단계 페이지 테이블로 변경됩니다. 커널 크기가 4M+
위 내용은 실용적인 전투 | RISC-V Linux 항목 주소 2M 예약 메모리 최적화의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!