Be myself :: '컴퓨터구조&OS' 카테고리의 글 목록

달력

092017  이전 다음

  •  
  •  
  •  
  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

'컴퓨터구조&OS'에 해당되는 글 9건

  1. 2014.05.05 7. 페이징
  2. 2014.05.05 6. 유저모드 Task switching
  3. 2014.05.05 5. 보호
  4. 2014.05.05 4. Task switching
  5. 2014.05.05 3. 인터럽트 처리
  6. 2014.05.05 2. Protected 모드로의 전환
  7. 2014.05.04 폰노이만 구조
  8. 2014.05.04 메모리 구조
  9. 2014.05.04 1.OS의 시작

1 개요

페이징 기법을 이해하면 RAM이 512Mbyte 밖에 안되는데 32비트 시스템에서 4G에 해당하는 메모리를 각 프로세스마다 할당되는지 이해 할 수 있을 것이다.

*선형주소: 프로그램상에서 만들어진 주소
물리주소: 실제 하드웨어인 RAM의 핀에 전기신호를 주어 위치를 지정하는 주소

2 페이징 구현

2-1 A20게이트

16비트 리얼 모드에선 오프셋 값으로 물리주소를 지정하는데, 0xFFFF:FFFF의 경우 물리주소로 나타내면 0x10FFEF이다. 이를 이진수로 나타내면 100001111111111101111이다. 과거 8086CPU에서 어드레스 라인이 0번에서 19번으로 20개가 존재했기 때문에 위의 주소에서 최상위 비트 1은 제외되었었다. 하지만 80286이 도입되면서 어드레스 라인이 24개가 되어 21번째 피트가 제외될 필요가 없게 되었다. 하지만 과거 8086CPU의 호환성 문제 때문에 A20에 키보드 컨트롤러를 AND게이트로 묶어 활용하게 되었다. 키보드 컨트롤러가 1이면 20번째 비트는 사용가능하고, 0이면 사용 불가능하다. 만약 A20게이트가 0이라면 홀수의 주소밖에 사용 할 수 없기 때문에 32비트로 완벽히 전환하려면 보통 A20게이트를 키고 프로그램을 짠다.

2-2 페이징 구현

페이징 구현의 과정을 그림을 통해 설명하겠다. 페이지 디렉토리의 크기는 1KB이고 총 1024개의 디렉토리 엔트리로 이루어 져 있다. 페이지 테이블의 크기도 1KB이고 총 1024개의 테이블 엔트리로 이루어져 있다. 1개의 페이지 디렉토리와 1개의 페이지 테이블로 총 4KB의 값을 표현할 수 있으므로 전체 표현 가능한 주소의 크기는 페이지 디렉토리 1KB X 페이지 테이블 1KB X 총 4KB페이지 = 4G 라는 값이 성립된다.

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

7. 페이징  (0) 2014.05.05
6. 유저모드 Task switching  (0) 2014.05.05
5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
Posted by flack3r

1 개요

유저모드의 Task switching 이 어떻게 일어나는지 살펴보고, 그를 위해 준비해야 할 것들이 무엇인지 알아보자. 여기서 주목할 점은, 태스크 스위칭에 따른 스택과 메모리의 변화가 어떻게 되는지 이다.

2 유저모드 태스크 스위칭

2-1 설정할 것

먼저 당연한 것이지만, 유저모드 세그먼트를 설정한다. GDT테이블에 DPL값3으로 등록하고, 디스크립터 셀렉터 번호도 RPL값 3으로 설정한다. 다음으로 콜게이트를 설정한다. 태스크 스위칭을 할 때, 콜게이트를 이용하여 할 것이기 때문이다.

2-2 커널->유저모드

먼저 또한 각 세그먼트들을 유저 데이터 셀렉터로 변경하고 esp도 유저모드가 쓸 esp로 변경한다. 그리고 여기서 우리는 하나의 트릭을 이용할 것이다. 앞 장에서 콜게이트가 호출 되었을 때 유저->커널과 커널->유저모드로 스택이 어떻게 변하는지 살펴 봤다. 우리는 커널->유저모드로 스택이 변해가는 과정을 이용할 것이다. 즉, 스택에 SS, ESP, CS, EIP, ES, EAX등을 PUSH하고 iret명령을 사용한다면, 자동적으로 레지스터 값들이 POP되면서 유저영역의 레지스터 들로 맞추어 져 모드 전환이 이루어 진다.

2-3 유저모드 멀티태스킹

유저모드에서 멀티태스킹이 어떻게 이루어 지는지 살펴보자. 유저모드에서 콜게이트나 트랩게이트를 이용하여 커널모드로 접근 했을 시 스택이 어떻게 변하는지 앞에서 살펴 보았다. 다시 한번 그림으로 파악해 보자.

이렇듯, 모드 전환이 이루어 지면 각종 레지스터의 값들이 자동적으로 스택에 PUSH된다. 이 점을 이용하여 FLAG값이나 DS값들 등 다른 값들도 PUSH한 후 별도로 마련해 놓은(TSS영역의 역할과 같다)메모리에 저장하고, 모두 저장하고 난 후 ESP값을 조절 한 후 새로 실행할 프로세스의 레지스터 저장 영역에서 값을 PUSH하여 콜게이트 핸들러의 수행명령이 끝난 후 iret명령으로 인하여 레지스터 들은 새로 실행할 프로세스의 레지스터로 세팅되고 결과적으로 컨텍스트 스위칭이 일어난 것이 되었다.

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

