초기의 컴퓨터는 한 사람이 컴퓨터를 조작하고 모든 자원을 썼지만, 시간이 흐르면서 시스템을 여러명이 나누어 쓰는 편이 꽤 효율적이라는 사실을 발견하게 되었다. 시스템을 공유한다는 사실은 효율성을 높여준것이지만 그에 따라 여러가지 문제가 발생하게 되었다. 

따라서 오에스는 시스템을 공유하는 환경에 대해 자기자신을 보호하면서 각자의 환경을 보장해주어야만 하는 임무를 띄게 되었다. 
크게  시스템을 '보호' 하는 방법으로 4가지를 들어 볼 수 있는데, 오에스의 표준이라고 하는 유닉스를 예를 들어 설명해 보겠다. 

첫번째 방법으로 'OS 프로텍션' 이다. 유닉스는 듀얼모드로 동작한다. 이 말은 곧, 유저모드와 시스템모드를 의미하게 되는데 하드웨어 차원에서 본다면 모드비트(mode bit)라는 것이 있어서 현재의 모드를 나타내주는 방법으로 구분 되어진다.  처음 시스템이 부팅될때에 하드웨어가 시스템 모드로 부팅하게 된다. 그리고 운영체제가 띄워지면서 이제사 유저모드로 유저 프로세스를 처리해 주게 되는 것이다. 트랩(trap: 소프트웨어적인 인터럽트) 이나 인터럽트가 발생하면 하드웨어는 즉시 유저모드에서 시스템 모드로 변신을 한뒤 오에스가 처리를 하고 다시 유저 모드로 모드 비트를 셋팅한다음에야 유저에게 프로세스 권한을 넘겨주게 된다. 
이러한 듀얼모드의 필요성을 묻는이가 있는가? 바로 임의의 유저로 부터 시스템을 보호하기 위한 일종의 면역 장치이기 때문이다. 이것이 바로 OS Protection 이다.  일부 극단적인 명령어 셋( instruction set) 들은 시스템 모드에서만 실행이 가능하며, 일반 유저들이 그러한 명령어를 부가하게 되면 시스템이 알아서 불법으로 규정하고 오에스로 하여금 트랩을 발생하도록 하는 것이다. 참고로 수퍼유저, 관리자유저는 시스템 모드에서 놀수 있는 특수한 권한이 부여된다. 

두번째로 I/O 프로텍션을 들 수 있다. 간단하게 얘기해서 오에스를 거치지 않은 입출력을 발생하게 하지 못하게 하는 것이다. 즉, 모든 I/O는 오에스를 통해서- 합법적인 절차를 거쳐서- 발생하게 된다. 

세번째로 씨피유 프로텍션을 들 수 있다. 이것은 유저 프로그램이 프로세스권한을 잡은 채로 무한루프에 빠졌을 상태!(오에스로 컨트롤을 돌려주어야 되는데 그러지 못할때) 를 방지하는 것이다. 어떻게? /.. 바로 간단한 타이머의 도입으로 가능하게 된다.  카운터는 일정시간마다 양수에서 0으로 점차 줄어들게되고 0이되면 인터럽트를 발생시켜 컨트롤을 유저프로그램에게서 빼앗고 프로그램을 강제종료시켜버리는 아주 냉혹한 방법입니다.

마지막으로 메모리 프로텍션을 들 수 있다.  메모리 프로텍션은 왜 필요하냐? 보호되지 않은 메모리 영역에 오에스의 슈퍼유저 공간이 있다고 생각해보자! 일반유저가 인터럽트를 발생시키거나 일반 프로그램이 특정 메모리를 접근하려고 하면 어떻게 되겠는가? 말하지 않아도 알 수 있을 것이다.  일반유저가 수퍼유저가 되거나?... 스플이나 버퍼 영역이 덮여서 망가지거나 엉뚱한 인터럽트 처리가 되거나?... 결과는 참담하다.  그래서 메모리 영역에 대한 보호가 필요한 것이다. 이러한 보호는 오에스에 대해서 뿐만아니라 각 유저 프로그램, 유저 사이에서도 이루어 져야할 사항인것이다. 따라서 메모리 프로텍션은 강력하게 하드웨어 적으로 지원이 되어야 하는데 이는 나중에 페이징, 세그멘터에션, 가상메모리등 다룰때 다시한번 살펴보기로하고 지금은 여러기법 중에 한가지를 소개한다. 

