운영체제 이론 – 시작

운영체제 이론은 사실 대학 다니면서 꼭 배우는 거지만… 운영체제를 직접 개발하려고 하면 반드시 꼭 정리 다시 해야 한다.

니가 아는 걸 직접 짜야 하는 걸 보게 된다.

즐거운 거잖아…!!!!!!

(저리가 by 독자)

그러니 일단 이론도 좀 시작해봅니다.

일을 막 늘리는 거 같아 보이면 기분탓입니다.

ncurses 01 – ncurses 프로그래밍이란?

전에 작업하던 C언어 내용과는 별개로 재미를 붙이기 위해서라도 좀 해야 할 거 같아서 추가로 시작해봅니다. ㅇㅂㅇ

일전에 DOS를 사용하던 분들은 아시겠지만, MC(Midnight Commander)라는 것을 이용하여 콘솔 화면에서도 GUI 처럼 화면을 이리저리 보여주고 방향키로 선택 커서를 옮겨 다니고, 화면에 단축키 처리를 할 수 있던 녀석이 기억 나실지 모르겠습니다. 도스 환경에서는 MDrill, 좀 근래에 썼던 사람들은 mdir이라고 아실텐지… (나이 인증 아닙니다.)

이런 비슷한 녀석이요.

당연히 터미널 시스템에서 텍스트 기반으로 쓰던 시스템 환경에서도 화면에 보이는 기술이 중요하다는 것을 알고 있기 때문에, 이런 기반의 기술을 내놓게 됩니다. 바로 Unix System V ver 4.0에 있던 curses라는 기능입니다. 이 기능을 GNU에서 공개해서 어디서든 쓸 수 있도록 한 것이 바로 ncurses입니다.

즉, ncurses 는 콘솔 화면에서 사용자가 이용하기 쉽도록 사용자 친화적인 콘솔 윈도우 화면을 만드는 데 이용되는 라이브러리입니다. 메뉴 바를 제어하거나, 키보드 입력을 돕거나, 윈도우를 띄워주는 그런 기능들을 합니다.

당연히 이런 기능들을 쉽게 이용할 수 있도록 라이브러리화 되어 있고, 함수로도 구현되어 있기 때문에 적절하게 사용하면 됩니다. 그렇다고 해서 뭐 그렇게 큰 환경이 필요한 게 아닙니다. 터미널로 접속 가능한 리눅스만 있으면 충분히 가능합니다.

C언어를 진행하다 보면 지속적으로 물어보는 것이 “이거 어떻게 써요?” 하는 겁니다. 리눅스 시스템 프로그래밍 하는 건 어느 정도 알겠고, 입출력 하는 프로그램이야 당연히 알겠고, 장치 드라이버 짜는 것까지는 알겠는데, 더 이상 어떻게 쓸 곳 없냐고 물어보더군요. 그래서 C 언어를 리눅스에서 프로그래밍하는 것과는 별개의 과정으로 이 과정 또한 조금씩 다뤄보려 합니다. C를 할 줄 안다면 어렵지 않습니다. 오히려 더 좋은 길잡이가 될 수 있으면 좋겠군요.

64비트 모드까지 부팅시켰는데..! ㅠㅠ

기분전환 삼아서 하는 운영체제 개발….

이제는 ia32-e 모드를 지나서 645비트로 동작시키도록 작업을 하고 있는데…

도중에 자꾸 덤프 뜬다. 작업 실행 도중에 코드 다 안짜고 멈추게 해서 그런가…ㅠㅠ

저기까지 진행한 작업이 메모리 구조를 페이징 구조로 변환해서 페이지와 세그멘테이션을 제대로 정리해서 메모리 관리가 될 수 있도록 한 기본 구조까지 만든 것이다.

틈ㅁ내서 만드는 거라 어차피 진도도 덜 나가고…ㅠㅠ

내 연구 테마가 메모리 매니지먼트닫 보니깐 여러모로 더 생각해서 짜게 되었다. 안그러면 그냥 단순한 레벨에서 걍 구현만 하고 끝내는 수준이었을 텐데…ㅠㅠ

파일 시스템이 없는 상태에서의 리눅스 커널 부팅

https://youtu.be/ONMhXMxmt20

리눅스 시스템에서 파일 시스템이 없는 경우에 커널 패닉이 일어난다고 했는데, 실제로도 일어나는지를 보여주기 위해서 화면 캡쳐를 통해서 직접 보여주도록 하였다.