7. 페이징  (0) 2014.05.05
6. 유저모드 Task switching  (0) 2014.05.05
5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
Posted by flack3r

5. 보호

컴퓨터구조&OS/OS 2014.05.05 21:23

1 개요

CPU는 때때로 커널과 함께 명령어들을 체크해 문제가 일어나지 않도록 검사한다. 합당한 명령어만 실행시키고 그렇지 않으면 커널이나 유저프로그램 자신이 이 에러를 다시 조정하도록 한다. 이 때, 체크하는 것으로는 다음과 같은 것이 있다.
1.프로그램 또는 프로세스가 세그먼트 외의 메모리 위치를 지정하지 못하게 하는 Limit Check
2.읽기, 쓰기 등의 속성에 맞게 접근되었는지 확인하는 type검사
3.접근 가능한 곳에 접근하는지 확인하는 특권레벨 체크,
4.명령어 세트 체크

위의 4가지를 검사하는데, 우리는 특권레벨과 관련된 내용을 공부할 것이다.

2 특권레벨

특권레벨과 관련된 용어를 설명하고, 특권레벨이 낮은 계층에서 레벨이 높은 계층으로 접근하는 방법들과 그 때의 스택의 변화를 알아볼 것이다.

2-1 용어 설명

-CPL(Current Privilege Level)
: CPL은 현재 실행되고 있는 특권레벨이다. CS, SS셀렉터 레지스터의 0,1번째 비트에 있는 수이다.

-DPL(Description Privilege Level)
: 디스크립터에 기재된 DPL값이고 2비트로 표현된다. 디스크립터를 통한 세그먼트 영역으로의 모든 접근에서 항상 CPL과 DPL의 관계가 체크된다.

-RPL(Requested Privilege Level)
: 콜게이트(낮은 특권레벨에서 높은 특권레벨의 루틴을 사용할 수 있게 하는 관문)를 통해 레벨이 낮은 프로세스가 높은 프로세스에 접근하는 일이 생기는데, 이를 악용할 소지를 없애기 위해 어느 레벨에서 요청했는지 적어놓는 역할을 한다.

-콜게이트
: 다른 세그먼트 디스크립터와 함께 GDT테이블에 디스크립터로써 포함되며, 또 하나의 세그먼트 정의라 셍각하여도 좋다. 유저 프로그램은 코드 셀렉터의 사용법과 마찬가지로 이 디스크립터를 셀렉터로 설정하여 Jmp나 Call명령을 내린다.

<콜게이트 디스크립터>

 

2-2 특권계층 변경

특권계층이 변경되는 상황을 알아 보겠다.
예외가 발생했을 때. (0으로 나눈다던지, Limit크기를 넘어 가는 접근을 한다던지 등)
하드웨어 인터럽트가 발생 했을 때
소프트웨어 인터럽트가 발생 했을 때(int 0x80 명령어로 트랩 게이트이용)
콜게이트 이용—Jmp, Call

이 중, 1번과 2번은 프로그래머의 의지와는 상관 없이 레벨변경이 일어나는 상황이므로, 우리가 관심을 가져야 할 부분은 3번과 4번이다. 3번의 경우, eax, ebx, ecx등의 레지스터를 이용해 인수를 정하고, int 0x80명령어로 인터럽트하는 수순으로 이루어 진다. 보통 셸코드 작성시 많이 사용하는 방법이다.

콜게이트를 이용해 계층을 변경하는 방식으론 Jmp와 Call이 있는데 원칙적으론, Jmp명령을 사용하여 계층변경은 불가능하지만 콜게이트를 이용해 가능하게 된 것이고, Call 명령은 낮은 특권계층에서 높은 특권계층으로의 접근을, RET는 높은 계층에서 낮은 계층으로의 전환을 담당한다.

Call 명령을 통해 계층변환이 이루어 지는 방식은 레벨3에서 call 명령으로 레벨0 루틴을 불러 내면 CS셀렉터의 0,1의 비트에 00 이 들어가고, 이때의 CPL은 0이다. 루틴이 끝난 후 RET로 레벨3으로 돌아가게 되는데 이때는 CS셀렉터의 0,1비트에 11(십진수 3)이 들어가고 CPL은 3이된다.

 

2-3 특권레벨 변동시 스택의 변화

일단 설명을 먼저 한 후 그림을 통해 정리하드록 하겠다.

<Call 명령이 내려졌을 때>

CPU는 이 태스크의 TSS영역에 있는 SS0와 ESP0값을 참조하여 커널모드 스택에 현재 유저태스크가 사용하고 있는 SS,ESP,CS,EIP를 차례로 PUSH한다. 그리고 SS와 ESP레지스터에 SS0와 ESP0의 값을 넣는다
콜게이트에 지정된 커널모드의 루틴주소로 점프하고 실행
RET명령시 스택에 저장된 EIP, ESP등을 pop하여 원레 레지스터 값으로 복원한다.
*인자가 있을 시 콜게이트 디스크립터에 입력된 인자의 갯수 만큼을 준수한다.

