Rust 수행 준비
Rust 코드 실행을 시작하기 전에 몇 가지 초기화를 실행해야 합니다.
.section .init.entry, "ax"
.global entry
entry:
/*
* 메모리 관리 구성을 로드하고 적용합니다. MMU와 캐시를
* 사용 설정할 준비가 되었습니다. .
*/
adrp x30, idmap
msr ttbr0_el1, x30
mov_i x30, .Lmairval
msr mair_el1, x30
mov_i x30, .Ltcrval
/* 지원되는 PA 범위를 TCR_EL1.IPS에 복사합니다. */
mrs x29, id_aa64mmfr0_el1
bfi x30, x29, #32, #4
msr tcr_el1, x30
mov_i x30, .Lsctlrval
/*
* 이 지점 앞에 오는 모든 내용이 완료되었는지 확인하고
* 오래된 로컬 TLB 항목을 사용하기 전에 무효화합니다.
*/
isb
tlbi vmalle1
ic iallu
dsb nsh
isb
/*
* MMU와 캐시를 사용하도록 sctlr_el1을 구성하고 이 작업이
* 완료될 때까지 진행하지 않습니다.
*/
msr sctlr_el1, x30
isb
/* EL1에서 트래핑 부동 소수점 액세스를 사용 중지합니다. */
mrs x30, cpacr_el1
orr x30, x30, #(0x3 << 20)
msr cpacr_el1, x30
isb
/* bss 섹션을 0으로 만듭니다. */
adr_l x29, bss_begin
adr_l x30, bss_end
0: cmp x29, x30
b.hs 1f
stp xzr, xzr, [x29], #16
b 0b
1: /* 스택을 준비합니다. */
adr_l x30, boot_stack_end
mov sp, x30
/* 예외 벡터를 설정합니다. */
adr x30, vector_table_el1
msr vbar_el1, x30
/* Rust 코드를 호출합니다. */
bl main
/* 루프가 인터럽트를 영원히 기다립니다. */
2: wfi
b 2b
- 이는 C의 경우와 동일합니다. 프로세서 상태를 초기화하고 BSS를 0으로 설정하고 스택 포인터를 설정합니다.
- BSS(역사적인 이유로, 블록 시작 기호 block starting symbol 이라고 불림)는 오브젝트 파일에서 0으로 초기화된 정적으로 할당된 변수들을 담고 있습니다. BSS는 실제로 이미지에 포함되지는 않습니다. 어차피 0으로 초기화 될 것이기 때문입니다. 컴파일러는 로더 프로그램이 BSS에 속하는 변수들을 0으로 초기화 할 것으로기대하고 오브젝트 파일을 만듭니다.
- 메모리가 초기화되고 이미지가 로드되는 방식에 따라 BSS가 이미 0으로 설정되었을 수도 있지만 확실히 하기 위해 0으로 설정합니다.
- 메모리를 읽거나 쓰기 전에 MMU와 캐시를 사용 설정해야 합니다. 그러지 않으면 다음과 같은 상황이 발생할 수 있습니다.
- 정렬되지 않은 액세스에 오류가 발생합니다. 컴파일러가 정렬되지 않은 액세스를 생성하지 않도록
+strict-align
을 설정하는aarch64-unknown-none
타겟의 Rust 코드를 빌드하므로 이 경우에는 문제가 없지만, 일반적으로 반드시 그런 것은 아닙니다. - VM에서 실행한다면 캐시 일관성 문제가 발생할 수 있습니다. 문제는 VM은 캐시가 사용 중지된 상태로 메모리에 직접 액세스하는 반면 호스트에는 동일한 메모리에 대해 캐시할 수 있는 별칭이 있다는 점입니다. 호스트가 메모리에 명시적으로 액세스하지 않더라도 추측 액세스는 캐시 채우기로 이어질 수 있으며, 캐시가 정리되거나 VM이 캐시를 사용 설정하면 둘 중 하나의 변경사항이 손실됩니다. 캐시는 VA 또는 IPA가 아닌 실제 주소로 키가 지정됩니다.
- 정렬되지 않은 액세스에 오류가 발생합니다. 컴파일러가 정렬되지 않은 액세스를 생성하지 않도록
- 편의상 기기용 주소 공간의 처음 1GiB, DRAM용 다음 1GiB, 더 많은 기기를 위한 또 다른 1GiB를 ID 매핑하는 하드코딩된 페이지 테이블(
idmap.S
참고)을 사용합니다. 이는 QEMU에서 사용하는 메모리 레이아웃과 일치합니다. - 예외 벡터(
vbar_el1
)도 설정합니다. 이에 관해서는 나중에 자세히 알아봅니다. - 오늘 오후의 모든 예에서는 예외 수준 1(EL1)에서 실행한다고 가정합니다. 다른 예외 수준에서 실행해야 하는 경우 이에 따라
entry.S
를 수정해야 합니다.