# RISC-V trap frame과 SBI secondary hart 기동

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

보조 hart는 이미 실행 중인 task의 예외 복귀와 달리 시작 주소와 초기 task·스택을 새로 받아야 합니다. v6.18.37 sbi_cpu_start 전체를 읽어 부트 데이터 공개와 SBI HSM 기동 요청을 연결합니다. trap frame의 자세한 분석은 기존 글에 남겨 두고 이 단원은 SMP 기동의 작은 완결된 함수를 대표로 사용합니다.

## sbi_cpu_start

```c

static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
{
	unsigned long boot_addr = __pa_symbol(secondary_start_sbi);
	unsigned long hartid = cpuid_to_hartid_map(cpuid);
	unsigned long hsm_data;
	struct sbi_hart_boot_data *bdata = &boot_data[cpuid];

	/* Make sure tidle is updated */
	smp_mb();
	bdata->task_ptr = tidle;
	bdata->stack_ptr = task_pt_regs(tidle);
	/* Make sure boot data is updated */
	smp_mb();
	hsm_data = __pa(bdata);
	return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);
}

```

### 65행

```c

static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)

```

기동할 논리 CPU와 그 CPU의 idle task를 받아 SBI HSM 기동 요청을 준비합니다.

### 67행

```c

	unsigned long boot_addr = __pa_symbol(secondary_start_sbi);

```

새 hart가 들어올 secondary_start_sbi의 물리 주소를 구합니다. 아직 그 hart의 정상 가상 주소 실행을 전제하지 않습니다.

### 68행

```c

	unsigned long hartid = cpuid_to_hartid_map(cpuid);

```

Linux 논리 CPU 번호를 펌웨어의 hart ID로 바꿉니다. 두 번호가 우연히 같아도 역할은 다릅니다.

### 69행

```c

	unsigned long hsm_data;

```

나중에 SBI에 전달할 부트 자료 물리 주소를 보관할 변수를 선언합니다.

### 70행

```c

	struct sbi_hart_boot_data *bdata = &boot_data[cpuid];

```

대상 CPU 전용 부트 자료 슬롯을 선택합니다. 여러 CPU 기동 요청의 데이터를 한 슬롯에 덮어쓰지 않도록 나뉘어 있습니다.

### 73행

```c

	smp_mb();

```

idle task 관련 준비가 뒤의 부트 자료 공개보다 앞서도록 CPU 간 메모리 순서를 맞춥니다.

### 74행

```c

	bdata->task_ptr = tidle;

```

새 hart가 현재 task로 사용할 idle task 포인터를 기록합니다.

### 75행

```c

	bdata->stack_ptr = task_pt_regs(tidle);

```

그 task의 pt_regs 위치를 초기 스택 포인터로 기록합니다. 스택 상단 배치 규칙과 연결되는 값입니다.

### 77행

```c

	smp_mb();

```

task와 stack 포인터 쓰기가 완료되기 전에 원격 hart가 기동 자료를 읽는 순서 문제가 생기지 않도록 장벽을 둡니다.

### 78행

```c

	hsm_data = __pa(bdata);

```

boot data 자체의 주소를 물리 주소로 바꿔 펌웨어에 전달할 값을 만듭니다.

### 79행

```c

	return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);

```

hart ID, 시작 물리 주소, 부트 자료 물리 주소로 HSM 시작을 요청하고 결과를 그대로 반환합니다. 실제 secondary 초기화는 다른 hart에서 이어집니다.