<인터럽트 예외가 발생 했을 때>

이 때는 EFLAGS가 ESP와 CS사이에 추가된 것만 빼면 콜게이트와 다를 것이 없다. 단지 특권계층 0 에서 인터럽트가 발생하면 ESP와 SS는 PUSH될 필요가 없다는 것만 주의하면 된다.

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

7. 페이징  (0) 2014.05.05
6. 유저모드 Task switching  (0) 2014.05.05
5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
Posted by flack3r

1 개요

이제 OS의 핵심적인 역할이라 볼 수 있는(필자의 생각에..ㅎㅎ) 멀티 태스킹이 어떻게 구현되는지 살펴보겠다. 일단, 커널단 에서의 멀티 태스킹을 살펴보고, 다음 장에서 세그먼트 보호의 개념을 다룬 후 유저영역에서의 멀티 태스킹을 살펴볼 예정이다. CPU에서 지원하는 멀티 태스킹 기술은 2가지가 있다. Call과 Jmp를 이용한 방법이 그것이다. 각 방법들을 하나하나 살펴보자.

2 태스크 스위칭과 tss

참고로 Real mode에선 멀티 태스킹이 지원이 되지 않는다. 따라서 멀티 태스킹은 protected mode에서 작동되고 인텔 80286이상에서 태스크 스위칭을 cpu레벨에서 지원한다.
여기서 멀티 태스킹이 무엇인지 짚어보고 가자. 말 그대로 음악을 들으면서 문서작업을 하거나 영화를 보면서 인터넷을 하거나 등의 여러 가지 일을 동시에 하는 것을 나타낸다. 하나의 프로그램을 실행시켰을 때, 하나의 '프로세스'가 생성되는데, cpu는 동시에 같은 프로세스를 처리 할 수 없다. 그렇다면 어떻게 멀티 태스킹이 된단 말인가?
이는 컨텍스트 스위칭 이라는 마술적인 기법을 사용하기 때문이다. 일정한 시간이 되거나, 어떠한 조건이 만족되면, OS의 스케줄러는 실행되고 있는 프로세스관련 메모리를 어떠한 메모리 영역에 저장을 하고 새로 시작되는 프로세스의 메모리들을 로드시켜 연산을 하는 것이다.
그렇다면 어떠한 메모리 영역에 저장을 시켜야 할까? 그것이 바로 TSS(Task state segment)이다.

TSS를 등록하기 위해선 TSS디스크립터를 GDT에 지정시켜 둔다.일단, TSS의 생김새부터 보고 가자.

그림의 설명을 보면 이해가 될 것이다.

그 다음 TSS를 선택하는 TSS세그먼트 디스크립터를 볼 순서인데, GDT의 생김새와 별 차이가 없고 Limit부분이 항상 0x67이상이어야 한다는 점과, Type에 B비트가 있는데, 이 부분은 이 태스크가 실행 중인지 혹은 실행을 기다리고 있는지를 나타내는 점이 다를 뿐이다. 따라서 별도의 그림은 생략한다.

2-1 JMP를 이용한 스위칭

지금까지 기본 배경지식을 알아 보았고 JMP를 이용한 스위칭 과정이 어떻게 되는지 그림을 통해 설명하겠다.

1. 프로그램이 Protected mode로 넘어오고 LTR명령으로 TSS영역을 저장한 후에 JMP TSS selector명령을 한다.
2. CPU내부의 TR레지스터와 GDTR레지스터를 참조하여 GDT에 있는 TSS selector를 찾는다.
3. TSS selector의 base Address를 참조하여 tss1영역을 찾는다.
4. Tss1영역에 현재 CPU레지스터값 저장
5. GDT에서 Tss2 디스크립터를 찾는다. 이 때, TR레지스터에 Tss 2 selector가 들어간다.
6. Tss 2 selector의 base Address를 참조하여 tss2 영역을 찾는다.
7. Tss2영역의 값 복원
8. 프로그램 실행.

2-2 Call명령을 이용한 스위칭

Call방식이 Jmp방식과 다른 점은 명령어 상에서 Jmp대신 Call을 한다는 점과 이전 태스크로 돌아가는 부분이 IRET로 바뀌는 것 뿐이다. 여기서 주의할 것은 IRET명령어가 인터럽트의 끝을 알리는 명령어와 동일하기 때문에 이를 구별하기 위해 TSS디스크립터의 B비트와 EFLAGS의 NT비트를 이용한다.

또 다른 차이점은 Call명령의 경우 비선점형 방식이라 실행되는 태스크에서 다른 태스크로 전환하는 명령을 수동으로 해 주어야 하는 반면 Jmp명령어는 컨텍스트 스위칭이 자유롭긴 하지만 유저모드의 태스크를 스위칭 하는데에는 약간의 문제점을 가지고 있다.

그럼, Call명령을 사용한 스위칭의 과정이 어떻게 이루어 지는지 그림을 통해 정리하고 끝을 내겠다.

 

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

6. 유저모드 Task switching  (0) 2014.05.05
5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
메모리 구조  (0) 2014.05.04
Posted by flack3r

1 개요

