08_week_C_pintos_systemcall-1

신치우·2022년 11월 28일
0

data_structure_and_Pintos

목록 보기
21/36

result:

Project 1 에서는 lib에 존재하는 systemcall (write, exit, halt 등)을 사용하였기 때문에 우린 kernel 부만 작업하면됐었다.

이제는 kernel 에서 user로 이어지는 부분을 작업한다.

순서는
Argument passing --> systemcall 순서로 진행된다.

Argument passing 을 통해서 kernel 의 데이터를 register에 올려줄 것이고
그 후 user부에서 동작이 이뤄지면서 systemcall 을 사용하여 test case를 통과할 것이다

해당 프로젝트에서는 multi thread는 지원되지 않고
각각의 프로세스는 하나의 Thread를 갖는다 (linux는 thread와 process를 구분하지 않고 하나의 task로 표현한다)

시작하기에 앞서 init.c file에서 동작 순서를 확인하면
init 부를 지나 run_actions 부터 동작하게 된다

	/* Run actions specified on kernel command line. */
	run_actions (argv);

	/* Finish up. */
	if (power_off_when_done)
		power_off ();
	thread_exit ();

이후
run_actions --> run_task로 이동하여 else 부분이 동작하게 된다

#ifdef USERPROG
	if (thread_tests){
		run_test (task);
	} else {
		process_wait (process_create_initd (task));
	}
#else

Argument passing

load의 순서는 git book을 참고하여 4단계로 구성하였다.
load를 하기 전에 token으로 file을 구분하여 저장한다.
--> while문에서 argv에 file을 token으로 구분하여 저장함

1단계를 진행하기 전 if_->rip = ehdr.e_entry; 의 역할은 ELF header가 갖는 명령어를 if_->rip에 저장해준다 : userland로 넘어가게되면 해당 명령어부터 실행될 것임

1~4단계가 끝나면 인자 개수와 fake return을 제외한 시작점을 저장해준다
그후 load가 끝나고 밖에 나오게 되고
process_exec 중간 에러에 걸리지 않는다면
do_iret 함수를 통해 interrupt frame에 저장된 정보를 register에게 전달한다

그 후 USERLAND가 동작함

보다 자세한 내용은 각각의 주석에 달려있음

수정하는 file : process.c
수정 구간 : static bool load()

