How User Program Work
실제 파일 시스템에 올라와있는 파일들을 핀토스에서 직접 불러서 실행시키고, Host OS가 쓰는 구조인듯?
1.
파일 시스템 디스크를 생성
cd ~/pintos/src/userprog
make
cd build
pintos-mkdisk filesys.dsk --filesys-size=2
// pintos-mkdisk: 핀토스에서 제공하는 가상 디스크 생성도구.
// 디스크 이름은 무조건 filesys.dsk로 해야함.
// --filesys-sizze=2 : 가상 디스크 용량을 2MB
JavaScript
복사
2.
파일 시스템 디스크 초기화
cd ~/pintos/src/examples
make
cd ../userprog/build
pintos -f -q
// filesys.dsk를 포맷. 핀토스의 자체 파일 시스템 구조 사용
// 모든 작업이 끝나면 핀토스를 종료. 없으면 화면이 멈춤
JavaScript
복사
3.
파일 시스템 디스크에 실행할 응용 프로그램 복사(echo 프로그램 복사)
pintos -p ../../examples/echo -a echo -- -q
// -p : echo 실행파일을 생성된 핀토스 디스크 파티션으로 복사
// -a : 프로그램 이름을 echo로 설정
// -- : boche 옵션과 핀토스 옵션을 구분, 왼쪽은 boche, 오른쪽은 핀토스
// 실행 프로그램은 Regular ELF 형식
JavaScript
복사
4.
프로그램 실행(echo 프로그램을 x라는 인자를 넣어서 실행(
pintos -q run 'echo x'
// run : 응용 프로그램을 실행
// 주: 핀토스의 현재 상태로는 응용 프로그램 실행 불가
JavaScript
복사
5.
결합된 명령어
pintos —filesys-size=2 -p ../../examples/echo -a echo — -f -q run ‘echo x’
// 옵션은 반드시 -p, -a, --, -f, -q, -run 순서
JavaScript
복사
프로그램의 실행
run 옵션일 경우 run_task() 호출
호출하면 그 다음 어쩌라고
최종 목표
왜 안되냐?
전체적인 함수 실행 순서
여기서 좀 중요한 함수 → start_process
start_process
•
프로세스를 위한 메모리 공간 확보
•
실행파일을 메모리에 탑재
•
프로그램 시작: 스택 프레임 설정, 프로그램 카운터 변경
start_process에 대한 함수 호출
전체적인 흐름
프로세스 생성
thread_create()
•
file_name : 스레드 이름(문자열)
•
PRI_DEFAULT : 스레드 우선순위
•
start_process: 생성된 스레드가 실행할 함수를 가리키는 포인터
•
fn_copy: start_process 함수를 수행할 때 사용하는 인자 값.
tid_t process_execute(const char *file_name)
{
char *fn_copy
tid_t tid;
...
tid = thread_create(file_name, PRI_DEFAULT, start_proecess, fn_copy);
...
return tid;
}
JavaScript
복사
스레드 생성
•
프로세스 디스크립터(struct thread) 생성 및 초기화
•
커널 스택 할당 후 커널 스레드가 수행할 함수를 등록
•
커널 스레드를 run queue(ready list)에 추가
tid_t thread_create(const char *name, int priority, thread_func *function, void *aux){
struct thread *t;
struct kernel_thread_frame *kf
...
t = palloc_get_page(PAL_ZERO); // 페이지 할당
init_thread(t,name,priority); // thread 구조체 초기화
tid = t->tid = allocate_tid(); // tid 할당
// stack frame for kernel_thread();
kf = alloc_fram(t,sizeof *kf); // 커널 스택 할당
kf->eip = NULL
kf->function = function; // 스레드가 수행할 함수
kf->aux = aux; // 수행할 함수의 인자.
...
/*Add to run queue.*/
thread_nblock(t);
return tid;
}
JavaScript
복사
프로세스 탑재
load(): file_name의 프로그램을 메모리에 탑재
메로리 탑재 성공 시 응용 프로그램 실행, 실패 시 스레드 종료
thread_exit();
static void start_process (void *file_name_)
{
char *file_name = file_name_;
...
/* if_.espЕ ݛ 스택 포인터*/
success = load (file_name, &if_.eip, &if_.esp);
if (!success)
thread_exit ();
/* start user program */
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g"
(&if_) : "memory");
}
JavaScript
복사
실행 파일의 메모리 탑재
ELF 파일 포맷에 따라 메모리 탑재
파일을 Open하고 ELf 파일의 헤더 정보를 저장
프로그램 배치 정보를 읽어 파일에 데이터를 메모리에 탑재
스택 생성 및 초기화
bool load(const char *file_name, void (**eip) (void), void **esp){
struct thread *t = thread_current();
struct Elf32_Ehdr ehdr;
struct fil *file = NULL;
t->pagedir = pagedir_create(); // 페이지 디렉토리 설정
proces_Activate() // 페이지 테이블 활성화
file = filesys_open(file_name);
/* ELF 파일의 헤더 정보를 읽어와 저장 */
if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
|| memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7)
|| ehdr.e_type != 2
|| ehdr.e_machine != 3
|| ehdr.e_version != 1
|| ehdr.e_phentsize != sizeof (struct Elf32_Phdr)
|| ehdr.e_phnum > 1024)
/* 배치 정보를 읽어와 저장*/
struct Elf32_Phdr phdr;
if (file_ofs < 0 || file_ofs > file_length (file))
file_seek (file, file_ofs);
if (file_read (file, &phdr, sizeof phdr) != sizeof phdr)
...
/* 배치 정보를 통해 파일을 메모리에 탑재*/
if (!load_segment (file, file_page, (void *) mem_page,
read_bytes, zero_bytes, writable))
...
if (!setup_stack (esp)) /* 스택 초기화 */
...
}
JavaScript
복사