인터럽트는 일반적인 의미로는 무엇인가를 방해한다는 뜻이다. 하지만 컴퓨터에선 방해한다는 의미보단, 우선순위가 높은 일을 먼저 처리하라고 알려주는 의미가 더 강하다. 인터럽트에 의해 우리는 마우스의 움직임, 키보드의 입력 등을 처리할 수 있는 것이다. 그렇다면 이러한 인터럽트를 어떻게 커널에서 처리하는지 그림으로 대략적인 개념을 잡고 가겠다.

 

 

 

 

 

 

 

 

 

 

 

 

 

2 PIC란??

인터럽트의 처리루틴을 가진 테이블(IDT)를 알아보기 전에 PIC의 개념을 잡고 가자. PC는 모든 외부로부터의 인터럽트(모니터, 마우스, 프린터, 스피커 등)을 8259A라는 칩을 통하여 입력 받는다. 이 8259A를 보통 PIC라 부른다. 여기까지만 말하면 PIC와 IDT가 무슨 연관인지 궁금해 질 것이다. 인터럽트가 처리되는 과정은, PIC에서 IRQ(인터럽트 처리 요청)을 받아 CPU의 INT포트에게 신호를 보내고, CPU에선 이 IRQ 번호를 이용해 IDT테이블에서 어떤 핸들러를 실행 시킬지 선택한 후, 인터럽트를 처리시킨다. 좀더 자세한 과정을 그림을 통해 알아보자.

Master PIC와 Slave PIC 각각의 작동순서를 살펴보면서 큰 흐름을 잡자. 일단 하인(?) 은 주인(?)의 IRQ 2번에 연결되어 있다. (왜 2번인지는 IBM의 고객센터에 따지자.) 그리고 각 장치들에서 IRQ요청이 왔다는 가정을 하자.

2-1. Master PIC동작 순서

자신의 INT핀에 신호를 실어 CPU의 INT피에 신호를 준다.
CPU는 이 신호를 받아 EFLAGS의 레지스터의 IE비트가 1로 세팅되어 인터럽트를 받을 수 있는 상황이라면 /INTA를 통해 마스터 PIC에 인터럽트를 잘 받았다는 신호를 보낸다.
마스터 PIC는 /INTA신호를 받고 몇 번째 IRQ에 연결된 장치에서 인터럽트 신호를 받았는지 숫자로 데이터 어드레스로 CPU에 전달한다.
CPU는 Protected Mode로 실행 중 이라면, 이 값을 리맵핑하여(IRQ번호를 바꿈) IDT에서 그 번호에 맞는 디스크립터를 찾아 처리한다.

여기서 리맵핑을 하는 이유는, 하드웨어 인터럽트와 예외상황 에서의 인터럽트를 구분하기 위해서 이다. CPU는 프로그래머가 시스템에 크거나 작은 충격이나 오류를 줄 수 있는 명령어를 실행시키는 것을 방지하기 위하여 예외처리를 하는데, 이 때 IRQ의 번호가 0번부터 시작해 PIC에서 받은 IRQ번호와 충돌이 일어 난다. 따라서, PIC에서 받은 IRQ번호를 리맵핑 한다.

2-2. Slave PIC동작 순서

자신의 INT핀에 신호를 실어 마스터 PIC의 IRQ2번핀에 인터럽트 신호를 보낸다.
마스터 PIC는 자신의 INT번호에 신호를 실어 CPU에게 전달한다.
그 이후는 마스터PIC의 처리 순서와 동일하다.

2-3. PIC초기화

PIC를 제대로 동작시키게 하기 위해선, PIC를 초기화시킬 필요가 있다. 각 PIC가 자신이 마스터인지 슬레이브인지 알아야 하고, 어떤 모드로 움직일지 등을 설정해야 하기 때문이다. 초기화 명령 프로그램의 구성은 ICW1, ICW2, ICW3, ICW4로 구성되는데 ICW는 하나의 명령어로 생각하자.

ICW1.

ICW2

ICW2는 PIC가 인터럽트를 받았을 때, IRQ번호에 얼마를 더해 CPU에게 알려줄지 지정한다. 즉 IRQ번호 리맵핑의 역할을 한다.

ICW3
PIC의 마스터, 슬레이브로서의 연결방법을 나타낸다. (마스터PIC)
S0~S7은 마스터 PIC의 각 IRQ선을 나타낸다. 각 비트에 0을 넣으면 그 IRQ선은 하드웨어 장치에 연결되어 있다는 것을 뜻하고, 비트에 1이 있으면, 그 IRQ선은 슬레이브 PIC가 연결되어 있다는 것을 나타낸다. (슬레이브 PIC)
3~7비트는 0으로 해두고 ID0~ID2는 Slave PIC가 Master PIC의 몇 째 IRQ에 연결되어 있는지 나타내는데 마스터 PIC에선 1로 나타내는 반면 여기선 숫자로 나타낸다.

ICW4

3 idt의 동작

PIC에서 인터럽트가 와 이를 CPU에서 어떤 순서로 처리하는지 등을 알아 보겠다.

3-1. Idt등록

동작 순서를 알아 보기 전에 IDT(Interrupt Descriptor Table)이 어떻게 생겼는지 알아 보자.