Union File System

도커의 이미지와 컨테이너 개념글에서 다뤘던 내용입니다만, 도커는 실행중에 변경된 부분을 이미지로 생성할 수 있다고도 적었습니다. 이게 가능하도록 하는 것이 바로 Union File System(UnionFS)입니다.

이 파일 시스템은 읽기 전용의 파일 혹은 디바이스에서 변경 사항을 기록하여 저장할 수 있도록 해주는 파일 시스템이다. 읽기 전용 파일을 실행할 경우, 해당 파일에 대해 쓰기가 가능한 임시 파일을 생성하여 읽기 파일을 그대로 복제하여 실행을 하게 된다. 그 다음, 수정이 된 내용에 대해 모두 사용하였다면 쓰기 작업을 진행한 다음, 기존의 읽기 파일을 대체한다. 이러한 방식을 Union Mount라고 한다.

도커에서도 해당 이미지 파일을 기본적으로 UnionFS가 지원되는 파일이다. 이 파일을 위의 Union Mount 처리를 하여 지속적인 변경 사항을 작성하여 업데이트 되는 것이다.

UnionFS를 잘 이용한 방식은 리눅스 배포판 중에 크노픽스(Knoppix)라는 배포판이 있다. 이 배포판은 CD 혹은 DVD에서 실행하는 라이브 운영체제 형식으로 배포되는데, 부팅 과정과 운영체제의 기본 실행은 램디스크에서 부팅 및 실행을 하면서도 변경된 사항에 대해서는 컴퓨터에 연결된 보조 저장장치(쓰기 가능)에 저장을 하여 다음에 실행될 때 해당 변경사항을 부팅 후 읽어들여서 적용시킨다.

유저랜드(userland) = 사용자 공간(user space)

운영체제에서는 메모리 사용을 기준으로 커널 영역(커널 공간)과 사용자 영역(사용자 공간)을 나눕니다. 운영체제가 부팅될 때, 부팅을 위해 이용되는 맨 앞의 작은 용량 다음에 운영체제 자체의 핵심 기능들을 실행하기 위해 올려놓는 공간을 주로 커널 영역이라 하고, 그 외에 영역에 대해서는 사용자가 이용할 수 있는 영역이라 하여 사용자 영역이라고 합니다.

이제 여기서 사용자 영역에서 실행되는 실행 파일과 라이브러리를 유저랜드라고 합니다. 특히 리눅스의 경우에는 커널만으론 부팅을 할 수 없습니다. 그래서 파일시스템에서 데이터를 불러오는데, 이때 불러오는 것은 부팅에 필요한 최소한의 실행 파일과 라이브러리, 그리고 고유의 패키징 시스템을 포함한 데이터를 불러옵니다. (시스템 데몬, 윈도우 라이브러리, 그래픽 라이브러리, 그 외 각종 라이브러리 등) 이 라이브러리들을 불러오면서 가상 메모리를 이용할 수 있게 되는 것 뿐만 아니라 사용자가 사용할 수 있는 공간을 만들 수 있도록 해줍니다. 운영체제 내용 정리할 때 다시 저세히 다루기로 하죠.

도커하면 빠지지 않는 기본 이야기: 리눅스 컨테이너

도커에 대한 설명을 하다보면 거의 항상 설명하고 하는 것이 있는데, 바로 LXC(LinuX Container)입니다. 오래전부터, 리눅스/유닉스 환경에서는 chroot라는 명령어를 제공했습니다. 이 명령어는 파일 시스템에서 루트 디렉터리(/)를 변경하는 명령어입니다.

이렇게 특정 디렉토리를 루트 디렉토리로 변경하게 되면chroot jail이라는 환경이 생성되는데, 이 안에서는 바깥의 파일과 디렉터리에 접근할 수 없게 됩니다. 경로 자체가 격리되기 때문에 서버 정보의 유출과 피해를 최소화하는 데 주로 이용되어 왔던 기술입니다. 그러나 chroot는 chroot jail에 들어갈 실행 파일과 공유 라이브러리를 직접 준비해야 하고 설정 방법 또한 상당히 복잡합니다. 또한 완벽한 가상 환경이 아니기 때문에 제약 또한 상당히 많습니다. 이러한 환경을 Confined Environment라고 합니다.

