minzkn@minzkn.com)
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Base (32 ~ 24bit) | G | B(D) | O | AVL | Limit (19 ~ 16bit) | ||||||||||
| P | DPL | S | E | ED/C | R/W | A | Base (23 ~ 16bit) | ||||||||
| Base (15 ~ 0bit) | |||||||||||||||
| Limit (15 ~ 0bit) | |||||||||||||||
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Selector | TI | RPL | |||||||||||||
| Type | 목적 |
| 0000b | 무효 |
| 0001b | 이용 가능한 80x286 TSS |
| 0010b | LDT |
| 0011b | 바쁜 80x286 TSS |
| 0100b | 80x286 call gate |
| 0101b | Task gate |
| 0110b | 80x286 Interrupt gate |
| 0111b | 80x286 Trap gate |
| 1000b | 무효 |
| 1001b | 이용 가능한 80x386 TSS |
| 1010b | 미래의 Intel 제품을 위한 reserved |
| 1011b | 바쁜 80x386 TSS |
| 1100b | 80x386 call gate |
| 1101b | 미래의 Intel 제품을 위한 reserved |
| 1110b | 80x386 Interrupt gate |
| 1111b | 80x386 Trap gate |
| 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Base (31 ~ 24bit) | G | B(D) | O | AVL | Limit (19 ~ 16bit) | ||||||||||
| P | DPL | 0 | Type | 0 | 0 | 0 | Word count (4 ~ 0 bit) | ||||||||
| Selector | |||||||||||||||
| Offset (15 ~ 0 bit) | |||||||||||||||
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Directory (10 bit) | Table (10 bit) | Offset (12 bit) | |||||||||||||||||||||||||||||
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Page directory base | OS bit | 0 | 0 | D | A | PCD | PWT | U/S | W | P | |||||||||||||||||||||
| 0 | 0 | 없음 |
| 1 | 0 | 없음 |
| 0 | 1 | 읽기 전용 |
| 1 | 1 | 읽기 / 쓰기 |
PageDirectory DD 4 ; 페이지 디렉토리
PageTable0 DD 1024 DUP (?) ; 페이지 테이블 0번
XOR EAX, EAX
MOV AX, CS
SHL EAX, 4
ADD EAX, OFFSET PageTable0 ; 여기까지 논리적 메모리 주소를 선형 메모리 주소로 변환한 것
AND EAX, 0fffff000h
OR AL, 7
MOV PageDirectory, EAX ; PageDirectory는 PageTable0 ...
MOV CX, 256 ; 4K * 256만큼을 재 맵핑 하기 위한 Count
MOV DI, OFFSET PageTable0
MOV AX, DS
MOV ES, AX
MOV EAX, 7 ; U/S, R/W, P를 Set
L_0:
STOSD
ADD EAX, 4096 ; Re map 00000h ~ 09ffffh to 00000h ~ 09ffffh
LOOP L_0 ; 4K단위로 Mapping
MOV EAx, 0102007h
MOV CX, 16
L_1:
STOSD ; Re map 0a000h ~ 0affffh to 102000h ~ 11ffffh
ADD EAX, 4096
LOOP L_1 ; 열심히 옮기지만 재맵핑 시키면서
XOR EAX, EAX
MOV AX, DS
SHL EAX, 4
ADD EAX, OFFSET PageDirectory
MOV CR3, EAX ; In paging... 페이징 준비 끝
| 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Directory (10 bit) | Offset (22 bit) | ||||||||||||||||||||||||||||||
| Global directory(10bit) | Middle directory(10bit) | Table(10bit) | Offset(13bit) |
| 25bit | 25bit | 14bit | |
PUSHF ; 여기서는 PUSHF, CLI, POPF는 개념적인 이해를 위해 쓴겁니다. CLI MOV EAX, CR3 MOV CR3, EAX POPF
; Copyright (c) MINZ
; Code by JaeHyuk Cho - <mailto:minzkn@infoeq.com>
DEF_ASM_GO32 EQU "GO32.ASM"
DEF_MAX_DefaultGDT = 2000h ; 8192d
DEF_MAX_DefaultIDT = 0100h ; 256d
PUBLIC RegisterIDT, RegisterGDT
PUBLIC SetupIDT, SetupGDT
PUBLIC Go32
PUBLIC L_Exit32
;
PUBLIC D_StackFrame
PUBLIC D_IDTR, D_GDTR
PUBLIC D_IDT_Item, D_GDT_Item
PUBLIC D_IDT, D_GDT
ASSUME CS:CODE_GO32, DS:DATA_GO32, ES:NOTHING, SS:STACK_DEFAULT
CODE_GO32 SEGMENT
여기까지는 그냥 일반적인 어셈블리의 앞 머리입니다.
RegisterIDT PROC FAR ; void far pascal RegisterIDT(unsigned int s_intnum) ; IDT 추가 생성
PUSH BP
MOV BP, SP
PUSH EAX
PUSH EDX
XOR EAX, EAX
MOV AX, WORD PTR [BP + 06h] ; s_intnum
MOV DX, DEF_SIZE_Descriptor
MUL DX
ADD EAX, OFFSET DESC_GO32_IDT:D_IDT
PUSH DESC_GO32_IDT
PUSH AX
PUSH DATA_GO32
PUSH OFFSET DATA_GO32:D_IDT_Item
PUSH DEF_SIZE_Descriptor
CALL FAR PTR CODE_MEMORY:MemCpy
POP EDX
POP EAX
POP BP
RETF 2
RegisterIDT ENDP
IDT를 구조에 맞게 인자로 받아서 만들어 줍니다.
RegisterGDT PROC FAR ; void far pascal RegisterGDT(unsigned int s_descnum)
PUSH BP
MOV BP, SP
PUSH EAX
PUSH EDX
XOR EAX, EAX
MOV AX, WORD PTR [BP + 06h] ; s_descnum
MOV DX, DEF_SIZE_Descriptor
MUL DX
ADD EAX, OFFSET DESC_GO32_GDT:D_GDT
PUSH DESC_GO32_GDT
PUSH AX
PUSH DATA_GO32
PUSH OFFSET DATA_GO32:D_GDT_Item
PUSH DEF_SIZE_Descriptor
CALL FAR PTR CODE_MEMORY:MemCpy
POP EDX
POP EAX
POP BP
RETF 2
RegisterGDT ENDP
GDT를 구조에 맞게 인자로 받아서 만들어 줍니다.
SetupIDT PROC FAR ; void far pascal SetupIDT(void)
PUSH DS
PUSH AX
MOV AX, DATA_GO32
MOV DS, AX
POP AX
POP DS
RETF
SetupIDT ENDP
IDT를 만드는 부분이지만 그냥 비어 있습니다. SetupGDT함수처럼 RegisterIDT를 사용하여 안에 채워넣으면 됩니다.
SetupGDT PROC FAR ; void far pascal SetupGDT(void)
PUSH DS
PUSH AX
PUSH BX
MOV AX, DATA_GO32
MOV DS, AX
; 0000h - Null descriptor
XOR AX, AX
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_LimitLow, AX
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_BaseLow, AX
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseMid, AL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access00, AL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access01, AL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseHigh, AL
PUSH AX
CALL FAR PTR CODE_GO32:RegisterGDT
; 0001h - IDT descriptor
; 0002h - GDT descriptor
; 0003h - Real code descriptor
PUSH CODE_GO32
PUSH DEF_Null
CALL FAR PTR CODE_CALC:ToPhysical
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_LimitLow, 0FFFFh
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_BaseLow, AX
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseMid, DL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access00, 10011010b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access01, 00000000b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseHigh, DH
PUSH 0003h
CALL FAR PTR CODE_GO32:RegisterGDT
; 0004h - Real data descriptor
PUSH DATA_GO32
PUSH DEF_Null
CALL FAR PTR CODE_CALC:ToPhysical
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_LimitLow, 0FFFFh
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_BaseLow, AX
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseMid, DL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access00, 10010010b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access01, 00000000b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseHigh, DH
PUSH 0004h
CALL FAR PTR CODE_GO32:RegisterGDT
; 0005h - Full data descriptor
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_LimitLow, 0FFFFh
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_BaseLow, 00000h
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseMid, 000h
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access00, 10010010b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access01, 11001111b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseHigh, 000h
PUSH 0005h
CALL FAR PTR CODE_GO32:RegisterGDT
; 0006h - Video data(TEXT) descriptor
; 0007h - Video data(GRAPHICS) descriptor
; 0008h - Code descriptor
PUSH CODE_KN32
PUSH OFFSET CODE_KN32:KernelMain32
CALL FAR PTR CODE_CALC:ToPhysical
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_LimitLow, 0FFFFh
MOV WORD PTR DATA_GO32:D_GDT_Item.STRUC_BaseLow, AX
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseMid, DL
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access00, 10011110b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_Access01, 11000000b
MOV BYTE PTR DATA_GO32:D_GDT_Item.STRUC_BaseHigh, DH
PUSH 0008h
CALL FAR PTR CODE_GO32:RegisterGDT
; 0009h - Data descriptor
; 000Ah - Bss descriptor
; 000Bh - Stack descriptor
; 000Ch - Heap descriptor
; Load GDT
MOV EAX, OFFSET DESC_GO32_GDT:D_GDT
PUSH DESC_GO32_GDT
PUSH AX
CALL FAR PTR CODE_CALC:ToPhysical
MOV WORD PTR DATA_GO32:D_GDTR.STRUC_LimitLow, (DEF_MAX_DefaultGDT * DEF_SIZE_Descriptor) - 1
MOV WORD PTR DATA_GO32:D_GDTR.STRUC_BaseLow, AX
MOV BYTE PTR DATA_GO32:D_GDTR.STRUC_BaseMid, DL
MOV BYTE PTR DATA_GO32:D_GDTR.STRUC_Access00, DH
LGDT QWORD PTR DATA_GO32:D_GDTR
POP BX
POP AX
POP DS
RETF
SetupGDT ENDP
사용할 Descriptor를 성격에 맞게 등록합니다.
Go32 PROC FAR ; void far pascal Go32(void)
PUSH DS
PUSH ES
PUSH FS
PUSH GS
PUSHAD
; Print
PUSH DATA_GO32
PUSH OFFSET DATA_GO32:S_MSG_Go32_Enter
CALL FAR PTR CODE_TEXT:Puts
; Clear descriptor
PUSH DESC_GO32_IDT
MOV EAX, OFFSET DESC_GO32_IDT:D_IDT ; 32bit offset
PUSH AX
PUSH DEF_Null
PUSH (DEF_MAX_DefaultIDT * DEF_SIZE_Descriptor) SHR 01h
CALL FAR PTR CODE_MEMORY:MemSetW
PUSH DESC_GO32_GDT
MOV EAX, OFFSET DESC_GO32_GDT:D_GDT ; 32bit offset
PUSH AX
PUSH DEF_Null
PUSH (DEF_MAX_DefaultGDT * DEF_SIZE_Descriptor) SHR 01h
CALL FAR PTR CODE_MEMORY:MemSetW
; Setup descriptor & environ
CALL FAR PTR CODE_GO32:SetupIDT
CALL FAR PTR CODE_GO32:SetupGDT
; Set PE
MOV AX, DATA_GO32
MOV DS, AX
MOV AX, SS
MOV WORD PTR DATA_GO32:D_StackFrame[DEF_Far_Segment], AX
MOV WORD PTR DATA_GO32:D_StackFrame[DEF_Far_Offset], SP
MOV EAX, CR0
OR AL, 01h
MOV CR0, EAX ; 보호모드 진입점
MAC_ClearCache ; Code cache를 지우기 위해 그냥 바로 앞에 점프 "jmp $+2"
MAC_JumpFar <0003h * DEF_SIZE_Descriptor>, <OFFSET CODE_GO32:L_GO32_Enter> ; DWORD jump 입니다.
L_GO32_Enter LABEL FAR
MOV AX, 0004h * DEF_SIZE_Descriptor
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
; MOV AX, 000Bh * DEF_SIZE_Descriptor
; MOV SS, AX
; XOR ESP, ESP
XOR EAX, EAX
XOR EBX, EBX
XOR ECX, ECX
XOR EDX, EDX
XOR ESI, ESI
XOR EDI, EDI
XOR EBP, EBP
MAC_JumpFar <0008h * DEF_SIZE_Descriptor>, <OFFSET CODE_KN32:KernelMain32> ; 실제 32비트 동작을 할 32비트 코드가 있는 곳
; Clear PE
L_Exit32 LABEL FAR
MOV EAX, CR0
AND AL, 0FEh
MOV CR0, EAX
MAC_ClearCache
MAC_JumpFar <CODE_GO32>, <OFFSET CODE_GO32:L_GO32_Return> ; Real mode로 돌아옵니다. 하지만 아직은 Real mode의 완전한 반환은 아닙니다.
L_GO32_Return LABEL FAR
; Restore environ
MOV AX, DATA_GO32 ; 여기서 실제로 Real mode를 위한 Segment를 배치하여 줍니다.
MOV DS, AX
XOR AX, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
LSS SP, DWORD PTR DATA_GO32:D_StackFrame
; Print
PUSH DATA_GO32
PUSH OFFSET DATA_GO32:S_MSG_Go32_Return
CALL FAR PTR CODE_TEXT:Puts
POPAD
POP GS
POP FS
POP ES
POP DS
RETF
Go32 ENDP
보호모드로 진입했다가 그냥 나옵니다.
CODE_GO32 ENDS
ASSUME CS:CODE_GO32, DS:DATA_GO32, ES:NOTHING, SS:STACK_DEFAULT
DATA_GO32 SEGMENT
S_MSG_Go32_Enter DB 0FEh, " Enter to 32bit processing."
DB DEF_ASCII_CarrigeReturn, DEF_ASCII_LineFeed
DB DEF_ASCII_EndOfString
S_MSG_Go32_Return DB 0FEh, " Return to 16bit processing."
DB DEF_ASCII_CarrigeReturn, DEF_ASCII_LineFeed
DB DEF_ASCII_EndOfString
D_StackFrame DW DEF_Null, STACK_DEFAULT
D_IDTR STRUC_Descriptor <0000h, 0000h, 00h, 00h, 00h, 00h>
D_GDTR STRUC_Descriptor <0000h, 0000h, 00h, 00h, 00h, 00h>
D_IDT_Item STRUC_Descriptor <0000h, 0000h, 00h, 00h, 00h, 00h>
D_GDT_Item STRUC_Descriptor <0000h, 0000h, 00h, 00h, 00h, 00h>
DATA_GO32 ENDS
ASSUME CS:CODE_GO32, DS:BSS_GO32, ES:NOTHING, SS:STACK_DEFAULT
BSS_GO32 SEGMENT
BSS_GO32 ENDS
ASSUME CS:CODE_GO32, DS:DESC_GO32_IDT, ES:NOTHING, SS:STACK_DEFAULT
DESC_GO32_IDT SEGMENT
D_IDT STRUC_Descriptor DEF_MAX_DefaultIDT DUP (<>)
DESC_GO32_IDT ENDS
ASSUME CS:CODE_GO32, DS:DESC_GO32_GDT, ES:NOTHING, SS:STACK_DEFAULT
DESC_GO32_GDT SEGMENT
D_GDT STRUC_Descriptor DEF_MAX_DefaultGDT DUP (<>)
DESC_GO32_GDT ENDS
END
; End of source
보시는 바와 같이 필요한 Data segment를 기술하였습니다.
http://downloadmirror.intel.com/5720/eng/PROT.HTM
)
page 66,132 .386p stack segment stack use16 dd 100 dup(0) stack ends data segment use16 gdt dd 0 dd 0 code_desc dd 0000ffffh dd 00cf9a00h data_desc dd 0000ffffh dd 00cf9200h ret_desc dd 0000ffffh dd 00cf9a00h gdt_label label fword gdt_limit dw 4*8-1 gdt_base dd ? protected_code_address dd 0 dw 08h data ends code segment para public use16 'code' assume cs:code,ds:data,ss:stack start: mov ax,data mov ds,ax ; setup gdt mov eax,0 mov ax,data shl eax,4 add eax,offset gdt mov gdt_base,eax ; runtime fixup of far jump into pmode mov eax,0 mov ax,code32 shl eax,4 add eax,offset protected_code mov protected_code_address,eax ; runtime fixup for far jump back to rmode mov eax,0 mov ax,code32 mov es,ax mov word ptr es:[4],18h cli db 66h lgdt gdt_label smsw ax or ax,1 lmsw ax jmp next next: jmp fword ptr protected_code_address ret_real: smsw ax and ax,0fffeh lmsw ax jmp far ptr s16 s16: mov ax,4c00h int 21h code ends code32 segment use32 assume cs:code32 sto: jmp far ptr ret_real protected_code: mov ax,10h mov ds,ax mov ebx,0b8000h mov ax,0741h mov ecx,80*25 st1: mov [ebx],ax add ebx,2 loop st1 jmp sto code32 ends end start
https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html
https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html
https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-2a-2b-2c-and-2d-instruction-set-reference-a-z.html
https://en.wikipedia.org/wiki/X86-64
https://en.wikipedia.org/wiki/Protected_mode
https://en.wikipedia.org/wiki/Long_mode
https://en.wikipedia.org/wiki/Control_register