P는 페이지와 관련되어 있는데 항상 1이다 DPL은 핸들러가 실행될 특권레벨을 나타내고, D는 0이면 16비트, 1이면 32비트임을 나타낸다.

이러한 IDT를 IDTR레지스터에 등록하여 참조될 수 있도록 한다.

3-2 IDT동작 순서

그림으로 정리하고 이번 장을 마치겠다.

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
메모리 구조  (0) 2014.05.04
1.OS의 시작  (0) 2014.05.04
Posted by flack3r

1 개요

GDT(Global Descriptor Table)란 각종 Descriptor의 테이블을 가지고 있는 것이다. 각종 세그먼트나 여러 가지 테이블들이 어떻게 구성되어 있는지 적어놓은 하나의 메모장이라 생각하여도 좋다. 필요성은 첫째, Real mode 에서 Protected 모드로 전환하기 위해 필요한 것이다. 각 세그먼트들을 나누어야 세그먼트들의 접근 유무를 확인할 수 있기 때문이다. 둘째, GDT는 IDT(Interrupt descriptor table)의 주소 값을 가지고 있어 인터럽트가 발생 하였을 때 어떤 처리를 할 것인지 결정하는 첫 번째 역할을 한다. 이 설명만으론 뭔가 부족하다. 다음 그림은 GDT가 설정되지 않았을 때 보이는 현상이다. 마우스를 표현 하였지만, 마우스가 움직이질 않는다. GDT에 IDT등록을 하지 않아서 이다.

그냥 그림이라 마우스가 움직이는지 그렇지 않은지 직접 확인은 하지 하지만, 움직이지 않는다.(믿어달라. 혹시 직접 확인해 보고 싶은 사람은 'OS구조와 원리'책을 참고하기 바란다.)

그럼, GDT가 왜 필요한지 알았으니, GDT를 만들어 어떻게 Protected모드로 전환되는지 먼저 살펴보고, 다음 글에서 인터럽트와 함께 IDT에 관한 부분을 살피겠다.

먼저 어떠한 순서로 Real Mode에서 Protected mode로 전환되는지 살펴 보겠다.

GDT 만들기 Protected Mode 레지스터 세팅 파이프라인 지우기 prefix를 사용한 점프

* real mode와 protected mode

real mode는 16비트로 동작하고, pc가 부팅할 때 처음 동작하는 cpu모드 이다. 이 영역에선 주소설정을 자유롭게 할 수 있어 악의적인 프로그래머가 커널영역의 메모리를 자유롭게 사용할 수 있어 os를 파괴하거나 등의 보안상의 문제가 발생할 수 있다.

반면 protected mode는 32비트로 동작하고, 각 세그먼트들의 속성값을 설정하여 각 세그먼트들의 접근을 보호한다.

2 protected mode로의 전환

2.1 GDT만들기

일단 GDT테이블에 등록되는 디스크립터의 생김새를 살펴 보자.

Limit 0~15bit

Base Address 0~15bit

P

DPL

S

type

Base Address 16~23bit

Base Address 24~31bit

G

D

0

AVL

Limit 16~19bit

<GDT 디스크립터>

위 그림에 대해 설명하자면, P는 페이징 기능과 관련되어 있고 일반적으로 1을 나타낸다. DPL은 보안과 관련되어 있는데 커널 레벨인지 유저레벨인지 나타낸다. 만약 셀렉터 레지스터의 RPL이 DPL보다 레벨이 높을 경우(예를 들어 유저영역에서 커널 영역으로 접근하려 할 시) 접근하지 못하도록 차단한다. S는 시스템 세그먼트인지 코드 세그먼트인지를 나타내고 type은 읽고 쓸수 있는지, 실행할 수 있는지 등을 나타낸다. G는 세그먼트 크기 단위를 나타내는데 0이면 BYTE고 1이면 4KB이다(즉, 4G사용) D비트는 이 세그먼트가 16비트인지 32비트로 작동하는지를 나타 낸다. Limit는 세그먼트 크기이고 Base Address는 세그먼트의 첫 시작 주소를 나타낸다. Base Address와 Limit가 왜 이렇게 나누어져 있는지는 예전 cpu와의 호환성 때문이다.

2.2 Protected mode 레지스터 세팅

이렇게 여러 개의 디스크립터로 만들어진 GDT를 등록해야 하는데, 이를 GDTR이라는 레지스터에 등록한다. 이 레지스터는 48비트 크기로 첫 16비트는 GDT의 크기가, 나머지 32비트엔 GDT의 시작주소가 물리주소로 들어간다.

이렇게 설정하면, 주소 지정은 어떻게 이루어 지는지 살펴보자. 세그먼트 레지스터는 16비트의 셀렉터 레지스터(CS,DS 등등..) 와 64비트 디스크립터 레지스터로 나뉘는데, 프로그래머가 사용할 수 있는 것은 셀렉터 레지스터일 뿐이다. 디스크립터 레지스터는 GDT디스크립터와 모양이 비슷하고 셀렉터 레지스터의 모양을 살펴 보자.

Index

TI

RPL

인덱스 값은 GDT에서 찾는 디스크립터가 어디에 위치하는지 찾는 값이고 RPL은 이 세그먼트가 커널영역인지 유저영역인지 확인하는 역할을 한다.

