시스템/Windows 구조와 원리

I. 컴퓨터의 구조와 역사

s3ich4n 2018. 1. 30. 02:32

01. 시스템 프로그래밍과 운영체제



시스템 프로그램: 시스템 전체의 운영, 관리, 개발에 반드시 필요한 부분을 관리하는 프로그램.

운영체제: 하드웨어에게 컴퓨터의 각종 리소스들을 관리하게 지시하고, 일반 사용자들이 이를 편하게 사용할 수 있도록 해주는 프로그램.


운영체제는 크게 커널(Kernel)과 GUI(Graphic User Interface)의 두가지 관점에서 볼 수 있다.


커널 (Kernel): 컴퓨터 시스템 내의 물리적 장치와 논리적 자원들이 효율적으로 고유의 기능을 수행하도록 관리하고 제어하는 부분을 의미.


GUI(Graphic User Interface): 컴퓨터와 사용자 사이의 중재자 역할을 해주는 프로그램.




02. 컴퓨터의 구조와 역사



컴퓨터는 마이크로프로세서라는 CPU에 의해 움직인다. CPU의 계산, 값비교, 데이터 전달 등의 일은 폰 노이만이 고안한 프로그램 내장 방식(stored-program concept)이라는 개념을 통해 정립되었고, 이는 현재의 마이크로프로세서도 그러한 특징을 여전히 가지고있다.


프로그램 내장방식의 주요컨셉: 

1) 프로그램과 자료는 쓰이기전에 메모리에 저장함.

2) 프로그램이 실행될 때는 프로그램의 명령어와 데이터들을 메모리로부터 읽어들임

3) 프로그램에 대한 저장과 변경은 기억장치의 프로그램을 변경함.


다시말해, 컴퓨터구조와 같은 수업시간에 들을 수 있는 Fetch -> Decode -> Execute -> Backup의 과정이 이때 정의되었다고 볼 수 있다.


이러한 구조를 통해 만들어진 최초의 컴퓨터는 ISA(Instruction Set Architecture) 이다. 눈여겨볼 점은 명령처리부분, 메인메모리부분, I/O 부분, 산술연산 부분 모두가 구현되어있다는 점이다.


2-1. 8086 마이크로프로세서: 16비트 마이크로프로세서의 대두


16비트의 데이터 버스: 데이터 전송을 위해 16개의 핀을 사용함을 의미.

20비트의 어드레스 버스: 보다 많은 메모리를 액세스 하기 위함.


16비트의 값을 가지고 어떻게 20비트의 메모리를 가리킬 수 있는가?

그것은 바로 세그먼트를 사용하는 것이다. 세그먼트는 다음 사진을 보면 이해가 빠를 것이다.



