[pintos] project 2 - userprogram

bang·2023년 5월 9일
0

syscall handler에서 intr_frame f는 어디에서 오는가?

코드를 보면서 공부를 하던 중 우리는 system call을 부르기 위해서 syscall.c에서 sycall_handler를 호출한다고 이해했는데 이 핸들러에서 함수의 인자인 intr_frame f가 어디서 오는지 갑자기 궁금해졌다.

순서

예를 들어, userprogram에서 fork를 사용한다고 가정한다. 그럼 lib/syscall.c에 있는 fork함수가 호출된다.

fork 함수 안에는 syscall1 함수를 바로 호출하여 SYS_FORK, thread_name을 넘겨준다.

syscall1함수를 살펴보면 다음과 같다.

#define syscall1(NUMBER, ARG0) ( \
		syscall(((uint64_t) NUMBER), \
			((uint64_t) ARG0), 0, 0, 0, 0, 0))

함수의 매개변수인 NUMBER와 ARG0에 각각 SYS_FORKARG0가 들어간다.

위 함수는 다시 syscall함수를 호출한다. 이 syscall 함수가 우리가 중점적으로 봐야하는 함수이다.

크게 박스로 표시해둔 두 부분을 봐야한다.

  1. 빨간 네모 박스에 해당하는 부분은 어셈블리 레지스터와 주어진 변수들의 포인터를 등록한다.
    - num_은 rax에 등록된다.
    - a1은 rdi에 등록된다.
    등록 후 각 함수의 매개변수로 들어온 값을 넣어준다.

  2. 파란 박스의 부분은 어셈블리어를 실행하는 부분이다.

    • "asm volatile"은 어셈블리어임을 나타내는 부분이다. 이를 통해 C언어와 어셈블리어 간의 인터페이스를 제공한다. C언어에서 사용하는 함수를 어셈블리어에서 호출할 때 사용한다.
    • "syscall\n"은 어셈블리어로 syscall_handler 를 호출하는 부분이다.
    • "mov %1 %%rax\n"은 rax에 있는 값을 %1로 옮긴다. 여기서 %1은 함수의 첫번째 인자를 나타낸다.
    • '"=a "(ret)'는 ret 변수를 rax에 할당하고 ret 값을 반환하도록 지정한다.
    • "g" 부분은 어셈블리어 코드에 일반 목적 레지스터에 할당하도록 요청한다.

[!info] 일반 목적 레지스터란?
프로그래머에 의해 여러가지로 활용할 수 있는 레지스터를 의미한다.
ex) 일반 목적 레지스터에 변수 num을 할당하면 나중에 변수 num 값을 레지스터에 로드할 필요가 없어서 레지스터를 사용하여 메모리에서 데이터를 읽는데 드는 시간을 절약할 수 있다.

결론

레지스터를 활용하여 userprogram에서 받아온 함수의 인자들을 kernel에 있는 함수에서도 사용할 수 있도록 레지스터의 값을 넘겨주면서 syscall_handler에서 사용할 수 있게 되는 것이다.

전체적인 흐름

0개의 댓글