그럼 셀렉터 레지스터에 값을 넣었을 때 어떻게 동작하는지 살펴 보겠다.

그렇다면, 결과적으로 지금까지 디스크립터 레지스터에 값을 넣기 위한 일을 한 것이다. 이렇게 구한 디스크립터 레지스터의 Base Address의 값을 통해 Protected 모드에서의 주소 지정방법을 설명할 수 있다. 예를들어 [ds:0x65]라고 한다면, 0x65와 limit를 체크하여 세그먼트 크기를 넘지 않는지 확인하고 넘지 않는다면, Base Address의 값과 0x65의 값을 합하여 물리주소의 값을 구한다.

2.3 파이프라인 지우기

우선 파이프라인을 지우기 전에 CR0의 레지스터의 최하의 비트를 1로 바꾼다. 이 비트는 pe비트라고 하며 1로 바꾸면 32비트 시스템으로 동작한다.

CPU가 연산할 때, I/O bus interface에서 명령어를 가져오고, 해석하고, 실행하고, 데이터 메모리 엑세스등의 단계를 거치는데, 단계들 마다 명령어를 각각 실행시켜 빠르게 하는 것을 파이프 라이닝 이라 한다. 쉽게 말하자면, 각 단계들을 수행하는 장치들이, 하나의 명령어를 처리하고, 그 명령어의 단계가 끝날 때까지 기다리는 것이 아니라, 다음 명령어의 그 단계를 처리한다면 더 빠르게 처리할 수 있다는 것이다. 더 자세한 사항은 기회가 되면 설명하도록 하겠다. 이러한 특성 때문에 Real mode의 16비트에서 Protected mode의 32비트로 전환 시, 현재 Excute되는 명령어만 바꾸어야 할 뿐만 아니라 cpu유닛에 남아있는 다른 단계들의 값들을 지우거나, 32비트로 바꾸어 주는 과정을 거쳐야 한다. 여기서 바꾸어 주는 과정은 따로 명령어가 없기 때문에 불가능하고, 지우는 방법을 택한다.

2.4 Prefix를 사용한 점프

16비트 레지스터에서 32비트 레지스터로 바꾸기 위해 명령어에서 제일 앞에 0x66과 0x67을 붙이면 된다. 혹은 32비트에서 16비트로 변형시킬 때도 쓰인다. 0x66은 operand prefix인데, 명령어의 오퍼렌드의 값을 변형시킨다. 0x67은 address prefix인데 대상 주소값을 변형 시킨다.

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
메모리 구조  (0) 2014.05.04
1.OS의 시작  (0) 2014.05.04
Posted by flack3r

 

개요

앞서 폰 노이만의 구조에 대해 살펴 보았고, 이제 그러한 구조(Stored program concept) 속에서 프로그램이 어떻게 동작하는지 알아보겠다.

 


테스트 환경 (해당 될시에만)

 

 운영 체제 (OS) : Windows 7

 


 

상세 분석

 

 

 

필자의 그림이 마음에 안들더라도 참고 봐 주었으면 한다.(그림판으로 처음 그린다..) 위의 그림은 컴퓨터 내부 구조를 간략하게 표현한 것이다. 프로그램이 실행 되는 과정에 따라 살펴보자. 

1. 첫번째, fetch

메인 메모리에서 명령어가 순차적으로 I/O bus(address Bus, Data Bus, control Bus로 구성 되어 있다.) 에서 Data Bus를 통해 cpu의 bus interface에 전달된다. 사실 이 과정이 일어나기 전에 가상메모리 기법(페이징 기법)을 통해 프로세스 별로 4G의 메모리를 할당 받고, HDD에 있는 데이터(명령어)들을 가상메모리에 위치 시키는 과정 (windows 에서는 PE구조등의 원리를 통해, linux 에서는 elf[Executable and Linkable Format]를 통해) 이 이루어 진다. 이러한 과정은 다음에 설명 하도록 하자. 

 

2. 둘째, Decode

bus interface에 전달된 명령어는 먼저 레지스터(eip레지스터)에 전달되고, 이 명령어는control unit을 통해 어떤 명령어 인지 해석하는 과정이 일어난다.

 

3, 셋째, Excution

컨트롤 유닛을 통해 해석된 명령어를 실행되는 과정이다. 이 과정은 명령의 종류에 따라 다르다. 산술 처리 명령(사칙연산 등)은 레지스터를 통해 연산하는 과정을 거치고, 명령 흐름 변경 명령(jmp명령등. 이러한 상황은 함수가 리턴 되거나 조건 분기 문(if,while,for문 등)을 통해 일어난다.) 은 pc레지스터에 다음에 실행될 명령어를 넣는 작업을 하고, 데이터를 주고받는 명령의 경우 레지스터와 데이터를 주고 받거나 I/O bus를 통해 데이터를 메인 메모리와 주고 받는다. 

 

4. 클럭