이 방법은 베이스(base) 와 리미트(limit) 레지스터를 지정하는 것이다. 이들은 각각 메모리 덩어리가 들어있는(한개의 어플일 수도 있고, 데이터 일 수도 있고,...) 물리적인 메모리의 시작 주소와 전체의 크기를 담아 줌으로써 절대로 그 이상또는 이 하의 주소를 탐내지 못하게 제한하는 기법이다. 이러한 프로텍션은 씨피유가 하드웨어적으로 모든! 유저보드에서 발생하는 어드레스를 이 두 레지스터쌍들과 비교를 함으로써 그 적법함을 판단하는 방식으로 이루어 지며, 두 레지스터쌍들은 반드시 시스템 모드에서만 접근이 가능하기 때문에 함부로 고칠 수 없다. 

이상으로 프로텍션에 대해 간단히 살펴보았다. 윈도우에 익숙해진 관리자 모드 때문인지  우분투 환경에서의 암호입력요구는 때론 번거로울때가 있다. 어느 것이 좋은지는 피부에 와 닿을정도로 느껴지진 않지만 운영체제를 공부하고 있는 나로써는 좀 더 공학적인 마인드로 운영체제를 이해할 필요가 있는 듯하다. 

다음장에서는 프로세스(process)! 란 도대체 무엇인가를 살펴보도록 하자

'OS > OS 파헤치기!' 카테고리의 다른 글

5. 프로세스의 생성 사용 및 소멸  (0) 2010.09.22
4. 프로세스(process)?  (0) 2010.08.25
2장 컴퓨터 구조  (0) 2010.08.16
1장. OS란?  (0) 2010.08.12
[공지]시작하며...꼭 읽어주시길.  (0) 2010.08.11
AND

OS를 구체적으로 논하기에 앞서서 먼저 OS가 담겨질 컴퓨터 구조에 대한 개괄적인 이해를 하는 시간을 갖도록 하자

지금부터 그림을 그리도록하겠다. 초록 들판위, 한가운데 씨피유가 버티고 있고 그 주변에는 디바이스(주변기기)들이 널부러져 있다. 그 사이에는 컨트롤러 라고 하는 톨게이트 같이 생긴것이 떡하니 버티고 서있고 톨게이트를 지나 씨피유와 디바이스를 연결해주는 길이있는데 이는 버스(BUS)라고 불리운다.  어떻게 한폭의 그림이 그려졌는가? 

대충 내부구조가 머리속에 그려졌다면 잠시 컴퓨터 OS의 동작 흐름을 잠시 살펴보도록 하자. 
먼저 컴퓨터의 전원이 들어오는 순간, 제일먼저 Bootstrap 프로그램이라는 것이 실행이 된다. 본 프로그램은 초기화(씨피유내부의 빠르지만 작은 용량의 레지스터라 불리우는 기억소자의 초기화, 디바이스 컨트롤러의 초기화, 메모리의 초기화 등등)를 모조리 시켜버린다.
쉽게 생각해서 컴퓨터 처음켜서 로고나오고 다음화면으로 넘어가기까지!!! 보통... 이 5초도 안걸리는 시간안에 슈루룩~~ 다 해버리고 OS의 커널 영역으로 진입하게 된다. 이후!! 하염없이 기다린다.......................................... 언제까지?  누구를?   .... 정답은 이벤트!
좀더 정확하게 말하자면 인터럽트를 기다린다고 할 수 있다.

인터럽트는 매우 중요한 의미를 가지고 있는 사건이다. 주로 씨피유가 뭔가에 열중하고 있을 때(놀고있는 것도 열중에 포함됨) 인터럽터를 걸어 줌으로 써 씨피유가 인터럽트를 걸은 녀석이 요구하는 일을 수행하게 만드는 것이다. 
그러면 엄청나게 다양한 인터럽트의 경우를 OS는 어떻게 다 알아차려서 정확하게 거기에 맞는 응답을 ,처리를 해줄수 있을까?  ... 그렇다 . 컴퓨터는 모든종료의 인터럽트에 대한 모든 해결법을 이미 준비해 놓은 것이다. 각 인터럽트는 각 서비스 루틴과 일종의 함수관계를 가지고 있고, 씨피유는 단지 중간에서 짝맞추기 게임을 하고 있는 것이다.  어때 이해가 쉽게 가는가?

인터럽트는 또한 하드웨어적인 컨트롤러 뿐만 아니라 소프트웨어가 발생시키기도 한다. 이를 트랩(Trap) 이라고 불리우기도 한다. 이는 '시스템콜' 이라는 형태로 씨피유에 도달하게 된다. 자기만의 OS를 만드는 방법중에 하나가 이렇게 자기만의 시스템콜을 만들어 OS 에 추가시켜 특정한 목적의 OS 를 제작할 수 도 있다. 

이러한 인터럽트의 발생을 씨피유는 어떻게 알아차릴까? 바로 특정한 패턴! 의 전기 신호가 시스템 버스를 따라서 씨피유에게 전달됨으로 씨피유는 인터럽트의 발생을 알아차리게 된다. 하드웨어에서 발생하건 소프트웨어에서 발생하건 인터럽트가 발생하게 되면 씨피유는 그 즉히 하던일을 중단해 버리게 된다. 그리고 실행권한을 어떤 '메모리의 고정된 위치'로 던저 주게 된다. 그 위치는 인터럽트 서비스 루틴이 시작되는 지점이며 루틴이 완료된 다음에야 씨피유는 하던일을 계속하게 된다. 