(출처: https://rikardit.wordpress.com/)


그림을 보자면, 세그먼트 값에는 4비트를 SHL하고, 오프셋값을 더하여 주소를 표기하는 방식을 가진다. 이처럼 세그먼트를 사용하여 '세그먼트:오프셋' 으로 주소를 표현한다.

e.g. 0xB1234라는 주소는 세그먼트 B123과 오프셋 0004로 표현할 수 있는 방식이다.


B     1230     +

0004   = 

----------

B     1234


혹은 세그먼트 B1000과 오프셋 0234로도 표기할 수 있을 것이다.


B     1000    +

0234    = 

----------

B     1234


아니면 AF00과 오프셋 2234도 같은 주소를 표기할 수 있을 것이다.


A     F000   +

2234    = 

----------

B     1234



2-2 8086의 레지스터

8086 마이크로프로세서에는 데이터 임시저장, 연산처리, 번지지정 등을 쉽게 수행하기 위해 레지스터의 개념을 도입하였다. 레지스터는 다음과 같다.


(출처: https://compsecurityconcepts.wordpress.com/tag/8086-microprocessor/)


레지스터는 여러가지 종류로 나뉜다. 아래에서 각각 설명하도록 한다.



 범용 레지스터(General Register)

 주로 연산결과나 값 임시저장에 쓰인다. 범용 레지스터의 값은 8비트씩 나누어 사용이 가능하다.

 e.g. AX는 AH/AL로 사용가능하다.

 AX

 accumulator로 쓰인다. 산술, 논리연산의 중심이다. I/O포트의 입출력 명령에도 쓰인다.

 BX

 주로 번지 레지스터로 쓰인다. 

 CX

 주로 반복횟수 카운터로 쓰인다.

 DX

 주로 간접 번지 지정에 쓰인다. 곱셈, 나눗셈의 보조 accumulator로 쓰인다. 


 포인터 레지스터

 SP

 (Stack Pointer)

 현재까지 쓰인 스택의 위치를 저장하기 위해 쓰인다. 세그먼트 레지스터인 SS와 함께 쓰인다. 

 BP

 (Buffer Pointer)

 스택의 데이터에 액세스하기 위해 쓰인다. 

 인덱스 레지스터

 SI, DI

 Source Index/Destination Index이다. 연산과 간접 번지 지정에 쓰인다. 문자열의 전송이나 비교 등에 쓰일 때는 SI: source가 되는 문자열, DI: destination이 되는 문자열의 주소를 나타낼 때 쓰인다. 

 IP (명령 포인터: Instruction Pointer)

 이 포인터는 다음에 실행할 명령이 들어있는 메모리의 주소를 저장한다. CS 세그먼트 레지스터와 함께 쓰인다.


 플래그 레지스터(Flag Register)

 8086에는 16비트로 된 플래그 레지스터가 있다. 이는 각각 연산의 결과, 시스템 제어 결과값이 들어있다.

 셋은 1을, 리셋은 0을 의미한다.


 그 

 CF

 연산 후 최상위 비트에 올림, 빌림이 생기면 셋, 아니면 리셋. 

 PF

 연산 결과, 하위 8비트 중 1로된 비트의 갯수가 짝수이면 셋, 홀수개이면 리셋.

 AF

 연산의 결과, 하위 4비트에 자리올림, 빌림이 생기면 셋. 10진연산 처리시 이용됨.

 ZF

 연산 결과가 0이 될 때 세트됨. 비교 명령시에도 결과에 따라 셋될 수 있음.

 SF

 최상위비트가 1일 때 셋, 0일 때 리셋. 부호가 있는 수치의 경우에는 MSB가 1이면 음수를 표시함.

 OF

 부호 연산 처리의 결과, 오버플로우가 발생했다면 셋

컨트롤

플래그

 DF

 

 IF

 하드웨어 인터럽트 제어 플래그. 셋되었다면 인터럽트를 받아들임. 리셋일땐 인터럽트를 받아들이지 않음. 

 TF

 단일 스텝 인터럽트 플래그. 이 기능을 사용하면 한 명령씩 실행시켜 동작확인 가능.



앞서 말한 컴퓨터구조로부터 이어지는 프로그램의 수행과정을 살펴보자면 메모리 주소는 여러부분으로 나뉘어서 쓰인다. 이는 각각 수행중인 명령어의 위치를 나타내는 메모리값, 프로그램이 사용하는 데이터가 있는 메모리값, 함수 호출등을 위한 스택위치를 저장하는 메모리값 등이 있다. 이러한 값 또한 세그먼트 레지스터가 개입되어 메모리 참조를 돕게된다.


 세그먼트

 오프셋 

 목적

 코드 세그먼트(CS) 

 IP

 다음에 수행될 명령어의 위치 지시

 스택 세그먼트(SS)

 SP, BP 

 스택의 주소를 참조 

 데이터 세그먼트(DS)

 AX, BX, CX, DX 등의 범용 레지스터와

 DI, SI

 데이터 주소 참조

 보조 세그먼트(ES)

 string 명령어를 위한 DI 

 string의 목적지 주소 


이러한 세그먼트들은 다음과 같이 쓰인다. 각종 레지스터들은 오프셋 값으로 사용할 때 암시적으로 세그먼트 레지스터들과 연결되는 것을 참고하길 바란다.


e.g.


mov ax, word ptr 1032h (현재 데이터 세그먼트의 오프셋 1034h 번지의 값, 다시말해 DS:1034 번지의 값을 AX 레지스터에 mov하라는 뜻이다)


다른 세그먼트에 명시적으로 접근또한 가능하다.

e.g.


mov ax, word ptr es:1032h (현재 보조 세그먼트의 오프셋 1034h 번지의 값, 다시말해 ES:1034 번지의 값을 AX 레지스터에 mov하라는 뜻이다)



cf) 명령어를 미리 fetch하는 개념은 8086에서부터 등장했다. 자세한 내용은 책을 참고하시길 바란다.


2-3 80286, 80386의 등장.


80386부터 어드레스 버스, 데이터 버스, 레지스터 등 모든 데이터 접근이 32비트로 이루어졌다. 이때부터 정수의 표현범위도 크게 증가하였으며 실수연산 또한 효율이 크게 증가되었다.


32비트에서는 또한 4GB의 물리메모리에 대한 엑세스가 가능해졌으며 OS가 메모리 자원을 할당하고 관리하도록 하는 메모리 관리 장치가 추가되었다. 이를 통해 메모리 관리 및 할당은 하드웨어 단에서 어느정도 수행하게 되었다.


80386부터 레지스터는 다음과 같이 확장되었다.


(출처: https://pdos.csail.mit.edu/6.828/2004/readings/i386/fig2-5.gif)


플래그 레지스터는 확장되며 아래에 해당하는 새로운 플래그가 추가되었다.


(출처: https://pdos.csail.mit.edu/6.828/2004/readings/i386/fig2-8.gif)

 IOPL(I/O 특권수준)

  I/O 특권수준을 나타내는 2비트 플래그이다.

 NT(내포 태스크 플래그)

 보호모드에서 현재 태스크가 다른 태스크에 의해 호출되었음을 나타낼때 쓰는

 플래그이다.

 RF(재시작 플래그)

 디버그 레지스터와 함께 쓰인다. 해당 플래그가 셋되면 디버그 falut를 무시하고

 다음 명령어를 계속 실행한다. 

 VM(가상모드)

 가상 8086 모드로 전환시킬 때 쓰는 보호모드 제어 플래그이다. 


또한 시스템 레지스터라는 새로운 그룹의 레지스터가 나타나게 되었다. 이는 보호모드에서 프로세서 제어와 검사를 위한 목적으로 만들어졌다. 오직 운영체제에서만 시스템의 작업을 위해 쓸 수 있도록 되어있다. 아래 사진은 시스템 레지스터 중 제어 레지스터를 나타낸다. 80386에서 CR1은 예약된(reserved) 영역이다.


(출처: http://ece-research.unm.edu/jimp/310/slides/micro_arch3.html)



  CR0 레지스터의 필드

 PE

 EFLAGS의 VM비트와 유사. 보호비트로 동작하려면 셋, 실제모드로 동작할땐 리셋.

 MP

 산술 보조 프로세서의 존재유무를 셋/리셋으로 표시.

 EM 

 프로세서가 부동 소수점 유닛이 없다면 셋됨. 해당 비트가 셋된 상태에서 부동 소수점 연산을

 수행하면 SW적으로 부동 소수점 연산 수행. 

 TS 

 태스크 스위칭 이일어날 때마다 셋됨. CLTS 명령으로 비트 클리어 수행. 

 ET 

 산술 보조 프로세서가 80387인지 아닌지 나타내어줌 

 PG

 프로세서의 페이징 MMU를 활성화할 것인지 나타냄. 셋되면 페이징 시스템이 동작함. 

 CR2 레지스터

  페이징시, 페이지 폴트가 발생하여 인터럽트 14번이 발생했을 때 페이지 부재가 일어난 주소를 저장하는 레지스터.

 CR3 레지스터

 페이지 디렉토리의 베이스 주소를 저장하는 레지스터.


또한 아래의 사진은 디버그 레지스터들을 보여준다. 이 레지스터 그룹은 하드웨어 브레이크 포인터를 가능하게 한다. 프로그램의 특정 메모리 주소가 액세스 되었을 시 프로그램이 멈추고 디버깅 루틴으로 제어를 넘긴다.


(출처: https://pdos.csail.mit.edu/6.828/2004/readings/i386/s12_02.htm)


DR0부터 DR3

 각 4가지 레지스터는 하드웨어 브레이크 포인트의 주소를 의미한다. DR7 레지스터와 함께 쓰여 하드웨어 브레이크 포인터를 사용할 수 있게 한다. 이 레지스터에 의하여 브레이크 포인트가 활성화 되어있을 때 프로세서가 해당 주소를 액세스한다면 인터럽트 1이 발생한다.

 DR6(Debug Status Register)

 해당 레지스터는 인터럽트 1이 발생한 이유를 알려주는 레지스터이다. 해당 레지스터의 클리어는 사용자가 직접 해주어야 한다.

 B0~B3

 어느 레지스터의 주소값에 의해 하드웨어 브레이크 포인터가 작동했는지 알려준다. 

 BD

 DR7의 GD비트에 의해 디버그 레지스터가 잠겨있을 때 디버그 레지스터를 액세스하면 인터럽트 1이 발생하고 해당 비트가 셋된다. 

 BS 

 EFLAGS의 TF비트가 셋되어 인터럽트 1이 발생했을 때 셋된다. 

 BT 

 태스크 변환시 TSS의 T-bit가 셋되어 인터럽트 1이 발생하였음을 나타낸다.

 (참고: https://pdos.csail.mit.edu/6.828/2010/readings/i386/s07_01.htm

 DR7(Debug Control Register)

 하드웨어 브레이크 포인터에 대해 조건을 지정해주는 레지스터이다.

 L0~L3

 DR0~DR3에 저장된 주소에 대해, 현재의 태스크 기간동안만 하드웨어 브레이크 포인터가 작동되게 한다. 태스크 변환이 일어나면 해당 비트는 클리어된다. 

 G0~G3

 DR0~DR3에 저장된 주소에 대해, 태스크 변환에 상관없이 모든 시간동안 하드웨어 브레이크 포인터가 작동되게 한다. 

 LE, GE 

 데이터 액세스 브레이크 포인트를 지정할 때 반드시 셋해주어야 한다. 만일 해당 비트가 셋되지 않았다면 인터럽트가 즉시 발생하지 않고 몇개의 명령어 실행 후에 인터럽트가 발생한다. LE는 하나의 태스크 기간동안, GE는 모든 태스크 기간동안 유효하게 해준다. 

 GD

 해당 비트가 셋된채로 디버그 레지스터(DR0~DR3)에 대한 액세스가 이루어지면 인터럽트 1이 발생되고 리셋된다. 


 RW0~RW3(2bytes)

 DR0~DR3에 저장된 주소에 대해 어떠한 액세스가 발생하였을 시 하드웨어 브레이크 포인트가 작동할지 지시한다.

 RW bit set

 내용

 00 

 명령어 수행 시에만 브레이크 포인트 작동

01

 쓰기 명령이 있을 때만 브레이크 포인트 작동 

10

 Pentium 이전 프로세서에선 reserved
 Pentium 이후부턴 CR4 레지스터의 DE플래그가 셋되어있을 경우, I/O 포트에 대한 읽기/쓰기 작업시 브레이크 포인트 작동 

11

 데이터에 대한 모든 액세스 시 브레이크 포인트 작동 


 LEN0~LEN3(2bytes)

 DR0~DR3에 저장된 주소의 유효범위를 알려준다. 이때 명령실행에 대한 브레이크 포인트 지정시 LEN필드는 항상 00을 지정해야하며, 데이터 액세스 브레이크 포인트 지정시에는 그 브레이크 포인트의 시작번지가 아래 표와 같은 주소 위치여야 한다.

LEN bit set

브레이크 포인트의 유효 범위 길이 

브레이크 포인트의 시작 번지 

 00

 1바이트

임의의 번지 

01

2바이트 

짝수 번지 

10

미사용 

11

4바이트 

4의 정수배 


그 외에는 TR6, TR7가 있는데 이는 TLB(Translation Lookaside Buffer)의 내용을 RAM으로부터 검사하는데 쓰인다.

IDTR, GDTR, LDTR은 추후 기술할 것이다.


그 외에 80486, 80586으로 들어서며 기손 프로세서와 호환성을 유지하거나, RISC의 개념을 추가하여 재설계하고, 내부캐시를 추가하여 작동의 원활한 수행을 꾀하였으며 이때부터 파이프라인의 개념이 처음 도입되었다. 펜티엄 프로세서의 등장으로 두개의 파이프라인을 동시에 수행하는 슈퍼 스칼라의 대두로 훨씬더 복잡한 작동원리가 추가되었다. 펜티엄 프로세서부터 CR4 레지스터의 일부를 사용하게 되었다.