# CPU idle, suspend와 resume context

v6.18.37 / arch/riscv/kernel/suspend.c

CPU가 깊이 잠들면 레지스터와 타이머·주소 변환 설정 일부가 사라질 수 있습니다. arm64의 PSCI/저장 경로, x86의 ACPI 및 플랫폼 상태, RISC-V의 SBI와 CSR 저장을 같은 것으로 취급할 수 없습니다. 대표로 RISC-V의 제어 레지스터 저장 함수를 읽습니다.

## suspend_save_csrs

```c

void suspend_save_csrs(struct suspend_context *context)
{
	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG))
		context->envcfg = csr_read(CSR_ENVCFG);
	context->tvec = csr_read(CSR_TVEC);
	context->ie = csr_read(CSR_IE);

	/*
	 * No need to save/restore IP CSR (i.e. MIP or SIP) because:
	 *
	 * 1. For no-MMU (M-mode) kernel, the bits in MIP are set by
	 *    external devices (such as interrupt controller, timer, etc).
	 * 2. For MMU (S-mode) kernel, the bits in SIP are set by
	 *    M-mode firmware and external devices (such as interrupt
	 *    controller, etc).
	 */

#ifdef CONFIG_MMU
	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SSTC)) {
		context->stimecmp = csr_read(CSR_STIMECMP);
#if __riscv_xlen < 64
		context->stimecmph = csr_read(CSR_STIMECMPH);
#endif
	}

	context->satp = csr_read(CSR_SATP);
#endif
}

```

### 15행

```c

void suspend_save_csrs(struct suspend_context *context)

```

절전 복귀에 사용할 제어 레지스터 저장 영역 context를 받습니다. 이 함수 자체가 잠드는 명령을 실행하지는 않습니다.

### 17행

```c

	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG))

```

ENVCFG 상태를 사용하는 커널의 기능 조건이 충족되는지 검사합니다.

### 18행

```c

		context->envcfg = csr_read(CSR_ENVCFG);

```

지원되는 경우 ENVCFG를 저장합니다. 없는 CSR을 무조건 읽지 않도록 조건을 따릅니다.

### 19행

```c

	context->tvec = csr_read(CSR_TVEC);

```

예외가 도착할 벡터 위치를 저장합니다. 복귀 후 정상 trap 처리를 다시 연결하는 데 필요합니다.

### 20행

```c

	context->ie = csr_read(CSR_IE);

```

인터럽트 허용 비트를 보존합니다. 외부 요청의 pending 상태 자체를 이곳에서 저장하는 것은 아닙니다.

### 32행

```c

#ifdef CONFIG_MMU

```

MMU를 사용하는 빌드에서만 다음 timer·SATP 저장 코드를 포함합니다. 이는 런타임 if와 다른 전처리 조건입니다.

### 33행

```c

	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SSTC)) {

```

SSTC 확장이 있으면 supervisor timer 비교 레지스터도 저장합니다.

### 34행

```c

		context->stimecmp = csr_read(CSR_STIMECMP);

```

다음 timer event와 관련된 비교값을 읽습니다. RV32에서는 아래에서 상위 절반도 읽습니다.

### 35행

```c

#if __riscv_xlen < 64

```

RISC-V 레지스터 폭이 64비트 미만인 빌드 조건을 선택합니다.

### 36행

```c

		context->stimecmph = csr_read(CSR_STIMECMPH);

```

32비트 CSR에 담기지 않는 timer 비교값의 상위 부분을 따로 저장합니다.

### 37행

```c

#endif

```

RV32 전용 부분의 끝입니다. RV64에는 이 상위 CSR 저장이 포함되지 않습니다.

### 40행

```c

	context->satp = csr_read(CSR_SATP);

```

주소 변환 루트·ASID·모드를 담는 SATP 값을 보존합니다.

### 41행

```c

#endif

```

MMU 빌드 전용 영역의 끝입니다.

