와 신난다.
이제, 0SOS는 32비트 코드를 실행 할 수 있다.
그말은즉슨, 32비트 범용레지스터를 쓸 수 있다는 이야기.
eax, esi 등등 같은거 말이다.
아 기뻐라.
이걸 봐라.
보면 잘 돌아간다.
C언어로 하면 되는데요 같은 헛소리 할꺼면 창 닫기를
아무튼 이해하려고 용썻다.
다 이해했다.
젠장맞을, 세그먼트 테이블하고, 메모리 사용 범위, 스택때문에 좀 머리아팠음.
일단 16비트 리얼모드에서 32비트 보호모드로 바꾸려면
GDT 테이블을 구성하고
프로세서에 GDT의 크기와 위치를 알린다.
그 테이블 안에 첫번째 요소로는 NULLDescriptor이라고, 모든 필드가 0으로 초기화 한
세그먼트 디스크립터를 넣고
그다음에는 우리가 정의하는데
나와 책 저자분은
Code, Data 세그먼트 디스크립터를 넣었다.
여기서 이해하려고 용썼는데,
나는 코드와 데이터 디스크립터의 베이스 주소, 제한이 동일하길레 둘이 겹치면 안되는 거
아닌가 라는 생각을 했는데,
내가 잘못 전제를 깔고 들어갔던거다.
젠장 결국
현재 코드에선, 정확힌 지금 정의된 테이블에선
코드영역하고 Data영역하고 세그먼트 디스크립터가 구분해주지 않는다
둘다 다 0~4GB를 가르킬 수 있는 디스크립터.
그리고 스택은 위에서 아래로 자라기때문에, Data영역의 데이터랑 겹칠일은 없다.
(64kb가 제한이기 떄문, 코드에서 esp, ebp를 보기 바람)
그래서 코드에 상대주소값으로 계산하는 코드가 있구만
(LABEL - $$ + 0x10000) 같은거.
아무튼 완전히 이해했으니 넘어가고
그러고 나선, 운영모드를 관리하는 CR0 레지스터를 설정해준다.
설정값은 아레 코드에 표로 만들어져 있뒀으니까 보시고, 각 요소가
뭔지 궁금하면 검색하세요.
변환후 32비트 코드영역으로 점프하면 완성.
와 신나.
아무튼 32비트 전환을 위하면서
시작점이 될 Kernel Entry Point는 다음과 같다.
[ORG 0x00]
[BITS 16]
SECTION .text
START:
mov ax, 0x1000
mov ds, ax
mov es, ax
cli ;Ignore Interrupt
lgdt[GDTR]
; Now Switch Protected Mode.
;
; CR0 Register
; Summary:
; Disable Paging, Disable Cache, Internal FPU, Disable Align Check
;
; fields:
;
; |PG|CD|NW| | | | | | | | | | |AM| |WP|
; 31---------------------------------------------16
; | 0| 1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|
;
; | | | | | | | | | | |NE|ET|TS|EM|MP|PE|
; 15----------------------------------------------0
; | 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 1| 1| 1| 0| 1| 1|
;
; 0b01000000000000000000000000111011
; 0x4000003B
;
mov eax, 0x4000003B
mov cr0, eax
jmp dword 0x08 : (PROTECTEDMODE - $$ + 0x10000)
; Following Code Now Prtoected Mode
[BITS 32]
PROTECTEDMODE:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0XFFFE
mov ebp, 0XFFFE
push (SWITCHMESSAGE - $$ + 0x10000)
push 2
push 0
call PRINT
add esp, 12
jmp $
PRINT:
push ebp
mov ebp, esp
push esi
push edi
push eax
push ecx
push edx
mov eax, dword [ebp + 12]
mov esi, 160
mul esi
mov edi, eax
mov eax, dword[ebp + 8]
mov esi, 2
mul esi
add edi, eax
mov esi, dword[ebp + 16]
.PRINTLOOP:
mov cl, byte[esi]
cmp cl,0
je PRINTEND
mov byte[edi + 0xB8000], cl
add esi,1
add edi,2
jmp .PRINTLOOP
PRINTEND:
pop edx
pop ecx
pop eax
pop edi
pop esi
pop ebp
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;; DATA AREA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 8, db 0
dw 0x0000 ;For Align
GDTR:
dw GDTREND - GDT -1
dd GDT - $$ + 0x10000
GDT:
NULLDescriptor:
dw 0x0000
dw 0x0000
db 0x00
db 0x00
db 0x00
db 0x00
CODEDescriptor:
dw 0xFFFF ; Limit[15:0]
dw 0x0000 ; Base[15:0]
db 0x00 ; Base[23:16]
db 0x9A ; P = 1, DPL = 0, Code Segment, Execute/Read
db 0xCF ; G = 1, D = 1, L = 0, Limit [19:16]
db 0x00 ; Base[31:24]
DATADescriptor:
dw 0xFFFF ; Limit
dw 0x0000 ; Base
db 0x00 ; Base
db 0x92 ; P=1, DPL =0, Data Segment, Read/Write
db 0xCF ; G= 1, D= 1, L= 0, Limit
db 0x00 ; Base
GDTREND:
SWITCHMESSAGE: db 'Switch Success. Now Running 32bit Protected Mode.',0
times 512 - ( $ - $$) db 0x00
리얼모드와 보호모드는 확실하게 메모리 접근이 다르다
이거이거 IA-32e 에서는 얼마나 복잡할지 기대되는데
게다가 페이징도 Disable인상태라 페이징 넣으면 얼마나 복잡해지려나 ㅋㅋㅋ…
아무튼 , 코드에 있는 표 나름 이쁘게 만들었다.
vim에선 이렇게 보이는데
위에 코드는 어떻게 보일지 모르겠네.
아무튼 32비트 완성 이제 커널코드 작성해야겠네.