이후에 리눅스에서는 LXC라는 시스템 레벨의 가상화를 제공하게 됩니다. LXC는 컴퓨터를 통째로 가상화하여 OS를 실행하는 것이 아니라 리눅스 커널 레벨에서 제공하는 일종의 격리된 가상 공간을 제공합니다. 이 가상 공간에는 운영체제가 설치되지 않고 호스트의 리눅스를 그대로 이용하기 때문에 가상 머신이라고 안하고 컨테이너라고 합니다. 아래의 이미지가 LXC를 설명하기 가장 좋은 이미지인 듯 하군요.

리눅스 커널의 자원 일부를 그대로 이용합니다. 리눅스 커널의 cgroups(control groups)를 통해 CPU, 메모리, 디스크, 네트웤 자원을 할당하여 완벽한 가상 공간을 제공합니다. 또한 프로세스 트리, 사용자 계정, 파일 시스템, IPC 등을 별도로 격리시켜서 호스트와 별개의 공간을 따로 만듭니다. 이렇게 격리된 곳이 바로 namespaces입니다. 마지막으로 보안 관리를 제공하는 SELinux(Security-Enhanced Linux) 또한 가상화된 공간에서 제공하여 보안도 호스트와 같은 수준으로 제공합니다. 즉, cgroups와 namespaces, SELinux 기능을 활용하여서 가상 공간을 제공하게 되는 겁니다. 추가적으로 필요한 자원이 있다면 드라이버를 가상 환경에 연결하여 지원해줍니다.

하지만, LXC는 격리된 공간에 대한 지원만을 할 뿐, 개발 및 서버 운영에 필요한 부가 기능에 대해서는 상당히 부족한 상황입니다. 도커는 이 리눅스 커널에서의 cgroups, namespaces, SELinux 기능을 기반으로 하여 이미지, 컨테이너의 생성 및 관리 기능과 다양한 부가 기능을 지원할 수 있도록 개발된 것입니다. 그래서 도커에 대한 설명을 하다 보면 자연스럽게 LXC에 대한 설명도 같이 들어가게 됩니다.

도커가 처음 개발될 당시에는 LXC를 통해 구현되었다고 과거 문서들에는 많이 나와있지만, 0.9 버전 이후로부터는 libcontainer를 개발하여 이용하는 것으로 알려져 있습니다. 도커 문서에는 실행 드라이버라고 하는데, native, lxc 중 선택해서 사용할 수 있습니다. lxc는 LXC에서 이용하던 라이브러리입니다. 어떤 것을 이용하는 것이 더 좋은지에 대해서는 여러모로 논의가 이어지고 있습니다만, 양쪽 다 열심히 업데이트 되고 있어서 어떻게 될지는 모르겠군요.

자작 운영체제는 은근 단순한 구조를 가진다

리눅스, FreeBSD 등등 여러 운영체제의 코드가 공개되어 있다보니 많은 사람들이 여러모로 운영체제 구조를 보고 공부하는 데에는 익숙해졌다고 봐도 될 정도이다. (못하면 할 수 있도록 공부하는 사람들이라고 생각하겠다.)

그러나, 실제로 개발을 진행하다 보면 운영체제 개발은 그렇게 쉬운 개발이 아니게 된다. 리눅스 커널만 보더라도 자료구조가 상당히 복잡하다. 그런데, 그런 구조여야 될 수 있는 수준으로 규모가 커진 운영체제 또한 리눅스이다.

그런 걸 보다가 다른 사람들이 자작으로 만든 운영체제를 보면 은근 단순한 구조를 가지고 있는 것을 보게 된다. 실제로 지금 내가 만들고 있는 운영체제도 메모리 구조는 단순한 매칭 형식으로 지원되어 있다. 1:1 매핑이라던가, 단순 세그멘테이션으로만 이루어진 보호모드에서 걍 1:1 페이징을 구성한다던가….

이렇게 만드는 이유는 간단하다. 디버깅이 편하다. ㅠㅠ 운영체제 개발에 필요한 디버깅은 사람의 머리다. 그러다 보니 어느 정도 제어를 할 수 있는 자료구조를 가지고 운영체제 개발을 하게 된다. 그러다가 좀 더 규모가 커지면서 구조를 업데이트 하는 것이고, 그렇게 계속 튜닝을 하다 보면 어느샌가 어느 정도 이상의 규모를 지지할 수 있는 성능의 운영체제가 되는 것이다.