정리하자면, 전체적인 프로그램의 실행 단계는 위의 3단계를 거친다. 하지만 부가적으로 위의 그림에서도 보이듯이, 모니터나 그래픽카드, 마우스, 키보드 등.. 여러가지 장치들이 IO bus에 연결되어 있는 것이 보인다. 이것이 뜻하는 바는 cpu가 메인메모리에서 프로그램의 실행 명령을 읽어 각 모니터에 화면의 픽셀 정보를 뿌려주고나 마우스의 동작을 읽어 변수에 저장하여 프로그램의 흐름을 바꾸거나 하는 등의 과정이 일어나는 것을 의미한다. 하지만 이러한 과정이 오류없이 잘 일어나게 하기 위해선 각 장치간 속도를 맞춰주어야 하는데, 이 때, '클럭'이라는 기법을 도입하게 된다. 

예를 들어

연산장치 -----> BUFFER -----> 출력장치 

이러한 과정이 일어난다고 해보자. 

이때, 연산장치의 속도가 출력장치의 속도보다 더 빠르다고 가정해보자.

그렇게 되면, 출력장치는 버퍼의 데이터를 받아 가져가게 되는데 속도가 연산장치보다 느리기 때문에 buffer가 넘치게 되고 buffer에 들어 오는 데이터는 중첩되어 데이터 손실이 일어나 문제가 발생한다.

출력장치의 속도가 연산장치보다 빠르다고 할 경우 출력장치는 버퍼의 내용을 다시한번 가져가 같은 내용을 두번 출력하는 문제가 발생한다. 이 문제를 해결하기 위해 , CPU는 클럭 신호에 맞추어 연산을 한다.(이러한 원리는 조합 논리회로의 특성을 이용한 것인데 이에 대해선 논리회로 관련 책이나 사이트를 참고하자.)

 

참고 URL 및 도서

뇌를 자극하는 윈도우즈 시스템 프로그래밍 -윤성우

- windows 구조와 원리 -정덕영 

- 뇌를 자극하는 프로그래밍 원리 -한세경

 

신고

'컴퓨터구조&OS > 컴퓨터구조' 카테고리의 다른 글

폰노이만 구조  (0) 2014.05.04
Posted by flack3r

 

테스트 환경 (해당 될시에만)

 

 운영 체제 (OS) : Windows 7

 


 

상세 분석

 

프로그램을 실행 시킬때, 명령어나 여러가지 데이터들이 프로세스별로 메모리(일반적으로 RAM)에 올라가게 된다. 여기서 프로세스란 컴퓨터에서 실행되고 있는 프로그램으로 간단히 생각해도 좋다. 이 때, 32bit 시스템 기준으로 OS는 가상메모리 4G를 할당하게 된다. 그리고 각 데이터들은  편리성,보안성 등의 이유로 각 세그먼트로 나뉘어 메모리에 올라가게 된다. 이 세그먼트에는 프로그램의 명령어 코드가 있는 코드 세그먼트,초기화된 전역변수나 static변수들이 위치하는 데이터 세그먼트, 초기화 되지 않은 변수들이 위치하는 Bss 세그먼트, 동적 메모리 할당을 위한 힙 세그먼트, 지역변수 들을 위한 스택 세그먼트 등으로 나눌 수 있다. 전체적인 구조를 보고, 각 세그먼트들이 어떻게 동작하는지 살펴 보도록 하자.

 

1. 전체적인 구조 

 

 

 위의 그림에서 보이듯 메모리 영역은 일반적으로 커널영역 1~2기가, 유저영역 2~3기가 가 할당 된다. 여기서 퀴즈를 내겠다. 유저 영역은 각각 프로세스별로 할당 된다는 것은 직관적으로 알 수 있다. 커널영역도 각 프로세스별로 독립적으로 할당 되겠는가? 답은 커널영역은 프로세스가 공유하며 같이 사용한다. 지금부터 각 영역이 어떤영역인지 설명을 하겠다.

 

2. 코드영역(code segment)

 

여기는 instruct code가 위치하게 되며, 읽기만 가능하고 쓰기는 불가능하다.

 

3. 초기화된 데이터영역, 초기화 되지 않은 데이터 영역,stack 영역(data segment,bss segment,stack segment)

 

말 그대로 처음 초기화된 데이터가 저장되는 영역이다. 초기화된 전역변수나 static 변수는 data segment에 저장되고 초기화 되지 않은 전역변수나 static변수는 bss segment에 위치한다. 그렇다면 지역변수는 어디에 위치할까? 지역변수들은 stack 영역에 함수의 호출과 반환의 과정에 있어서 데이터가 저장된다. 이 부분은 그림을 통해 살펴보자.

 

 

위의 코드는 전역변수 global과 지역변수 local을 3으로 초기화 하고, notdeclare변수를 초기화 하지 않은 상태로 선언한 간단한 코드이다. 이 코드가 어떻게 어셈블리로 변한되어 지는지 살펴 보겠다.

 

 

 

위의 그림은 main함수 부분을 diassemble한 것이다.  빨간색 박스로 표시된 부분을 살펴 보면, [ebp-4] 부분에 3이 저장되어 지는것을 볼 수 있다. (local변수의 위치가 왜 [ebp-4]에 있는지는 아직 설명한 적이 없다. 이에 대해선 다음에 설명 하겠다.) 하지만, 전역변수나 초기화 되지 않은  notdeclare 변수는 값이 저장되는 명령어를 찾아 볼 수가 없다. 즉 global변수와 초기화 되지 않은 변수는 특별히 코드를 통해 초기화 되는게 아니라, 이미지(윈도우 에선 exe)가 메모리로 로드되는 순간 이미 data영역과 bss영역에 값이 초기화 되어져 있다는 것, 지역변수의 경우 특정 명령어를 통하여 stack에 로드 되는 것을 뜻한다.

 

