'2016/02 글 목록
Loading...
2016. 2. 19. 12:00

[OS 개발 18] 태스크 스위칭과 보호 (3) - 보호

1. 보호의 개념 이번 포스팅에서는 보호에 대해 알아보도록 하겠습니다. 글을 쓰는 과정에서 나도 공부하면서 작성하는지라 처음에는 좀 내용이 빈약할 수 있습니다. 왜냐하면 이번 포스팅에서는 개념위주로 작성할 계획이기 때문입니다. 일단 포스팅을 마치고 나중에 다시 확인해서 부족한 점이 있으면 보완하도록 하겠습니다. 지난 포스팅까지는 jmp와 Call을 통해 각 태스크 간에 어떻게 스위칭이 일어나는지 살펴보았습니다. 그런데, 여기에서 한 가지 혹은 그 이상으로 문제가 발생할 개연성이 생깁니다. 특정 프로세스로 스위칭했는데 그 태스크 혹은 레벨(특권 레벨 간의 모드 스위칭은 다음에 알아볼 계획이다)에 민감한 코드, 혹은 데이터가 존재한다면 어떻게 될까요? 이러한 문제에서 기인하여 인텔 아키텍처에서는 보호모드에서..

2016. 2. 18. 20:52

[OS 개발 17] 태스크 스위칭과 보호 (2) - CALL 스위칭

1. CALL 스위칭으로 변경하기 앞서 포스팅에서 현재 태스크에서 다음 태스크로 넘어갈 때, jmp나 Call을 사용한다고 했습니다. 이번에는 앞에서 봤던 코드를 활용하여 CALL 방식으로 프로세스를 불러들이도록 하겠습니다. 따라서 코드를 변경해야 하는데, 지난 코드에서 일부만 수정해 보았습니다. jmp TSS2Selector:0 --> CALL TSSSelector:0 ; CALL 명령으로 태스크 스위칭 한다. jmp $ --> iret ; 이전 태스크로 다시 돌아간다. 2. CALL 스위칭 CALL과 jmp의 가장 큰 차이는 jmp는 다음 태스크를 실행 후, 다시 돌아올 때에도 jmp를 통해 돌아오는 반면, CALL 명령은 iret 명령을 통해 돌아온다는 점입니다. 그리고 CALL 명령은 EFLAGS..

2016. 2. 16. 17:14

[OS 개발 16] 태스크 스위칭과 보호 (1)

1. 태스크의 개념 이번 포스팅에서는 태스크 스위칭에 대해 포스팅하겠습니다. CPU는 작동하는 과정에서 많은 프로세스들을 동시에 실행하고 이를 처리합니다. 여기에서 프로세스가 태스크(Task, 작업)를 가리키는 하나의 유닛으로 볼 수 있습니다. 즉, 태스크는 CPU가 처리하는 일련의 작업들의 각 개체라고 보시면 되겠습니다. 이러한 태스크는 커널에서 관리하고 처리해주는 메커니즘을 적절하게 구현해줘야 합니다. 왜냐하면, 무수히 많은 태스크들이 앞으로 운영체제에서 작동해야 할텐데, 이를 어떤 순서로 어떻게 호출하고 실행할 것인가에 대한 명시가 없다면, 태스크 처리상에 문제가 발생할 것이기 때문입니다. 우리가 다루는 윈도우나 리눅스도 멀티 태스킹 작업을 하면서 보기에는 동시에 프로세스가 처리되는 것처럼 보이지만..

2016. 2. 16. 15:27

[OS 개발 15] 무한 재부팅에 대한 개인적 견해