static bool
load (const char *file_name, struct intr_frame *if_) {
  struct thread *t = thread_current ();
  struct ELF ehdr;
  struct file *file = NULL;
  off_t file_ofs;
  bool success = false;
  int i;

  /* for project 2 - start*/
  uintptr_t stack_ptr;   // stack pointer가 가리키는 위치 표시
  char *address[64];   // stack pointer가 처음 들어간 주소를 다시 넣으려함

  char *argv[64];   // 인자를 나눠서 저장할 공간 - 0은 file name 그 이후부터는
                    // 인자들 - 2중 포인터 사용 : 2차원 배열로 저장하기 위해서
  int argc = 0;   // 인자 개수

  char *token;           // file name을 token화
  char *remain_string;   // 남은 string을 저장하기 위한 공간

  token = strtok_r (file_name, " ",
                    &remain_string);   // strtok_r 을 사용해서 토큰으로 구분하고
                                       // 나눔 그때마다 argv 배열에 저장
  argv[0] = token;

  while (token != NULL) {
    token = strtok_r (NULL, " ", &remain_string);
    argc++;
    // argv[argc]= "NULL";
    argv[argc] = token;
  }
  /* for project 2 - end */

  /* Allocate and activate page directory. */
  t->pml4 = pml4_create ();   // 해당 작업 진행시 내부에서 palloc이 할당됨
  if (t->pml4 == NULL)
    goto done;
  process_activate (thread_current ());

  /* Open executable file. */
  file = filesys_open (
      argv[0]);   // 위에서 active하였기때문에 이제 실행가능한 파일을 open 함
  if (file == NULL) {
    printf ("load: %s: open failed\n", file_name);
    goto done;
  }

  /* Read and verify executable header. */
  if (file_read (file, &ehdr, sizeof ehdr) !=
          sizeof ehdr ||   // ehdr (ELF file) 을 file에 복사해 넣음
      memcmp (ehdr.e_ident, "\177ELF\2\1\1", 7) ||
      ehdr.e_type != 2 || ehdr.e_machine != 0x3E ||   // amd64
      ehdr.e_version != 1 || ehdr.e_phentsize != sizeof (struct Phdr) ||
      ehdr.e_phnum > 1024) {
    printf ("load: %s: error loading executable\n", file_name);
    goto done;
  }
  
  /* for project 2 - ROX */
  t->running = file;   // 위 if문에서 ehdr을 file에 복사해 넣었으니 해당 정보를
                       // 가진 file을 running에 넣어줌
  file_deny_write (file);   // file의 권한을 막음 --> 나만 쓸수 있게 
  /* for project 2 - ROX */

  /* Read program headers. */
  file_ofs = ehdr.e_phoff;
  for (i = 0; i < ehdr.e_phnum; i++) {
    struct Phdr phdr;   // phdr == Program header

    if (file_ofs < 0 ||
        file_ofs > file_length (
                       file))   // file_ofs 가 file_length보다 크다 == 더이상 쓸
                                // 공간이 없다. 0보다 작다 == file에 문제가 있음
      goto done;
    file_seek (file, file_ofs);   // 커서를 file_ofs까지 이동시켜줌 --> 그
                                  // 이후부터 써야하니깐

    if (file_read (file, &phdr, sizeof phdr) !=
        sizeof phdr)   // phdr을 file에 phdr size만큼 복사한 byte가 sizeof
                       // phdr이랑 다르면 ==  (위에가 잘못된거)
      goto done;
    file_ofs += sizeof phdr;   // file ofs의 위치를 phdr 의 크기만큼 이동해서
                               // 기록을 할 준비
    switch (phdr.p_type) {
    case PT_NULL:
    case PT_NOTE:
    case PT_PHDR:
    case PT_STACK:
    default:
      /* Ignore this segment. */
      break;
    case PT_DYNAMIC:
    case PT_INTERP:
    case PT_SHLIB:
      goto done;
    case PT_LOAD:
      if (validate_segment (&phdr, file)) { // validate_segment --> phdr이 file에서 로드가능한 유요한 세그먼트를 설명한다면 true를 return 아니면 false를 return
        bool writable = (phdr.p_flags & PF_W) != 0;
        uint64_t file_page = phdr.p_offset & ~PGMASK;
        uint64_t mem_page = phdr.p_vaddr & ~PGMASK;
        uint64_t page_offset = phdr.p_vaddr & PGMASK;
        uint32_t read_bytes, zero_bytes;
        if (phdr.p_filesz > 0) {
          /* Normal segment.
           * Read initial part from disk and zero the rest. */
          read_bytes = page_offset + phdr.p_filesz;
          zero_bytes =
              (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE) - read_bytes);
        } else {
          /* Entirely zero.
           * Don't read anything from disk. */
          read_bytes = 0;
          zero_bytes = ROUND_UP (page_offset + phdr.p_memsz, PGSIZE);
        }
        if (!load_segment (file, file_page, (void *) mem_page, read_bytes, zero_bytes, writable))
          goto done;
      } else
        goto done;
      break;
    }
  }

  /* Set up stack. */
  if (!setup_stack (if_))
    goto done;

  /* Start address. */
  if_->rip = ehdr.e_entry;

  /* TODO: Your code goes here.
   * TODO: Implement argument passing (see project2/argument_passing.html). */
  
  /*==========여기서 부터 argument passing 단계 시작 =============*/

  /* token들을 USER stack에 넣어줌과 동시에 해당 address도 기억을 하기 위하여 address를 사용함 - 1단계 */
  address[0] = if_->rsp;
  for (int i = argc - 1; i > -1; i--) {
    if_->rsp = if_->rsp - (strlen (argv[i]) + 1);
    memcpy (if_->rsp, argv[i], strlen (argv[i]) + 1);
    address[i] = if_->rsp;
  }
  
  /* token들을 stack_ptr (user VM)에 넣어줌 - 2단계 */
  if ((USER_STACK - (if_->rsp)) % 8 != 0) {
    int i = 8 - (USER_STACK - (if_->rsp)) % 8;
    if_->rsp = if_->rsp - i;
    memset (if_->rsp, 0, i);
  }

  /* 1단계 애들의 주소를 넣어준다 - 3 -1 단계 처음엔 0을 넣어줌 */
  if_->rsp = if_->rsp - 8;
  memset (if_->rsp, 0, 8);

  /* 1단계 애들의 주소를 넣어준다 - 3 -2 단계 주소를 넣어줌 */

  if (address != NULL) {
    size_t addr_size = argc * sizeof (address[0]) / sizeof (char);
    if_->rsp = if_->rsp - addr_size;

    memcpy (if_->rsp, address, addr_size);
  }

  /* fake return을 넣어줌 - 4단계*/
  if_->rsp = if_->rsp - 8;
  memset (if_->rsp, 0, 8);

  success = true;
  /* 인자의 개수는 R.rdi에 저장해주고 시작 주소는 R.rsi에 넣어줌 */
  if_->R.rdi = argc;
  if_->R.rsi = if_->rsp + 8; //fake return을 제외한 시작점

done:
  /* We arrive here whether the load is successful or not. */

  return success;
}
profile
하루에 집중을

0개의 댓글

관련 채용 정보