4. Heap영역

이 영역은 malloc이나 new등과 같이 프로그래머가 프로그래밍 과정에서 동적으로 메모리를 할당하는 영역이다. 

 

5. Heap영역과, stack 영역

이 두 영역을 제외한 나머지 영역을은 프로그램이 실행되기 전에 이미 결정되어 메모리에 데이터가 고정되어져 있다. 하지만 Heap영역과 stack 영역은 프로그램이 실행됨에 따라 동적으로 바뀌는 영역이기에 메모리상에 어떻게 위치되어져야 하는것이 하나의 이슈가 된다. 두 개의 영역을 어떻게 위치시켜야 메모리를 효율적으로 사용할 수 있을까? 답은 두 개의 영역을 떨어뜨려서 서로 반대 방향으로 메모리를 할당하면 된다. 무슨말인지 그림을 통해 설명 하겠다. 

 

 

위의 그림에서 보듯이 데이터가 메모리에서 동적으로 할당 될때, 서로 겹치지 않게 하기 위해 메모리상에서 위치가 서로 떨어져 있고, 데이터가 할당 될 때도 서로 반대 방향으로(stack은 높은 주소-> 낮은 주소, heap은 낮은 주소->높은 주소) 주소값이 할당 된다. 

 

6. 공유 라이브리 영역

 

공유 라이브러리는 stack영역의 중간 쯤에 위치 하는데 이는 다음 그림을 통해 확인 할 수 있다.

 

 

ldd는 공유라이브러리 의존성 등을 확인할때 쓰는 툴이다. 이 툴을 이용해 아까 작성했던 예제를 살펴보면, libc.so.6이나 /lib/ld-linux.so.2 등의 라이브러리가 스택 영역에 위치해 있는 것을 확인 할 수 있다.

 

그림은 [원본유지로 설정]

 

 

참고 URL 및 도서

그림 참조: http://www.hackerschool.org/Sub_Html/HS_University/BOF/essential/PDF_Files/13.pdf


- OOO 도서

 

신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
메모리 구조  (0) 2014.05.04
1.OS의 시작  (0) 2014.05.04
Posted by flack3r

 

  1. 1. 개요

지금부터 전반적인 OS커널에 대한 이야기를 할 것이다. 이론중심이 될 것이고 관련 소스나 실습을 원하시는 분들은 따로 자료를 참조하시기 바란다. MBR부터 시작하자.

 

  1. 2. MBR이란?

 

MBR이란 무엇일까? 컴퓨터가 처음에 부팅을 시작하면 각종 하드웨어들에 대한 체크들을 한다. 잘 작동하는지부터 시작해 마더보드 상태 체크, 각 장치가 잘 연결되어 있는지 등 이것저것 확인한다. 제일 마지막으로 사용자가 부팅영역으로 사용할 영역이라 정해놓은 디스크의 512바이트의 프로그램을 램으로 읽어 들여 실행하게 된다.

 

뭔가 이상하지 않은가? 겨우 512바이트의 프로그램만 로딩해선 OS라 부를만한 기능(멀티 테스킹, 파일 시스템관리, 네트워크 등)을 수행할 수 없을 것 같다. 해법은 초기 512바이트의 프로그램에서 OS커널 프로그램을 로드시키는 방법이다. 그래서, MBR영역은 초기 첫 매듭을 매는 역할을 한다. 따라서 이를 부트스트랩이라 부르기도 한다. 왜 부트스트랩인가? 부츠를 신을 때 밑에서 쭉 지퍼를 올리는 것을 연상하기 바란다… 마음에 안드는가? 필자도 부트스트랩이란 용어가 직관적이지 않아 마음에 들지는 않지만 별수 없다. ㅠㅠ

 

지금까지의 내용을 정리 하자면, MBR영역이 OS가 메모리에 로드되는 첫 단추이다. 이 MBR영역의 511바이트와 512바이트엔 0x55 0xaa 라는 값이 입력되어야 한다. 왜냐하면 BIOS가 마지막 512바이트를 로드 할 때 이 부분을 보고 이 프로그램이 MBR인지 아닌지를 판단하기 때문이다. 이상의 과정을 그림으로 확인하겠다. 1번 과정은 디스크의 MBR영역으로, BIOS가 프로그램을 읽어 들인다. 그 다음 2번에서 MBR에서 읽은 영역을 실행시켜 다음 프로그램을 3, 4번에서 램으로 가져오는 과정이다.


신고

'컴퓨터구조&OS > OS' 카테고리의 다른 글

5. 보호  (0) 2014.05.05
4. Task switching  (0) 2014.05.05
3. 인터럽트 처리  (0) 2014.05.05
2. Protected 모드로의 전환  (0) 2014.05.05
메모리 구조  (0) 2014.05.04
1.OS의 시작  (0) 2014.05.04
Posted by flack3r