무한 재부팅에 대하여 어느덧 OS 개발에 대한 15번째 포스트 입니다. IDT에 대한 포스팅까지 마친 시점에서 이번 포스팅에서는 잠시 무한 재부팅 문제에 대해 좀 살펴보기로 하겠습니다. 그 동안 OS를 만들고자 했던 많은 분들이 겪어왔던 고충 중 하나가 바로 무한 재부팅 문제입니다. 이전 포스팅에서도 무한 재부팅에 대해 한번 언급한 걸로 기억하는데, 사실 저 역시 OS 개발진행 과정에서 무한 재부팅 현상을 빈번하게 겪었습니다. 이를 해결하기 위해 수 없이 구글링 해 보았지만 무한 재부팅 문제에 대해 깊이 있게 설명하거나 다루는 글이 생각보다 많지 않습니다. 대부분 글을 보시면 아시겠지만 명확한 결론이 없습니다. 물론 저도 분명한 해결책을 제시하기 위해 이 글을 쓰는 것은 아닙니다(워낙 그 경우가 다양하기..

2016. 2. 12. 22:16

[OS 개발 14] 인터럽트와 예외처리(4) 예외처리 구현하기

1. 예외처리 코드 예외 처리 코드는 이전 인터럽트 코드에서 일부를 추가하였습니다. 특히 Boot.asm은 지난 포스팅에서 사용했던 Boot.asm을 사용하면 되겠습니다. 단, 코드에서 다음과 같이 2섹터를 사용하기 위해 al에 넣을 값을 2로 바꿔주기만 했습니다. Boot.asm 커널부분에서는 일부 내용이 추가되었는데, 대부분 이전 포스팅을 참고하면 해석 가능합니다. 바뀐 부분 중에서 일부 설명이 필요한 부분만 흰색으로 구역을 설정했고, 이에 대한 내용은 그 아래 설명에서 확인하면 될 것 같습니다. Kernel.asm 2. 코드 분석 설명1 이 부분도 이전에 설명했던 인터럽트 코드와 비슷하게 해석하면 되겠지만, 0으로 나누는 divide 예외는 IRQ 0번이므로 0값을 edi에 넘겼습니다. 설명2 여기..

2016. 2. 12. 19:24

[OS 개발 13] 인터럽트와 예외처리(3) PIC와 인터럽트 구현하기

1. 코드 실행하기 앞서 두 포스팅에 걸쳐서 IDT에 대해 알아보았습니다. IDT와 PIC, 예외의 개념들을 토대로 다음과 같이 어셈블리 코드로 구현해 보았습니다. (init.inc는 이전 파일과 내용은 그대로이며, 이름만 바뀌었습니다.) 2. 코드 분석 Boot.asm 분석 설명1. 플로피 디스크 드라이브의 모터를 끄는 부분인데, 0x3F2번지에 out I/O명령을 사용하여 XOR 연산을 통해 프로그램 실행 도중에는 모터가 멈추도록 합니다. 설명2. 이 부분이 앞서 포스팅에서 다뤘던 PIC를 직접 설정해주는 부분입니다. 하드웨어 인터럽트를 지정해주기 위해 마스터와 슬래이브 PIC를 구현하였습니다. PIC 포스팅을 살펴보면서 코드를 이해하면 좋을 듯 합니다. 2016/02/12 - [분석연구소/운영체제]..

2016. 2. 12. 13:58

[OS 개발 12] 인터럽트와 예외처리(2) PIC와 예외처리

1. PIC의 개념 인터럽트는 소프트웨어 인터럽트와 하드웨어 인터럽트로 분류할 수 있습니다. 그런데 키보드 입력, 디스크 제어 등은 하드웨어 단에서 인터럽트가 걸려야 하기 때문에, 구현할 때 PIC에 대해 어느 정도 알고있어야 합니다. PIC는 Programmable Interrupt Controler의 약자로, 하드웨어 인터럽트를 처리하는 역할을 담당합니다. 대부분의 PC는 서로 다른 주소에 위치한 두 PIC를 갖습니다. 이 중 하나는 개별적 IRQ라인들 15개 중에서 각각 0~7, 8~15번째의 IRQ를 가지고 있습니다. 아래의 그림을 참고하시기 바랍니다. PIC는 크게 master –slave 구조로 구성되어 있습니다. 그리고 각 PIC에는 8개의 핀(마스터-0~7핀, 슬레이브-8~15핀)이 붙어있..

2016. 2. 11. 11:11

[OS 개발 11] 인터럽트와 예외처리(1) IDT의 개념

1. IDT의 개념 이제 GDT를 끝내고 IDT 개념에 대해 다룰 순서입니다. IDT는 Inturrupt Descriptor Table의 약자로, 위키피디아는 다음과 같이 정의하고 있습니다. 인터럽트 벡터 테이블을 구현하기 위해 x86 아키텍처에서 사용되는 데이터 구조체이다. IDT는 프로세서가 인터럽트와 예외에 대한 정확한 반응을 결정하기 위해 사용된다. 컴퓨터가 동작할 때, 많은 행위들이 일어나는데, 이 행위에 대해서 CPU에게 알려줘야 할 필요가 있습니다. 그래야 다른 행동과의 충돌을 피할 수 있을 것입니다. 이러한 차원에서 IDT의 개념이 생겼으며, GDT와 비슷하게 IDT 역시 인터럽트에 대한 정보가 저장된 디스크립터를 테이블 양식으로 저장하고 있습니다. 인터럽트 디스크립터의 세부 정보는 아래 ..

2016. 2. 10. 21:56

[OS 개발 10] 32비트 커널 로더(4) - 커널 구현과 분석

1. 부트로더에서 커널 구현부로의 점프 앞서 언급한대로, 부트로더에서 커널 구현부로 넘어가는 부분을 우선 구현해야할 것입니다. 다음 코드를 보시죠. 위 코드는 부트로더를 확장하여 작성한 코드입니다. 일부 앞서 포스팅에서 언급했던 내용은 해당 포스팅에서 설명을 참고하도록 하고, 추가된 흰색 구역을 위주로 설명하고자 합니다. 설명1 보호 모드에 진입하겠다는 것을 0번 컨트롤 레지스터(CR0)를 통해 CPU에 알려줘야 합니다. 컨트롤 레지스터에 대해서는 나중에 별도의 포스팅을 통해 제대로 설명해보도록 하겠습니다. 일단, CR0 레지스터를 통해 앞으로 32비트 단위로 보호모드를 사용하겠다는 것을 알린다는 것만 알면 될 것 같습니다. 그런데 or연산을 하는 이유는? 비트중에서 값이 바뀌는 비트 외의 비트 값은 변..

2016. 2. 6. 15:32

[OS 개발 9] 32비트 커널 로더(3) - GDT의 개념과 적용

1. GDT의 개념 이전 포스팅을 마치면서 잠깐 GDT에 대해 언급하였습니다. 16비트 리얼 모드에서 32비트 보호 모드로 운영 모드를 바꿔야 하며, 이를 위해 GDT를 사용한다고 했는데요,. 본 포스트에서는 GDT 에 대해 알아보도록 하겠습니다. GDT를 풀어쓰자면 글로벌 디스크립터 테이블(Global Descriptor Table, GDT)이며, 말 그대로 무언가에 대한 기술서를 테이블 형식으로 한데 모아둔 형태를 의미합니다. 여기에서 무언가는 각 세그먼트 영역을 나타냅니다. 즉, 세그먼트 영역에 대한 데이터를 일정한 디스크립터 형식으로 기술하고 이를 하나의 테이블에 모아두고자 하는 것이 GDT를 사용하는 목적이죠. 그렇다면 이 디스크립터라는 녀석은 도대체 어떤 형식을 갖추고 있는 걸까요? 다음 그림..

2016. 2. 5. 15:30

[OS 개발 8] 32비트 커널 로더(2) - 리얼 모드와 보호 모드

32비트 보호모드로의 전환 전 포스팅에서 마지막에 16비트 모드에서 32비트의 전송 체계로 바꿔줘야 한다고 했습니다. 이게 무슨 의미 일까요? 부트로더의 개념 및 제작, 실행, 분석 포스팅에서 제작했던 부트 로더 프로그램은 사실 16비트 단위로 데이터가 처리되는 리얼 모드(Real Mode)에서 동작되고 있었습니다. 리얼 모드는 80286 이후의 x86 호환 CPU의 운영 방식입니다. 그런데 리얼 모드의 여러가지 한계, 혹은 문제로 인해 우리는 이후 커널 프로그램을 구동할 때에는 운영 모드를 바꿔줘야 합니다. 여기에서 우리는 32비트 보호 모드(Protected Mode)로 운영 모드를 전환할 것이다. 이렇게 운영 모드를 전환해줘야 하는 이유에는 여러가지가 있습니다. 1. 앞서 레지스터 세그먼트와 오프셋..

2016. 2. 5. 15:27

[OS 개발 7] 32비트 커널 로더(1) - 커널과 디스크 구조

1. 커널 로딩 드디어 OS의 핵심이라고 볼 수 있는 커널을 로딩하는 단계까지 왔습니다. 부트로더 포스팅만 해도 시간이 꽤 걸렸는데, 앞으로 커널 로더를 구현하는 부분은 얼마나 걸릴지 모르겠네요. 이전 포스트까지 디스크의 MBR 영역에서 부트 로더 프로그램을 읽어들이는 코드를 만들어 보았습니다. 그런데 512 바이트 영역은 내가 진짜 만들고자 하는 OS 프로그램을 넣어서 실행하기에는 굉장히 작은 공간이죠. 따라서 디스크 MBR 영역 다음의 영역에서 OS 커널 프로그램을 읽어들이고 이를 메모리 공간에 적재하는 과정이 필요합니다. 부트 스트랩 과정에서 5단계에 해당할 것입니다. 아래 링크를 통해 다시 한번 그 절차를 살펴보도록 하겠습니다. 2016/02/03 - [분석연구소/운영체제 구조] - [OS 만들기..

[OS 개발 6] 레지스터 세그먼트와 오프셋 개념

세그먼트:오프셋 주소 개념과 물리주소 변환 계산하기 레지스터의 종류에는 범용 레지스터, 세그먼트 레지스터, 컨트롤 레지스터 등, 다양한 역할을 담당하고 있는 레지스터들이 있는데, 이번 포스팅에서는 세그먼트 레지스터에 대해서 알아보도록 하겠습니다. 세그먼트 레지스터는 처음 인텔이 8086 CPU를 개발하는 과정에서 1Mb로 지정한 이유로 어드레스 버스와의 호환성 문제로 인해 사용하게 되었습니다. 어드레스 버스가 20비트가 필요함에도 불구하고, CPU는 16, 32, 64비트 단위로 호환되는 특성상, 20비트 어드레스 버스와 호환되기 어려웠기 때문입니다. 따라서 16비트 레지스터 2개를 이용하여 20비트 메모리에 접근하는 방식을 채택하였으며, 이를 위해 segment:offset 주소체계가 사용되었습니다. ..

2016. 2. 3. 14:12

[OS 개발 5] 부트로더의 개념 및 제작, 실행, 분석

1. 간단한 부트코드 입력 준비단계가 길었는데 이제 본격적으로 시작해보겠습니다. 우선, 우리는 부트스트랩의 첫 과정으로, 디스크의 첫 512b바이트를 읽어들이는 부분을 구현해야 합니다. 특별히 이 512바이트 영역을 MBR영역이라고 칭한다고 이전 포스트에서 언급했었습니다. 즉, 이번 포스팅에서 할 일은 부트 코드를 입력하고 부트 로더를 실행해 보는 것입니다. 그 전에, 제가 앞으로 포스팅할 때 설명하는 방식에 대해 간략하게 소개해 보도록 하겠습니다. 우선 아래 코드와 같이, 전체적인 코드와 함께 될 수 있으면 코드의 설명부분을 주석으로 처리할 것입니다. 만약 다음 포스팅 때 중복되는 내용이 있다면 건너뛸 수도 있습니다. 그리고 뒤에 [설명n]을 붙여놨습니다. 이는 해당 명령어가 무엇을 의미하는지 좀 더 ..

[OS 개발 4] 준비 단계(3) - 부트스트랩 과정

부트스트랩 대부분의 PC 부팅과정은 다음과 같습니다. 1. 컴퓨터가 구동되면 전기적 신호에 의해 메인보드에 이식되어있는 BIOS가 구동된다. 2. 이 후 POST 단계(Power On Self Test)를 통해 메모리와 하드디스크, 하드웨어를 자체적 으로 점검하기 시작한다. 3. CMOS 설정 정보를 읽어들이고 부팅에 필요한 정보를 획득한다. : CMOS는 현재 시간이나 하드웨어 정보(BIOS)를 보관하고 유지하기 위해 쓰이는 비 휘발성 메모리를 의미한다. 4. 하드디스크 첫 번째 섹터인 Master Boot Record(MBR)를 검사하고 이를 로드한다. : MBR은 전체 512Byte이다. (추후에 좀 더 구체적으로 설명하도록 하겠습니다). 5. 부트로더가 실행되어 커널을 메모리에 로딩(혹은 적재라고..

2016. 2. 2. 13:54

[OS 개발 3] 준비 단계(2) - 레지스터와 어셈블리 명령 체계

1. 어셈블리 언어? OS를 제작하는 과정에서 우리는 어셈블리 언어와 맞닥뜨릴 것입니다. 그런데 이 어셈블리 언어가 그리 쉽지만은 않습니다. 저도 그 동안 프로그래밍을 해오면서 거의 C++이나 자바와 같은 하이레벨(High Level) 언어를 위주로 주로 공부했을 뿐, 로우 레벨(Low Level) 언어에 대해 제대로 공부해보기는 사실상 처음인 것 같고 어려움을 느꼈습니다. 하지만 운영체제 구축이 주 목적인 만큼, 우리는 어셈블리 언어에 대해서 잘 알아야만 합니다. 뿐만 아니라, 어셈블리 언어에 대해 공부하면 추후에 디스어셈블링 기술을 배울때도 유용합니다. 디스어셈블링 기술은 이미 제작된 소프트웨어를 역으로 해부하여 소스코드를 분석해내는 기술인데, 이때 어셈블리 언어 해석 능력이 매우 유용하게 작용합니다..

2016. 2. 2. 13:05

[OS 개발 2] 준비 단계(1) - 제작 환경 구축

제작을 위한 준비 본격적으로 OS제작에 앞서 몇 가지 준비물이 필요합니다. 1. NASM 먼저 우리는 앞으로 OS를 제작하기 위해 어셈블리어를 자주사용하게 될텐데, 이를 CPU가 인식할 수 있는 기계어로 변환하는 작업이 필요합니다. 이미 OS를 제작한 선구자들이 이러한 과정에서 편의를 위해 NASM이라는 컴파일러를 제작했습니다. 사실 카와이 히데미씨가 제작한 NASK라는 컴파일러도 있긴 하지만 이는 사용하지 않기로 했습니다. 일단 아래 사이트에서 NASM을 다운받아 봅니다. http://www.nasm.us/ 사이트에 접속하면 아래와 같이 링크를 통해 다운받으면 됩니다.(참고로 저는 꽤 옛날 버전인 0.99버전을 받았습니다. 일부 블로거 분들 글을 보니 최신 버전이 호환문제로 나중에 무한 재부팅과 같은 ..

2016. 2. 2. 11:41

[OS 개발 1] 첫 시작

운영체제(Operating System, OS) 만들기에 앞서 그 동안 프로그래밍을 공부하면서 운영체제에 대해서도 계속 공부해야겠다는 생각을 가지고 있었지만 그러지 못했습니다. 이제는 험난했던 대학원 생활도 끝났고 입사를 앞둔 상황에서 OS를 꼭 공부하고, 특히 블로그를 통해 그 과정을 정리하기로 했습니다. 그런데 막상 시작하려고 하니 어디서부터 손을 대야 하나 감을 잡지 못했죠. '무조건 책부터 사야하나?''다들 구글링을 하던데 구글 검색만으로도 OS 공부가 가능할까?' 그 시작 방법조차 여의치 않아서 OS 처음 공부 방법을 좀 찾아봤더니 OS를 직접만들고 이를 공유하는 사람들이 꽤 있다는 사실을 알아챘습니다. 나는 왜 그 동안 OS를 직접 만들어볼 생각을 못했는지,,그런데 그 블로거들의 공통점은 대부..