'Embedded Lab > linux, x86' 카테고리의 다른 글
[JTAG & UART] (0) | 2012.09.13 |
---|---|
[Flash Memory(NOR / NAND)] (0) | 2012.09.12 |
[vim에서 여러 줄에 주석 달고 해제하기] (0) | 2012.08.30 |
[bashrc에 shell 칼라 설정] (0) | 2012.08.30 |
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
[JTAG & UART] (0) | 2012.09.13 |
---|---|
[Flash Memory(NOR / NAND)] (0) | 2012.09.12 |
[vim에서 여러 줄에 주석 달고 해제하기] (0) | 2012.08.30 |
[bashrc에 shell 칼라 설정] (0) | 2012.08.30 |
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
명령 모드에서
V를 누르게 되면 하단에 Visual이라는 메세지가 출력됨 그 상태에서 주석 처리할 줄을 선택한 후에
:norm i#
-> # : 추가할 문자
주석 지울 시에는 V를 눌러 Visual로 전환후 주석 제거할 줄 선택 후
:norm 2x
-> 2는 선택된 줄의 왼쪽으로 부터 몇번째 문자
-> x는 삭제를 의미
1v, 2v 이런식으로 v명령어 앞에 숫자를 붙여서 사용할수도 있으며
1v 는 20줄 선택 2v는 40줄 선택 이런식으로 20줄씩 증가
[Flash Memory(NOR / NAND)] (0) | 2012.09.12 |
---|---|
[fork에 대한 그림 설명] (0) | 2012.09.05 |
[bashrc에 shell 칼라 설정] (0) | 2012.08.30 |
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
[NASM과 MASM] (0) | 2012.06.02 |
[fork에 대한 그림 설명] (0) | 2012.09.05 |
---|---|
[vim에서 여러 줄에 주석 달고 해제하기] (0) | 2012.08.30 |
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
[NASM과 MASM] (0) | 2012.06.02 |
[CPU스케쥴러] (0) | 2012.05.26 |
nask는 NASM를 최적화한 어셈블러입니다.
명령어는 대소문자를 구분하지 않습니다.
DB(data byte) :파일의 내용을 1바이트만 직접 쓰는 명령어
RESB(reserve byte) : 예약의 의미(nask에서는 예약뿐아니라 띄어놓은 부분을 0x00으로 채우준다.)
; : 주석
DW(data word) : 어셈블러에서 워드는 16bit(2byte)의 의미
DD(data double-word): 더블워드는 32bit(4byte)의 의미
'명령어 $' : 이때 $는 이 행이 선두로부터 몇 바이트째인가를 알려주는 변수
<c언어의 #define 역할>
EQU
ex) CYLS EQU 10
ORG(origin) : 메모리 어디에 로딩되는지 nask에 알려주기 위한 명령어.(시작점 위치 알려주기)
ORG명령어 사용시 달러마크($)의 의미는 출력파일에서 몇 번째바이트인지를 나타내지 않고,
ORG에 지정된 주소로부터 몇 번째 주소인지를 나타낸다.
"entry:" : entry라는 레이블 선언. ':'사용하면 레이블을 선언한다.
<제어문>
MOV : 대입문
ex) MOV AX,0 ; AX=0
JMP : c언어의 goto문역할
CMP : 비교문
JE(jump if equal): 조건 점프 명령어
ex) CMP AL,0
JE fin
//AL == 0이 같으면 fin으로 이동해라.
JAE(jump if above or equal) : 크거나 같으면 점프
ex) CMP SI, 5 ; SI>=5이면 에러로..
JAE error
JA : 크거나
JBE(jump if below or equal) : 작거나 같으면 점프
JB : 작거나
JC(jump if carry) : 캐리플래그가 1이면 점프
JNC(jump if not carry) : 캐리플래그가 0이면 점프
INT(interrupt) : 인터럽트 명령어
HLT(halt) : CPU를 대기상태 만드는 명령어. 키보드, 마우스에 변화가 생기면 CPU는 계속 해서 프로그램 실행
//전기를 절약할수있다.
<메모리를 지정할때>
"데이터의 크기[번지]"
ex) MOV BYTE [678], 123
메모리 678주소에 123을 기억시킨다. 데이터 크기로는 BYTE, WORD, DWORD
<대표적인 16bit(2byte) 레지스터>
AX : 어큐뮬레이터(accumulator: 누적 연산기)
CX : 카운터(counter:수를 세는 기계)
DX : data
BX :base
SP :stack pointer
BP :base pointer
SI : source index(읽기 인덱스)
DI : destination index(쓰기 인덱스)
<8bit(1byte) 레지스터>
AL : accumulator low(AX 레지스터의 16비트 중 아래쪽 비트 0~7부분)
CL : counter low
DL : data low
BL : base low
AH : accumulator high(AX 레지스터의 16비트 중 위쪽 비트 8~15부분)
CH : counter high
DH : data high
BH : base hight
//BP, SP, SI, DI는 L과 H로 나눌수 없다.
//여기서 32bit 레지스터는 단지 E(Extend)만 16비트 레지스터명 앞에 붙인다.
< 16bit 세그먼트 레지스터>
ES : extra segment( 덤 세그먼트)
CS : code segment
SS : stack segment
DS : data segment
FS : 명칭없음(덤 세그먼트 2번째)
GS : 명칭없음(덤 세그먼트 3번째)
◆ 어떤 메모리라도 세그먼트 레지스터와 함께 번지를 지정하지 않으면 안된다.
그래서 MOV CX,[1234]는 MOV CX,[DS:123]와 같다. 어셈블에서는 생략해도 자동으로 해준다.
MOV AL,[SI] 는 MOV AL,[DS:SI]라는 의미 .기본적으로 DS:가 붙기때문에 항상 DS는 0으로 안하면 메모리 번지는 DS*16 + SI가 된다.
[vim에서 여러 줄에 주석 달고 해제하기] (0) | 2012.08.30 |
---|---|
[bashrc에 shell 칼라 설정] (0) | 2012.08.30 |
[NASM과 MASM] (0) | 2012.06.02 |
[CPU스케쥴러] (0) | 2012.05.26 |
[캐리지리턴(\r)] (0) | 2012.05.04 |
->NASM : 프리웨어로 윈도우와 리눅스에서 어셈블리어를 확인할수있다.
->MASM : 마이크로사의 어셈블러 로써 윈도우즈에서만 사용가능하다.
명렁어의 차이 (1)
주소 지정 방식의 차이
MASM에서는…
- Mov AX, offset defined_data
defined_data 의 주소를 AX에 저장
- Mov AX, defined_data
defined_data 의 값을 AX에 저장
NASM에서는…
- Mov AX, defined_data
defined_data 의 주소를 AX에 저장
- Mov AX, [defined_data]
defined_data 의 값을 AX에 저장
명렁어의 차이 (2)
피 연산자 사용의 차이
MASM에서는…
용도에 따라서, @, $, %, %% 등이 사용됨
약간 복잡한 방식
NASM에서는…
주소를 나타내는 [ ] 외에는 달리 사용되는 특수문자가 없음
프로그래머에게 단순한 사용 방식을 제공
기타 차이점 (1)
MASM 과 NASM의 사용 시, DB 혹은 DW 등을 이용하여 변수를 선언 시에 약간 다를 수 있다.
스트링 선언 방식의 차이 등…
times, resb, resw 등의 약간의 차이점이 있음
이들 어셈블러는 해당 버전마다 약간씩 사용법이 다를 수 있다.
추가된 새로운 지시어/피연산자 사용 법
매크로의 사용방법 등…
나머지는 NASM Manual 문서를 찾아보도록 하자
[bashrc에 shell 칼라 설정] (0) | 2012.08.30 |
---|---|
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
[CPU스케쥴러] (0) | 2012.05.26 |
[캐리지리턴(\r)] (0) | 2012.05.04 |
[vi편집기 자동정렬] (0) | 2012.05.01 |
※CPU스케줄링
1) 정의
- 작업을 처리하기 위해 프로세스들에게 중앙처리 장치나 각종 처리기들 을 할당하기 위한
정책을 계획하는 것
2) 방법별 분류
① 선점(preemptive) 스케쥴링
- 한 프로세스가 CPU를 차지하고 있을 때 우선순위가 높은 다른 프로세스가 현재 프로세
스를 중지시키고 자신이 CPU를 차지할 수 있는 경우
- 높은 우선순위를 가진 프로세스들이 빠른 처리를 요구하는 시스템에서 유용
- 빠른 응답시간을 요구하는 시분할 시스템에 유용
- 높은 우선순위 프로세스들이 들어오는 경우 오버헤드를 초래
② 비선점(nonpreemptive) 스케쥴링
- 한 프로세스가 CPU를 할당받으면 다른 프로세스는 CPU를 점유못함
- 짧은 작업을 수행하는 프로세스가 긴 작업이 종료될 때까지 기다려야 함
- 모든 프로세스들에게 공정하고 응답시간의 예측이 가능
3) CPU 스케쥴링 알고리즘별 분류
① 우선순위(priority) 스케줄링
- nonpreemptive
- 프로세스에게 우선순위를 부여하여 우선순위가 높은 순서대로 처리
ㄱ) 정적(static) 우선순위 방법
- 주변 환경 변화에 적응하지 못하여 실행중 우선순위를 바꾸지 않음, 구현이 쉽고
오버헤드가 적다
ㄴ) 동적(dynamic) 우선순위 방법
- 상황 변화에 적응하여 우선순위를 변경, 구현이 복잡, 오버헤드 많다,
시스템의 응답속도를 증가시켜 효율적
② 기한부(deadline) 스케줄링 - nonpreemptive
- 작업을 명시된 시간이나 기한내에 완료되도록 계획
- 작업시간이나 상황등 정보를 미리 예측하기가 어렵다
③ FIFO 스케줄링 - nonpreemptive
- 프로세스들은 대기 큐에 도착한 순서대로 CPU를 할당 받는다
- 일괄처리 시스템에서 주로 사용, 작업 완료 시간을 예측하기 용이
- 짧은 작업이 긴 작업을 기다리게 됨
- 중요하지 않은 작업이 중요한 작업을 기다리게하여 불합리
④ 라운드로빈(round robin) 스케줄링
- preemptive
- FCFS에 의해서 프로세스들이 보내지며
- 각 프로세스는 같은 크기의 CPU 시간을 할당 받는다
- 시분할 방식에 효과적, 할당시간의 크기가 매우 중요
- 할당시간이 크면 FCFS와 같게되고, 작으면 문맥교환이 자주 일어난다
⑤ SJF(shortest job first) 스케줄링 - nonpreemptive
- 준비큐내의 작업중 수행시간이 가장 짧다고 판단되는 것을 먼저 수행
- FCFS보다 평균 대기 시간을 감소, 큰 작업은 시간 예측이 어렵다
- 짧은 작업에 유리
⑥ SRT(short remaining time) 스케줄링
- preemptive
- 가장 짧은 시간이 소요된다고 판단되는 프로세스를 먼저 수행
- 남은 처리 시간이 더 짧다고 판단는 프로세스가 준비큐에 생기면 언제라도 실행중인
프로세스가 선점됨
- 긴 작업은 SJF보다 대기 시간이 길다
⑦ HRN(highest response ratio next) 스케줄링
- nonpreemptive
- 긴 작업과 짧은 작업간의 지나친 불평등을 어느 정도 보완한 기법
- 짧은 작업이나 대기시간이 긴 작업은 우선순위가 높아진다
⑧ 다단계 큐(multilevel queue) 스케줄링
- preemptive
- 작업들을 여러 종류의 그룹으로 나누어 여러개의 큐를 이용하는 기법
⑨ 다단계 피드백 큐(multilevel feedback queue) 스케줄링
- preemptive
- 입출력 위주와 CPU 위주인 프로세스의 특성에 따라 서로 다른 CPU의 타임 슬라이스를
부여
- 짧은 작업에 유리, 입출력 위주의 작업에 우선권을 줌
- 하위단계 큐일수록 할당시간은 커진다
※프로레스 스케쥴링 기법
1. preemptive 기법(선점 기법)
하나의 프로세스가 CPU를 점유하고 있을 때 다른 프로세스가 CPU를 빼앗을 수 있는 방법.
1) Round Robin 스케줄링: FIFO와 같은 방법이지만, 주어진 시간 할당량 안에 작업을
마쳐야 하며, 할당량을 다 소비하고도 작업이 끝나지 않은 프로세스는 다시 대기 큐의
맨 뒤로 돌아가는 방법.
2) SRT 스케줄링: 실행시간 추정치(남은 시간)가 가장 적은 프로세스에게 먼저
CPU를 할당하는 방법.
3) MFQ(다단계 피드백 큐) 스케줄링: 작업처리를 여러 단계로 나누어 처리하는 기법으로
높은 단계에서는 시간 할당량을 짧게 주고, 낮은 단계로 갈수록 시간 할당량을 많이
주고 마지막 단계는 RR기법으로 처리.
2. non-preemptive 기법(비선점 기법)
프로세스에게 이미 할당된 CPU를 강제로 빼앗을 수 없고, 사용이 끝날 때까지 또는
CPU를 할당 받은 프로세스가 스스로 넘길 때까지 기다려야 하는 방법.
1) FIFO 스케줄링: 대기 큐에 먼저 들어온 작업에게 CPU를 먼저 할당.
2) SJF 스케줄링: 작업 시간이 가장 적은 프로세스에게 CPU를 먼저 할당하는 기법.
3) HRN 스케줄링: 우선 순위에 의한 방법.
[nask NASM 어셈블러 문법] (0) | 2012.06.07 |
---|---|
[NASM과 MASM] (0) | 2012.06.02 |
[캐리지리턴(\r)] (0) | 2012.05.04 |
[vi편집기 자동정렬] (0) | 2012.05.01 |
[rm, rndir 옵션] (0) | 2012.04.11 |
캐리지 리턴(CR)과 라인 피드(LF)는 느린 프린터의 유산인 걸로 알고 있습니다. 굳이 두 동작으로 나눈 이유는 과거의 느린 프린터가 물리적인 동작을 취하는데 충분한 시간을 확보해주기 위해서 신호를 두 개로 나누어 보내주었기 때문이라고 알고 있습니다. 하지만 현재는 둘 중 하나만 있어도 뉴라인으로 간주합니다. 따라서 신경쓰지 않으셔도 됩니다. (아~~주 가끔 그 문제로 삽질을 하는 경우도 있을 수는 있지만..- -+) 그리고 LF로 뉴라인을 나타내는지 CR+LF로 뉴라인을 나타내는지는 언어의 차이가 아니라 시스템의 차이입니다. 덧붙이자면, printf ("abcdefg\rhi"); 화면표시결과는 abcdefg 표시후 맨앞줄로 이동후 hi를 표시하면 hicdefg 로 나타나고, printf("abcdefg\nhi"); 화면표시결과는 abcdefg 표시후 다음줄로 이동후 hi를 표시하면 abcdefg hi 위에서 g 바로밑 다음부터 hi임 (편집기에서 바로보이는지 조금 안맞네요) printf("abcdefg\n\rhi"); 는 abcdefg 표시후 커서를 맨앞으로 이동후 줄을 바꾸고 hi를 표시합니다. abcdefg hi 로 나타납니다.
CR은 현재 위치를 나타내는 커서(?)를 맨 앞으로 이동시킨다는 뜻이고,
LF는 커서의 위치를 아랫줄로 이동시킨다는 뜻입니다.
이 두 동작을 합치면 뉴라인('\n')과 동일한 동작을 하게 됩니다.
Unix-like 시스템에서는 LF로,
윈도우즈에서는 CR+LF로 표현합니다.
정규식에서는 CR과 LF는 의미가 없습니다.
모두 뉴라인 하나로 표현됩니다.
[NASM과 MASM] (0) | 2012.06.02 |
---|---|
[CPU스케쥴러] (0) | 2012.05.26 |
[vi편집기 자동정렬] (0) | 2012.05.01 |
[rm, rndir 옵션] (0) | 2012.04.11 |
[x86 / datasheet / 메모리관리 / x86에서의 메모리정책 (보호모드/실제모드)] (0) | 2012.04.04 |
1. visual
gg: 파일의 처음으로
v: visual mode
G: 파일의 끝까지 선택 후
=: 정렬
2. non visual
gg: 파일의 처음으로
=: 정렬
G: 끝까지
gg: 파일의 처음으로
G: 파일의 끝으로
[CPU스케쥴러] (0) | 2012.05.26 |
---|---|
[캐리지리턴(\r)] (0) | 2012.05.04 |
[rm, rndir 옵션] (0) | 2012.04.11 |
[x86 / datasheet / 메모리관리 / x86에서의 메모리정책 (보호모드/실제모드)] (0) | 2012.04.04 |
[TSS(Task State Segment)] (0) | 2012.04.04 |
rm -r 폴더이름 : 해당폴더와 그 밑에 하위 폴더 모두 삭제
[캐리지리턴(\r)] (0) | 2012.05.04 |
---|---|
[vi편집기 자동정렬] (0) | 2012.05.01 |
[x86 / datasheet / 메모리관리 / x86에서의 메모리정책 (보호모드/실제모드)] (0) | 2012.04.04 |
[TSS(Task State Segment)] (0) | 2012.04.04 |
[extern 키워드] (0) | 2012.04.04 |
0. 서문
1. 실제모드
실제모드는 x86 계열로 처음 등장한 Intel 8086 CPU와 같은 동작 모드를 말하는 것으로, 16 bit CPU인 8086, 80286에서뿐만 아니라, 80386 이후의 모든 32-bit 프로세서에서도 이를 지원한다. x86 계열의 모든 CPU는 처음 시작할 때는 실제모드로 동작한다.
실제모드에서는 20 bit address bus를 사용하여 총 1MB의 메모리를 사용할 수 있으며, 16 bit register를 사용한다. 레지스터의 크기가 16 bit이기 때문에, 20 bit 주소를 나타내기 위해 segment register라는 것을 도입하였다. 이는 16 bit segment register와 16 bit offset을 중첩시켜서 20 bit의 주소를 만들어내는 것이다. 모든 메모리 접근에는 segment와 offset이 같이 필요하며, 하나의 segment를 사용하면 64K(0x10000)만큼의 메모리를 사용할 수 있다. 실제모드에서는 가상 메모리라는 개념이 존재하지 않으며, segment와 offset으로 만들어지는 주소는 바로 물리적인 메모리 주소이다. 또한 이 모드에서 동작하는 모든 프로그램은 메모리의 어떤 영역이든지 맘대로 접근할 수 있으며, cli (clear interrupt), sti (set interrupt)같은 명령어를 포함하여 실제모드에서 사용할 수 있는 모든 명령어들을 모두 사용할 수 있다.
IBM-PC는 8086 CPU를 이용하여 만들어졌는데, 이것이 처음 등장하던 당시엔 1MB의 메모리는 상당히 큰 것이었다. 그래서 IBM은 앞의 640KB(0 - 0x9ffff)만을 프로그램이 사용할 수 있게 하고, 나머지 384KB(0xa0000 - 0xfffff)는 BIOS와 ISA 장치용으로 사용하게 하였는데, 이는 실제모드로 동작하는 각종 프로그램들이 640KB의 메모리만을 사용할 수 밖에 없는 제약을 만들었다. 일반적으로 리눅스 부팅을 할 때 사용되는 LILO도 실제모드로 시작하여 리눅스 커널을 로드하기 때문에, 마찬가지로 640KB의 제약을 받게 된다.
2. 보호모드(Protected Mode)
Intel 80286부터 처음 도입된 보호모드는 80386에 이르러서 완성된 모습을 보여 지금에 이르게 된다. 80286의 보호모드를 간단히 살펴보면, 우선 24 bit address bus를 사용하여 총 16MB(0x1000000)의 메모리를 사용할 수 있게 하였다.
segment register는 selector라는 명칭으로 바뀌었고, descriptor table이라는 것을 통하여 16 bit segment를 24 bit base address로 바꾸게 하였다. 이 base address에 offset을 더함으로써 모두 16MB의 메모리를 사용할 수 있었지만, 80286 역시 16 bit CPU였기 때문에 각 segment의 크기는 여전히 64KB의 제한을 가지게 되었다.
이런 제한을 없애고 완전한 32 bit address space와 32 bit register set을 제공하는 80386이 등장하였고, 이후에 운영체제들은 80386에서 제공하는 보호모드의 기능을 활용하게 되었다. 보호모드에서는 CPU가 제공하는 모든 기능과 명령어들을 활용할 수 있다. 보호모드에서는 privilege level이라는 것이 등장하는데, 이는 프로세서를 활용할 수 있는 권한정도를 말한다. 이는 0부터 3까지 있는데, 0이 모든 일을 할 수 있는 모드로 일반적인 운영체제 구현에서 커널모드가 이 상태이며, 3은 응용프로그램처럼 사용자 권한의 실행상태를 나타낸다. 이 privilege level을 통하여 커널모드/사용자모드를 구현하게 된다. 보호모드에서는 32 bit address bus를 통하여 4GB의 메모리를 사용할 수 있으며, 메모리 보호기능과, 페이징(paging) 메커니즘 등을 통해 가상 메모리를 효율적으로 구현할 수 있다. 인터럽트나 예외처리, task switching 등도 모두 보호모드에서 지원하는 기능을 활용한다.
3. Intel 80386 Registers TSS (Task State Segment)가 있는 위치를 가리키는 GDT 내의 TSS descriptor를 가리키는 selector. 내부적으로 segment의 base address와 segment limit도 가지고 있지만 외부에서는 selector 값만을 참조할 수 있다. LTR (Load TR), STR (Save TR) 명령으로 참조하고 설정한다.
4. 보호모드에서의 메모리 관리
보호모드에서는 segmentation과 paging 메커니즘을 이용하여 메모리를 관리한다. segmentation은 4GB의 메모리를 segment라는 단위로 쪼개는 것을 말한다. 여기서는 16 bit의 selector와 32 bit의 offset을 이용하여 4GB 범위안에 있는 32 bit의 선형주소(linear address)를 만드는 일을 한다. 이렇게 만들어진 선형주소가 물리주소(physical address)가 되는 것이 아니라 메모리를 4KB 단위로 쪼개서 관리하는 paging mechanism을 거쳐서 물리주소로 변환된다. (control register CR0의 PG flag를 수정함으로써 paging 메커니즘을 사용하지 않을 수도 있다)
여기에는 segment의 base address와 segment limit (크기), 그리고 DPL (descriptor privilege level)을 비롯한 정보가 들어간다. (여기에 보면 segment type이라는 것이 있다. 이것은 이 descriptor가 나타내는 것이 무엇인지를 말하는 것이다. segment는 일반적인 code/data/stack일 수도 있고, 뒤에 나오는 TSS 일수도, gate일 수도 있는데 이 type을 가지고 무엇을 가리키는 descriptor인지 구별할 수 있으며, 이에 따라 descriptor의 구조가 달라진다.)
segment descriptor table은 이들 segment descriptor를 모아두고 있는 것을 말하는데, 여기에는 시스템 전체에 대한 descriptor table인 GDT (global descriptor table)과 프로세스마다 개별적으로 정의하고 있는 LDT (local descriptor table)이 있다. 이들은 모두 메모리 상에 존재하게 되는데, GDT의 위치는 GDTR (GDT register)가 가리키고 있다. LDT의 위치는 LDTR (LDT register)가 가리키고 있는데 이 LDTR은 원래 GDT에 있는 한 segment descriptor를 가리키고 있는 selector이다. 즉 GDT에는 시스템에 있는 모든 LDT에 대한 segment descriptor가 들어있으며, LDTR은 이 중 현재 프로세스의 LDT에 대한 segment descriptor를 가리키는 selector이다.
16 bit인 selector에는 이 descriptor table에서의 index 값과, 이것이 이것이 GDT에서의 index인지, LDT에서의 index인지를 나타내는 TI (table indicator), 권한을 나타내는 RPL (requestor privilege level)이 들어있다. 이 TI와 index를 가지고 해당하는 table에서 segment descriptor를 찾아서 base address를 구하게 된다. 이 값에 offset을 합하면 지정한 selector와 offset에 해당하는 linear address가 만들어지게 된다.
이렇게 segmentation을 거쳐 나온 linear address는 paging 메커니즘을 통하여 physical address로 변환이 된다.
paging은 요즘의 운영체제에서 모두 구현하고 있는 paging을 지원하기 위한 것이다. 이를 이용하여 실제로 하드웨어적으로 있는 메모리보다 많은 메모리를 사용할 수 있으며, 메모리를 효율적으로 사용할 수 있으며, swapping을 쉽게 구현할 수 있게 된다. 메모리는 4KB 단위의 page로 쪼개지며, 이들은 page directory와 page table로 체계화된다.
각 page들의 시작 위치는 page table entry에 기록이 되며, 각 page table들의 위치는 page directory entry에 들어있다. page directory의 시작 위치는 control register중의 하나인 CR3이 가지고 있다. 앞에서 넘어온 linear address는 page directory에서의 index, page table에서의 index, offset 세가지로 쪼개지며, 이들 table들을 차례로 따라가서 실제 page의 주소를 얻고, 여기에 offset을 더함으로써 실제 physical address가 나오게 된다.
이렇게 가상주소가 물리주소로 변환되는 과정을 정리하면 다음과 같다.
5. 보호모드에서의 태스크 관리
보호모드에서는 각 task별로 TSS (Task State Segment)라는 것을 관리한다. 여기에는 하나의 task의 상태 - 일반 register, segment register, flag, EIP, stack segment selector, stack pointer, LDT selector, page directory base address 등 - 가 저장이 되며, task switching이 일어날 때 이전의 상태를 자동으로 여기에 저장을 하며, 새로운 TSS에 있는 상태가 현재 상태로 복구가 된다. task register인 TR은 현재 task의 TSS를 가리키는 selector이다. 각 TSS는 GDT에서 TSS descriptor로 기술되며, TR은 이 중에서 현재 TSS의 descriptor를 가리키는 것이다.
task switching을 하는 방법으로 우선 call이나 jmp 명령에 전환할 TSS selector를 지정하는 것이 있다. 이렇게 하면 프로세서는 현재 상태를 현재 TSS에 저장을 하고, 새로운 task의 TSS로 상태를 모두 바꾼후, 새로운 task를 실행한다.
task gate는 task switching을 일으키는 특별한 descriptor로서 LDT나 IDT (Interrupt Descriptor Table)에 들어가는 descriptor이다. 여기에는 TSS descriptor에 대한 selector가 들어있다. task gate는 interrupt나 trap이 발생하였을 때 task switching이 일어나게 하는 것처럼 간접적으로 task switching이 일어나게 하거나, 특정한 task들이 TSS에 접근할 수 있도록 하기 위해서 사용한다. 앞의 경우에서처럼 call이나 jmp에 task gate의 selector를 지정을 해주면 여기서 가리키는 TSS로 task switching이 일어난다. 또한 task gate가 IDT에 있을 때 해당하는 interrupt가 발생하면 이 task gate를 통하여 해당하는 TSS로 task switching이 일어나게 된다.
6. 보호모드에서의 인터럽트/예외 처리
인터럽트나 예외가 발생하면 어떤 것이 발생하였는지 식별하는 번호가 나오게 된다. (인터럽트는 CPU의 인터럽트 핀에 의하여 발생하며, 예외는 프로세서가 작업을 하는 중에 잘못된 일을 발견하거나 - 여기에는 fault, trap, abort가 있다 -, 프로그래밍으로 들어가 있는 코드에 의하여 - INT 3, INT n, BOUND 등 - 에 의하여 발생하는 것이다) 이 번호를 vector라고 부르는데 이를 index 삼아, IDT (interrupt descriptor table)에 있는 descriptor를 찾아서 이를 처리하게 된다. IDT는 interrupt 처리에 관련된 descriptor들을 모아둔 것으로 이의 위치는 IDTR (IDT register)가 가지고 있다.
여기에 들어가는 descriptor로는 task gate, interrupt gate, trap gate가 있다. task gate는 앞에서 이야기한 것처럼 TSS selector를 가지고 있는 gate로서, 해당하는 TSS로 task switching이 일어나게 된다. interrupt gate와 trap gate는 GDT/LDT에 있는 segment descriptor에 대한 selector와 offset을 가지고 있는 gate로서, selector를 가지고 segment의 시작주소를 얻고, 여기에 offset을 더하여 이를 처리할 handler의 주소를 얻게 된다. 그리고 이 handler의 위치로 건너가서 해당하는 처리를 한 후 이를 마친후에 복귀하게 된다. 이 과정에서 privilege level이 바뀔 수도 있으며, 처리 중에는 현재 TSS에 있는 stack을 그대로 사용한다. interrupt gate와 trap gate를 통하는 경우의 차이는, interrupt gate를 통하는 경우 처리하는 동안 interrupt를 금지하고 (flag의 IF를 clear) 처리를 마치고 복귀할 때 다시 이를 복구하지만, trap gate를 통하는 경우에는 interrupt를 금지하지 않는다.
7. 보호모드에서의 시스템콜
시스템콜은 사용자모드에서 커널모드에서 실행되는 코드를 부르기 위한 방법이다. 이를 위해서 위해서 보호모드에서는 call gate라는 것을 제공한다. call gate는 다른 privilege level 사이로 제어권을 넘기는 방법으로, segment selector와 offset을 가지고 있다. 이 selector는 GDT/LDT에 있는 segment descriptor를 가리키고, 여기서 얻어지는 base address에 offset을 더하여 실행할 함수의 위치를 얻게 된다. call이나 jmp 명령에 목적하는 call gate의 segment selector를 지정함으로써 call gate를 통하여 커널모드로 진입하게 된다.
이 때 CPL (current privilege level)과 call gate descriptor의 DPL, call gate selector의 RPL을 비교하여 권한을 검사한다. 시스템콜에 진입하였을 때에는 현재 task의 TSS에 있는 stack을 사용하며, ret 명령을 통해서 결과값과 함께 시스템콜을 부르기 이전의 상태로 되돌아가게 된다.
[vi편집기 자동정렬] (0) | 2012.05.01 |
---|---|
[rm, rndir 옵션] (0) | 2012.04.11 |
[TSS(Task State Segment)] (0) | 2012.04.04 |
[extern 키워드] (0) | 2012.04.04 |
[cp 명령어옵션] (0) | 2012.04.03 |