부트스트랩 코드의 cs 관련 질문
글쓴이: Reper / 작성시간: 월, 2014/07/21 - 9:25오후
%include "init.inc" [org 0] [bits 16] jmp 0x07C0:start start: mov ax, cs mov ds, ax write: mov ax, 0xB800 mov es, ax lea si, [msgBoot] mov di, 0 write_loop: mov al, byte [si] mov byte [es:di], al or al, al jz read inc di mov byte [es:di], 0x07 inc di inc si jmp write_loop read: mov ax, 0x1000 mov es, ax xor bx, bx ; es:bx = 0x1000:0000 mov ah, 2 mov al, 1 mov ch, 0 mov cl, 2 mov dh, 0 mov dl, 0 int 0x13 jc read prepare_pm: cli lgdt[gdtr] mov eax, cr0 or eax, 0x00000001 mov cr0, eax jmp dword CodeSelector:0000 ; Global Descriptor Table (GDT) gdtr: dw gdt_end - gdt - 1 dd 0x7C00 + gdt gdt: dd 0x00000000, 0x00000000 dd 0x0000FFFF, 0x00CF9A01 ; Code Segment Descriptor dd 0x0000FFFF, 0x00CF9201 ; Data Segment Descriptor dd 0x8000FFFF, 0x0040920B ; Video Segment Descriptor gdt_end: msgBoot db "I am in Boot !" , 0 times 510-($-$$) db 0 dw 0xAA55
안녕하세요. 커널 공부를 하고 있는 학생입니다. 지금 16비트 실제 모드에서 32비트 보호 모드로 넘어가는 코드를 작성 중인데요.
위의 코드는 아무 이상 없이 잘 동작 합니다. 그런데 cs에 0x07C0의 값을 넣어주기 귀찮아서,
[org 0]
[bits 16]
jmp 0x07C0:start
start:
...
이 코드를
[org 0x7C00]
[bits 16]
start:
...
이렇게 고쳤는데 무한 재부팅이 됩니다. BIOS가 부트 코드를 메모리의 0x0000:07C0 주소에 적재 하면서 cs에는 0000이 들어가게 되는데,
이 0의 값을 고쳐 주지 않으면 무슨 문제가 있나요 ..? 기계어로 디스어셈블 해봐도 오프셋이나 여러 코드가 정상적으로 작동하기 위한
내용에는 아무 이상이 없어보이는 데요 ... 우선 문제의 요점은, 제 생각엔 cs(code segment) 레지스터의 값인 것 같습니다.
혹시 아시는 분 계시다면, 답변 해주시면 정말 감사하겠습니다.
Forums:
-
참고로 init.inc 에는 단순히 CodeSelector, DataSelector, VideoSelector 가 equ를 통해 GDT의 인덱스 값으로 상수화 되어있습니다.
첨부한 부트로더 코드의 실제 부팅시 적재될 메모리
첨부한 부트로더 코드의 실제 부팅시 적재될 메모리 주소가 0x7c00이기 때문에 정도로 이해하시면 되겠군요.
http://kkamagui.tistory.com/14
아 죄송합니다. 원 질문을 대충 읽었네요. 이미 알고
아 죄송합니다. 원 질문을 대충 읽었네요. 이미 알고 계신 내용이겠네요.
질문내용중에 "BIOS가 부트 코드를 메모리의 0x0000:07C0 주소에 적재 하면서 cs에는 0000이 들어가게 되는데,"
부분이 있는데요, 의도하신대로라면 메모리의 0x07c0:0000 주소에 적대하면서 cs에는 0x07c0 이 들어가야 하지 않을까요.
혹시 org 0x7c0 하신건 아닌지요.
잘 살펴보면 원질문자께서 "BIOS가 부트 코드를
잘 살펴보면 원질문자께서 "BIOS가 부트 코드를 메모리의 0x0000:7C00 주소에 적재 하면서 cs에는 0000이 들어가게 되는데," 라고 적으실려다 오타낸거 같습니다.
0x7c00, 0x07c0:0000, 0x0000:7c00 이 같은 주소니까요.
dd 0x7C00 + gdt 이 부분에 의심이
이 부분에 의심이 갑니다. 말씀하신 상황에서 그냥 dd gdt 해야 하지 않을까요.
org 0에서는 gdt 값이 offset이기 때문에 0x7c00을 더해주었지만, org 0x7c00에서는 gdt값이 온전한 주소값이 되기 때문에 0x7c00을 더해줄 필요가 없어 보입니다.
-
예, 제가 오타를 적었네요; 그런데 [org 0] jmp 0x07C0:start 와 [org 0x7C00]으로 소스를 어셈블러를 통해 기계어로 변환한 후, 디스어셈블 결과를 살펴봤을때 gdt의 위치의 오프셋을 살펴봤는데 아무 이상이 없었습니다. 그래서 이렇게 질문을 드리는 거구요 ...
- 0: ea 05 00 c0 07
실제로는 처음 jmp 0x07c0:start 라인이 없어지기 때문에 쉽게 비교하기 어렵기 때문에,
코드분석을 쉽게 하기 위해서 (잘못된 코드이지만) jmp 0x07c0:start 라인은 그대로 두고, [org 0] 을 [org 0x7c00]으로만 바꾼 코드를 어셈블 후 디스어셈블한 결로를 diff한 것입니다. org 값을 변경했을 때, 코드가 어떻게 해석되는지를 알 수 있을겁니다.
오프셋 0: 은 테스트를 쉽게 하려고 첫 jmp라인을 남긴 것이니 무시하면 됩니다. [org 0x7c05]하고 jmp 0x07c0:start라인을 없앴다고 생각하면 됩니다.
오프셋 0x0e, ox3f의 경우 앞의 것은 CS가 0x07c0이고 뒤에것은 CS가 0x0000인 경우라서 실제 실행에서는 문제가 되지 않습니다.
문제는 오프셋 0x57 부분에 있는데요.
lgdt[gdtr] 할때 gdtr에 있는 값이 다르다는데 문제가 있습니다. 두 경우 모두 gdt의 오프셋(0x5c)은 같은데 말이죠.
실제 실행하였을 경우 메모리에서 gdt의 위치는 0x7c5c = 0x07c0:005c = 0x0000:7c5c 입니다.
따라서 [org 0x7c00]에서는 앞에서 이야기했듯이 gdtr:에서 dd 0x7c00 + gdt를 dd gdt로 바꾸어야 합니다.
이 부분 그대로 두었기 때문에 0x7c00 + 0x7c5c = 0xf85c가 들어가면서 잘못된 gdt 주소값이 들어가게 되는 문제가 생기게 되는 것입니다.
말로할게 하니라 실제로 실행해 보면 알수 있겠죠. 저는 분석만 한 것이기에, 틀릴수도 있습니다만 도움이 되었으면 좋겠습니다.
-
헛.. dd gdt 로 변경하니 정상 작동을 하는군요 ! 제가 보고 있는 서적에 GDTR 레지스터에 GDT의 크기를 명시한 후, GDT의 물리 주소를 채워야 한다고 하길래 순간 오프셋 기준을 생각치 못하고 헤맸군요. 답변 감사드립니다. ㅎㅎ
댓글 달기