구성
- 컴퓨터의 구조
- 파일 실행 과정
- 레지스터 초기화
- 운영체제의 시작(booting sequence)
- grub
- kernel compile(리눅스 운영체제 수정하기)
이 정리는 23-2에 수강한 오퍼레이팅 시스템 강의를 기반으로 하였습니다.
컴퓨터는
의 5가지 구성 요소로 되어있다(input + output으로 입출력 장치라고 합쳐 얘기하기도 함).
하나씩 간단하게 알아보자.
메모리는 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품이다. 즉, 프로그램이 실행되려면 반드시 메모리에 저장되어 있어야 한다는 것과 같다.
예시로 ex1.c파일을 만들어 이 파일의 코드를 실행하려고 한다면, gcc -o ex1 ex1.c
로 실행 파일을 만든다. 그리고 ./ex1
로 이 ex1.c 의 코드를 실행해볼 수 있는데, 이때 기계어로 만들어진(명령어 + 데이터) 정보들이 메모리에 로드된다.
로딩이 되고 나면 cpu가 메모리에 저장된 ex1의 명령어를 하나씩 실행한다. 이렇게 메모리에 로드되어 실행 타임에 실행되는 것을 프로세스라고 한다.
cpu는 컴퓨터의 두뇌이다.
쉽게 말하면 우리가 밥을 먹기 위한 과정을 생각해보면 된다. 배가 고프면, 냉장고를 열어 먹을걸 찾아보고, 조리해서, 식탁에 올리고, 먹는다. 이 과정에서 if(배고프면) 냉장고 열기
, if(냉장고에 먹을게있으면) 조리하기
, if(조리를 다 했으면) 식탁에 올리기
, if(식탁에 음식이있으면) 먹기
이 과정들은 어떻게 바로바로 수행되는 걸까? 배고프면 내가 무엇을 할지 어떻게 알고 있는 것일까?
우리 뇌가 저 일련의 과정을 배고플 때 루틴[]
배열로 저장해놓고 있다고 해보자. 만약 배고프면 이 배고플 때 루틴[0]
으로 가서 냉장고 열기부터 시작하는 것이다. 냉장고 열기가 끝났으면 당연히 배고플 때 루틴[1]
으로 이동해서 음식이 있으면 조리하기를 수행할 것이다. 결국은 이렇게 i
를 2
, 3
으로 늘려가며 for문
으로 배고플 때 루틴
배열을 끝까지 읽어 마지막인 음식을 먹고배고픔 해소하기
목적을 달성한다.
이때 다음 행동을 가리키는 let i
같은 존재가 cpu에도 있다. 그리고 이런 행동 루틴 배열은 메모리가 된다. cpu는 자신의 i를 가지고 메모리를 돌며 명령어를 읽고 행동한다. 그리고 i를 바꿔 다음 행동을 가리킨다. 그렇게 가리켜진 메모리의 특정 명령어를 또 수행한다. 이게 cpu의 일과다. 그래서 cpu는 컴퓨터의 두뇌라는 것이다. 뇌가 없으면 배고플 때 뭘 해야할지 모르는 것처럼, 컴퓨터도 마찬가지다. 다음 행동을 미리 알고 있고 수행하기 위해선 cpu가 반드시 필요하다.
파일을 저장하는 장소가 디스크다. 앞에서 예로 들었던 ex1.c같은 파일이 디스크에 저장된다.
메모리가 현재 실행되는
프로그램을 저장한다면, 디스크는 보관할
프로그램을 저장한다고 생각할 수 있다. 당장에 실행 안할 파일들은 디스크에 저장되는 것이다.
우리 뇌가 배고플 때 할 행동, 씻을 때 할 행동, 잘때 할 행동들을 매 초마다 생각하진 않는다. 그 상황이 닥치면 그때 나 어떤 행동을 해야하지 하고 생각한다. 이처럼 뇌가 당장 사용안하는 생각들을 묻어두고 필요할 때 꺼내는 것을 기억이라고 하고 디스크와 비슷하다고 할 수 있다. 또한 씻기 직전이면 씻을 때 할 행동을 미리 생각하고(오늘은 트리트먼트를 쓴다던지) 씻는 것은 실행파일을 메모리에 로드하고 수행하는 것과 비슷하다고 할 수 있을 것 같다.
결과를 보여주는 모니터나, 코드를 입력하는 키보드 등의 주변 장치를 통틀어서 말한다.
ex1.c를 컴파일하면 ex1이라는 실행 파일이 만들어진다. 이 실행 파일은 아직 실행되지 않았기 때문에 디스크에 저장된다.
./ex1로 실행하면 이 실행 파일이 메모리에 로드되는데, 이렇게 실행 타임에 ex1이 실행되는걸 프로세스라고 부른다. 로딩이 되고 나면 cpu가 ex1에 있는 명령어를 하나씩 수행한다.
그림에서 왼쪽이 cpu고 오른쪽이 메모리이다. 메모리를 보면 기계어가 쭉 들어있는데, 컴파일러가 기계어로 바꿔놓고 이를 메모리에 프로세스로 만든 모습이다.
이렇게 로딩이 되고나면, 왼쪽에 있는 cpu가 명령어를 하나씩 꺼내서 실행한다. 이 실행하는 과정을 cpu execution cycle
이라고 부른다. 파워가 들어가는 순간부터 cpu는 이 사이클을 계속 반복한다.
fetch next instruction(명령어)
스텝은 cpu가 실행하기 위한 명령어를 메모리에서 가져오는 단계를 말한다. 이때 메모리의 어디에 이 명령어가 저장되어 있느냐는 eip(리눅스 용어, 운영체제마다 다를 수 있음)라는 것이 가리켜주고 있다.
update eip
스텝은 아까 eip가 가리키던 명령어를 cpu가 가져갔으니, 다음으로 실행할 명령어를 가리키기 위해 메모리의 명령어 위치를 업데이트하는 것을 말한다.
execute fetched instruction
스텝은 cpu가 아까 가져왔던 명령어를 실행하는 과정이다.
(사실 더 과정이 있지만 지금은 스킵)
cpu안의 클락이 한번 틱 칠 때마다 사이클의 스텝 하나가 실행된다.
ex1이 실행되기 직전, 빨갛게 표시된 eip가 80483c4를 가리키고 있다. 이는 80483c4에 ex1의 명령어의 시작 위치인 것이다. 이 상태에서 한번 틱! 하면 해당 위치에 들어있는 명령어를 가져온다. 지금 80483c4엔 55가 들어있으므로 이 55를 instruction register에 가져오게 된다.
실행할 명령어를 가져왔으니 다음 틱에는 eip를 업데이트 한다. eip가 가리키는 주소 값이 80483c4에서 80483c5로 바뀌었다.
이렇게 한 개의 사이클이 끝나고 다음 사이클의 첫 틱에는 eip가 가리키는 80483c5에 들어있는 값을 가져와 동일한 과정을 반복할 것이다.
파워를 넣으면 cs, ip 레지스터가 초기화된다. cs 레지스터는 코드(메모리) 세그먼트를 가리키는 역할이다.
ip 레지스터는 코드 세그먼트 내에서 다음으로 실행될 명령어의 오프셋 주소를 갖는다. 오프셋은 거리 차이를 나타낸다는 뜻이다.
처음에 파워를 넣으면 cs = f000, ip = fff0으로 초기화된다. 이렇게 가리켜진 명령어는 fffffff0인데 이는 BIOS 프로그램이다. 이제 지금부터 위에서 설명했던 사이클이 시작되는 것이다.
바이오스 프로그램은 Basic Input Output System의 약자인데, 이 프로그램은 시스템 초기화와 부트 로더라는 프로그램을 로딩하고 실행하는 역할을 한다.
그럼 이 바이오스는 부트 로더를 어떻게 찾냐면, 현재 부트 디스크의(ex. A 드라이브) 첫번째 섹터를 메모리에 로딩하고 실행한다. 부트 디스크는 보통 a, b, c,,, 로 알파벳 순서이다. 없으면 다음으로 넘어간다. 이 순서대로 찾아서 메모리에 로드되는 프로그램이 부트 로더이다. 리눅스는 이 부트 로더 중에서도 grub 부트 로더가 사용된다.
그럽 로더는 실제로 운영 체제를 찾아 로딩하고 실행시키는 프로그램인데, 리눅스의 경우 이 로더가 리눅스를 찾아서 실행시킨다고 할 수 있다. 리눅스를 실행한다는 건 운영체제를 시작하겠다는 뜻과 같다.
그래서 파워를 넣으면 리눅스 운영 체제가 바로 시작되는 것이 아니고, BIOS -> grub -> linux 순서대로 실행되는 것이다. 리눅스가 실행된 이후 부터는 모든 것을 운영 체제가 컨트롤 한다.
운영체제는 interrupt descriptor table을 초기화하고, 시스템 자료구조를 초기화하고, 시스템 프로세스들을 쭉 실행시킨다. 이때 마지막 실행되는 시스템 프로세스가 login이다. (아래 장면)
실행되는 시스템 프로세스들은 각자 나름대로 자기가 해야할 초기화 작업을 하고 어떤 이벤트를 기다리는 상태로 blocking이 되기도 하는 식으로 진행이 된다.
그러므로 로그인 요청이 나오면 로그인 이전의 프로세스들이 다 진행 완료인 상태인 것이다.
grub(Grand Unified Bootloader)이 어떻게 운영체제를 찾을 수 있는 것일까?
기본적으로 grub은 운영체제를 /boot/grub/grub.conf 파일을 열어서 그 안에서 운영체제의 위치를 찾는다.
(grub.conf)
title은 운영체제 이름을 설정한다. 타이틀이 두개가 있다는건 이 시스템에서 운영체제가 2개 있다는 뜻이다. 이 운영체제 중 어떤 것을 선택할지는 사용자가 선택할 수 있다.
그리고 kernel 옆에 쓰여진 /kernel-genkernel-x86-...
, /boot/bzImage
가 운영 체제 파일의 위치이다. My linux를 선택한 경우 /boot/bzImage
에서 리눅스 운영체제를 로딩한다.
우린 운영 체제를 구성하는 파일 일부를 수정할 수 있다. 그렇게 수정한 파일은 컴파일하고 다시 적용해 변경된 운영체제로 사용할 수 있도록 하는 과정이 필요하다.
일단 수정하고싶은 부분을 수정한 후에 아래 과정을 따라가자.
make 명령어는 c파일이 여러개로 복잡하게 되어있느 프로그램에서 변경된 파일만 찾아 컴파일하고 최종 실행 파일을 만들어주는 명령어이다. bzImage(big zip Image)는 최종 실행 파일 이름을 bzImage로 하겠다는 듯이다.
이 명령어는 /root/linux-2.6.25.10
(버전마다 다름) 경로에서 실행되어야 한다. 그 외 경로에서는 실행되지 않는다.
이렇게 만들어진 실행 파일은 arch/x86/boot/bzImage
경로에 만들어진다.
grub이 My linux에 대해서 운영체제 실행 파일을 /boot/bzImage
에서 찾기 때문에 만든 실행 파일을 저 경로에 두어야 한다.
그래서 cp arch/x86/boot/bzImage /boot/bzImage
로 해당 경로에 복사한다.
리눅스 실행 파일을 수정해 grub이 찾을 수 있는 경로에 두었다면 다시 부팅해야한다.
가상 머신을 껐다 켜도 되지만, reboot
로 간단하게 재부팅할 수 있다.
이렇게 커널 컴파일이 완료되었다. 커널 컴파일은 항상 이 과정을 따른다.