자 여기서 궁금한점이 있지않은가?  바로 위에 문단에 마지막 문장 '루틴이 완료된다음에야 씨피유는 하던일을 계속하게 된다.'
어떻게? 현재 1부터 100까지 세어가는 중 15에서 인터럽트를 만나서 잠깐 일을 처리하고 돌아와 16부터 다시 셈을 해 나가야되는데 15까지 셈을 한것을 어디에 저장하지?  . 컴퓨터에는 내부적으로 현재 실행주소가 항상 저장이 되는 레지스터가 존재한다. 이곳의 내용을 잠시 특정한 메모리 공간에 저장해 놓았다가, 인터럽트 처리후 다시 불러오면 되겠네? .. 정답!   하나하나 과정을 말하면 복잡하니 개념을 이렇게 잡아두자. 인터럽트 발생시 현재의 내용을 특정메모리 영역에 고스란히 저장해 놓았다가 인터럽트 처리가 끝나면 다시 불러온다.  따라서 하나의 인터럽트 처리시 다른 인터럽트가 들어와 특정메모리 영역을 덮어 버리면 어떻게 되는것인가? 그렇게 이전에 내용은 지워저 버려서 감당할 수 없는 결과가 나오게 된다. 여기에 대한 해결방법 한번쯤 생각해보도록...  

위의 설명이 길고 장황하지 않은가?  그만큼 중요하기 때문이다. 이러한 인터럽트를 처리하는 구체적인 방법들이 나름대로 존재하는데 , 직관적이며 대표적인 방법이 '인터럽트 벡터'를 이용하는 것이다.  '인터럽트 벡터' 의 개념은 아무리 인터럽트가 많아도 유한개의 인터럽트 집합이 존재한다는 전제에서 각 인터럽트 핸들링 서비스 루틴이 들어있는 주소를 가르키는 포인터를 테이블 화 한것이 바로 인터럽트 벡터이다. 즉, 인터럽트와 그 인터럽트에 해당되는 서비스루틴의 주소를 매치 시켜놓은 테이블! 이 바로 인터럽트 벡터이다. 
이러한 개념은 여러분들이 잘 아는 MS-DOS 와 UNIX ,LINUX 에 적용되어 있다.   인터럽트가 발생하면 테이블 한번 쭉 훑어 본뒤에 대응되는 서비스 루틴의 시작주소를 한방에 콜! 하는 방식이다. 

뭐 여러가지 다른 인터럽트 처리 방법들이 있지만 궁금한사람은 책을 찾아 보도록....

그럼 인터럽트라고 다 같은 인터럽트냐? 아니다. 인터럽트도 나름대로 계보가 존재하기에 우선순위가 주어지게 된다. 인터럽트가 한꺼번에 여러개가 발생하게 되는 경우 일종의 큐(먼저들어오는 녀석이 먼저 실행되는 구조의 저장공간)에 담아서 보관하게 되는데, 우선순위가 높은 인터럽트는 낮은 인터럽트를 그냥 무시하게 된다. 심지어는 실행되고 있는 낮은 우선순위의 인터럽트를 밀어내기도 한다. 

인터럽트가 발생하였을 때 씨피유가 모든 I/O에게 인터럽트 발생한게 너냐? 라고  물어서 알아내는 방법을 폴링 이라고 한다. 또한 인터럽트를 발생한 디바이스 자체가 자진해서 씨피유에게 알려오는 방법을 인터러브 드리븐 방식이라고 한다. 현대의 OS는 인터럽트 드리븐 방식이다. 

I/O 이야기가 나온김에 잠시 언급하고 넘어가자면 먼저 컨트롤러에 대해 생각해 봐야한다. 초반에 그려두었던 그림이 생각가는가? 거기에서 컨트롤러를 떠 올려보자 . 기본적으로 하나의 주변기기에 하나의 컨트롤러가 달려있지만, 하나 이상의 주변기기를 달아줄 수도 있다. 그 대표적인 예가 바로 스커지(SCSI: Small Computer System Interface) 이다. 이 방식에서 최대 7개 이상의 디바이스들을 데이지 체인 방식으로(서로 꼬리에 꼬리를 물어 연결이 되어있는) 연결이 가능하였다. 이 스커지의 최대 특징은 바로 독립성에 있는 듯한데, 스커지 어뎁터에는 이미 또 한개의 입출력만을 전담하는 독립된 씨피유를 가지고 있기에 그만큼  씨피유에 부과될 인터럽트를 '내선에서~' 처리 가능하게 해주는 믿음직한 장치이다. 하지만 요즘은 씨피유의 능력이 워낙 뛰어나게 발전하여 입출력으로 인한 인터럽트는 껌으로 여긴다. 
이러한 디바이스 컨트롤러는 결국 데이터를 주변 디바이스들간에 옮기는 책임을 전담하고 있는 장치이며, 버퍼를 가지고 있다. 입출력을 시작하기 위하여 일단 씨피유가 디바이스 컨트롤러 내부에 존재하는 레지스터안에 적당한 명령어와 데이터를 셋팅하게 된다. 그럼 디바이스 컨트롤러는 차례로 그 명령어들을 하나씩 읽어봄으로써 어떠한 조치를 취해야 하는지 판단하게 된다. 