그렇다고 해서 대충 한다? 그건 아니다. 다들 운영체제의 이론에서 볼 법한 그런 내용들을 기반으로 생각해서 만드는 것이다. 그러므로 모르면 모르는대로 또 문제가 된다. 이거 은근 여러모로 사람 머리를 엄청 써야 하는 거니깐 은근 무시할 수 없는 수준까지 올라간다. 그러니, 단순한 구조라고 해서 무시할 것이 못된다.

p.s. 이런 운영체제 혼자서 설계해서 만들 수 있는 사람들은 널리고 널렸다는 게 문제다.

허접한 운영체제 개발 – 부트로더 제작과 운영체제 이미지 로딩, 보호모드 전환, 그리고 C 코드 실행까지 한방에!

리눅스 환경에서의 개발은 내가 갖고있는 바이오 노트북에서 이루어지는데, 바이오 노트북이 사실 해상도가 무지 낮다. 게다가 11인치짜리 모델이라…ㅠㅠ 게다가 책상 위가 난잡해지는 게 싫어서 평상시엔 켜놓고 나서 원격으로 이용중이다. 뭐, 이 글과는 관련은 없다. 스샷과는 관련이 좀 있다. ㅠㅠ

규링은 운영체제를 가지고 석사 논문을 쓰고 있다. (여럿 쓴 것도 있다.) 그런 녀석이 운영체제 하나 직접 만들어보는 게 어려울까 싶어서 도전해 보려 해도… 어렵다. ㅇㅅㅇ

자료는 뒤지면 여러모로 나온다. 게다가 여기까지의 부트로더 기술과 32비트 보호보드는 인텔의 메뉴얼과 몇몇 정형화된 코드들이 있어서 어렵지 않게 작업할 수 있긴 하다. 근데 그걸 머릿속에서 막 쥐어짜면서 직접 코드로 짜니깐 안쉽다. (게다가 어셈블리어다.)

근데 막상 만들고 나니 실제로 다른곳에서 만든 것과 거의 유사한 코드들이 나온다. 그래서 그나마 조금은 덜 걸렸을지도 모르겠다.

p.s. 왜 사람들이 이 수준이 되면 비슷한 변수명을 가져다가 막 예시로 만드는지 알겠다. 그게 제일 안전하다. 내 코드스타일 식의 변수명을 붙이고 하는 건 좀 있다가의 작업이 되겠다. ㅇㅅㅇ

운영체제 개발의 기본 자료: wiki.OSDev.org

운영체제를 개발해 보고 싶다고 맘먹는 사람들은 많아도 실제로 운영체제를 직접 개발해보는 사람은 실제로 많지 않다. 진입장벽 자체가 엄청 어렵다. 대학 학부에서는 솔직히 별 도움도 안되는 수준의 어셈블리어를 가르치는 경우도 많고, C언어도 그닥 잘 배워서 오지 않는 경우도 많다.

그런데 운영체제의 개발에 대한 자료는 많다. 그리고 자작 운영체제에 대한 것들도 사실 엄청 많이 존재한다. 우리가 주로 쓰는 운영체제의 숫자가 그렇게 많지 않을 뿐이지, 개개인이 직접 만들어보겠다고 하면서 자작으로 만드는 운영체제의 숫자는 연간 몇 백 에서 몇 천 단위가 된다고 할 정도로 많이 존재한다. 홈브류 컴퓨터 만들어보겠다고 여러모로 취미로 굴려보는 사람들하고 같다고 보면 된다.

게다가 직접 동작하고자 하는 운영체제는 x86 기반이라면 자료가 진짜로 넘치고 넘친다. 요즘은 ARM 보드에서 동작하는 것들도 자료 보고 많이 만들고 하는 거 같다만, ARM쪽은 내가 모르는 게 아직 많아서… 게다가 자료 올려주는 사람들이 뭔 특정 수치를 주고 거기에 입력을 하는데, 그 값들이 뭔지 정확하게 알고 적는 사람이 은근 없어서 되게 불편하다. (운영체제 개발에는 그것들이 엄청 중요하다.)

그런 대표적인 자료를 올려놓은 위키가 바로 이번 제목에 있는 위키이다. 운영체제에 조금이라도 관심이 있는 사람들은 아마 여기 있는 자료를 한번도 보지 않은 사람은 없을 것이다. 아주 기초적인 개발 환경 뿐만 아니라 부트로더부터 시작해서 운영체제 이론에 등장하는 여러 내용들, 그리고 각종 장치 드라이버 및 레퍼런스 북까지…

운영체제에 관심 있는 사람들은 여기 내용 좀 살펴봐도 좋을 것이다.