자, 여기서 잠깐 알아두고 넘어갈 포인트 ! 사용자에 의해 데이터 입출력이 시작되었을 때 사용권한에 대한 두 가지 경우가 발생하게 된다. 첫번째는 입출력의 과정이 모두 끝날때 까지 기다렸다가 씨피유의 사용권한이 유저에게 넘어가는 경우(이것을 동기적 I/O) 와 I/O가 시작된 것만 확인하고 바로 유저에게 사용권이 넘어가는 경우(비동기적I/O) 가 있다. 어떤경우와에 사용되는지 구현원리를 알고싶은 사람은 책을 찾아보도록...

I/O 라고 해서 다 똑같이 취급해서는 안되는 경우가 있다. 이러한 경우는 특수한 경우의 I/O 인데 대표적으로 DMA 가 바로 이 경우에 해당된다. 보통의 경우  씨피유가 중간에서 중재자 역할을 하게 되는데 이러한 중재자 역할이 초고속 디바이스인 메모리와의 데이터 교환에 있어서는 오히려 번거로운 존재가 되어 버린다. 따라서 일부 디바이스 드라이버는 DMA 컨트롤러의 레지스터에 소스 주소및 데스티네이션 주소, 그리고 단위전송 크기를 셋팅한 뒤 씨피유의 클럭을 찔끔찔끔 훔쳐내면서 원하는 디바이스와 메모리와의 데이터 교환을 직접 하도록 유도해 준다. 
이러한 특수한 형태의 I/O의 예로 memory-mapped I/O 가 있다. 이는 램의 특정 영역이 디바이스 컨트롤러의 레지스터 들과 1:1 대응관계를 갖도록 먼저 약속을 하여 램에 전송할 데이터를 쇽쇽 넣어주게 되는 것이다. 램은 빠르니까... 

오늘은 이만....대충 어렵지 않으리라 생각된다. 나도 정리를 하면서 세삼 다시 알아가는 것 같아 기분이 좋다 ㅎㅎ 

'OS > OS 파헤치기!' 카테고리의 다른 글

5. 프로세스의 생성 사용 및 소멸  (0) 2010.09.22
4. 프로세스(process)?  (0) 2010.08.25
3. 하드웨어 보호(Hardware Protection)  (0) 2010.08.17
1장. OS란?  (0) 2010.08.12
[공지]시작하며...꼭 읽어주시길.  (0) 2010.08.11
AND

NASM, MASM 차이

asm 2010. 8. 13. 00:48

MASM은 MS사에서 만든 어셈블러입니다.


NASM은 오픈소스로 만들어진 어셈블러입니다.

 

MASM와 NASM은 Intel 문법을 따르지만, directive에 있어서는 조금 차이가 납니다.

 

MASM은 윈도우 환경에서만 사용될 수 있으나, NASM은 다양한 환경에서 사용될 수 있습니다.

 

또한, 주소 지정 방식에서도 조금 차이가 납니다.

 

뭘 공부해야 하느냐는 목적에 따라 사용 하면 됩니다.

 

1. 윈도우, 리눅스 환경 및 독자 OS 개발에 사용하고 싶다면 NASM을 추천합니다.

 

참고로, Visual Studio에서 NASM 문법을 사용해서 C언어와 함께 개발하려면 독립적인 OBJECT 파일로

 

만들어서 링크해야 합니다. 즉, Visual Studio에서 인라인 어셈블은 안됩니다.

 

2. WinDebug 등의 디버거를 이용해서 윈도우용 프로그램을 리버스 엔지니어링하려면 아무래도 MASM 문법

 

에 익숙한 것이 낫습니다. 이런 경우에는 MASM을 공부하세요.

 

또한, MS에서 만든 것이다 보니 Visual Studio에서 C언어와 함께 인라인 어셈블이 가능합니다.

'asm' 카테고리의 다른 글

어셈을 시작하며  (0) 2010.08.27
About link errors  (0) 2010.07.15
segment:offset  (0) 2010.07.07
AND