32비트 모드로 전환하고, C언어 커널로 들어간게 바로 전인데,
또 부랴부랴 64비트 모드로 넘어갈 준비를 해야한다.
일단 그전에 이전의 출력이 맘에 안들기도 했고 책에서 보여주는 사진도 그렇고
출력을 좀 개선하기로 했다.
이게
이렇게 바뀌였다.
두번째 SUCCESS가 아니라 SICCESS 인거, 수정했다.
다만 스샷찍기 귀찮아서 그냥 기존 이미지 쓰기로 함
이거 하려고 코드좀 많이 넘나들면서 고쳤는데,
일단 16비트 부트로더에서 출력하는 부분인
1~2줄을 위해서 어셈코드를 고쳤다.
일단 이전에 출력 함수를 호출하는 구문은
push HELLO
push 0
push 0
call PRINT
add sp, 6
즉, 색상을 지정하는 코드가 없음.
그래서 고쳤다, 현제 16비트 부트로더에서 출력을 하기위해선 4개의 파라미터가 필요하다.
지금 출력을 하는 코드는
push HELLO
push 0x0B
push 30
push 1
call PRINT
add sp, 8
함수 내부에서도 좀 수정을 가했다.
PRINT:
push bp,
mov bp, sp
push es
push si
push di
push ax
push cx
push dx
mov ax, 0xB800
mov es, ax
mov ax, word[bp + 4]
mov si, 160
mul si
mov di, ax
mov ax, word[bp + 6]
mov si, 2
mul si
add di, ax
mov si, word[bp+10]
mov bl, byte[bp+8]
.PRINTLOOP
mov cl, byte[si]
cmp cl,0
je .ENDPRINTLOOP
mov byte[es:di], cl
mov byte[es:di+1], bl
add si, 1
add di, 2
jmp .PRINTLOOP
길다, 젠장. 다 필요없고 파라미터를 처리하는 구문인 byte[bp + 8] 이런식으로
되어있는 부분중 bl 레지스터에다가 입력한 속성코드를 넣고, 출력할때 지정하는
형식으로 바꾼거다.
그 다음 3번째 줄인 32비트 보호모드 전환성공 메시지 출력을 위해
32비트 코드로 전환하는 엔트리 포인트에서 사용하는 어셈 함수를 고쳤다.
고친 내용은 비슷하다.
push (SUCCESS - $$ + 0x10000)
push 0x0A
push 4
push 60
call PRINT
add esp, 16
대충 속성을 넣는 구문이 추가됬다.
함수 부분도 역시 똑같이 고쳐졌다.
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 bl, byte[ebp + 16]
mov esi, dword[ebp + 20]
.PRINTLOOP:
mov cl, byte[esi]
cmp cl,0
je PRINTEND
mov byte[edi + 0xB8000], cl
mov byte[edi + 0xB8000+1], bl
add esi,1
add edi,2
jmp .PRINTLOOP
똑같이 mov bl, byte[ebp+16] 으로 값을 넣은뒤, 출력구문에서
잘 활용한다.
그러고 나서 C언어로 진입했을때 사용하는 출력 함수인
PrintVideoMemory 함수도 파라미터를 하나 더 추가했다.
구현은 다음과 같다.
void PrintVideoMemory(int x, int y, BYTE Attribute ,const char* _str)
{
CHARACTER_MEMORY* Address = ( CHARACTER_MEMORY* ) 0xB8000;
int i = 0;
Address+= ( y * 80 ) + x;
for ( i = 0; _str[i] != 0; i++)
{
Address[i].bCharactor = _str[i];
Address
[i].bAttribute = Attribute;
}
}
뭐 내 만족을 위해서 책에 나와있지도 않은인지, 아직 안나온건진 모르겠지만
아무튼 바꿧다.
이쁘게 나오니까 기분이 좋다.
그리고, 64비트 커널이 사용할 메모리를 확보하기 위해
메모리 사이즈를 체크하고
그 공간을 0으로 초기화 하는 구문도 넣었다.
BOOL Initalization64KernelMemoryArea()
{
DWORD* Address
= (DWORD*) 0x100000;
while((DWORD) Address
< 0x600000)
{
*Address
= 0x00;
if( *Address
!= 0 )
return FALSE;
Address
++;
}
return TRUE;
}
BOOL CheckMemorySize()
{
DWORD* Address
= (DWORD*) 0x100000;
while( (DWORD) Address
< 0x4000000 )
{
*Address
= 0x12345678;
if( *Address
!= 0x12345678)
return FALSE;
Address
+= (0x100000 / 4);
}
return TRUE;
}
그 내용이다.
이걸 엔트리 함수에서 활용해 체크하고, 메시지를 출력한다.
정상 동작하나 테스트를 위하여
launch_qemu.sh 안의 내용을 좀 고쳐봤다.
기존에 정상 동작하던 옵션은
qemu-system-x86_64 -L . -m 64 -fda disk.img -localtime -M pc
이다.
이렇게 지정하면 vm에게 -m 64 옵션에 의해 64바이트의 메모리를 할당해준다.
이렇게 잘 출력된다.
그럼 VM에게 메모리를 덜 줘보겠다.
qemu-system-x86_64 -L . -m 32 -fda disk.img -localtime -M pc
-m 32 로 메모리를 32MB만 줬다.
오 예스
원하던데로 출력이 잘 된다.
이제 남은건 페이징 키고
여타 자질구래한거 준비해서 64비트 모드에
시동 거는 일만 남았다.
그리고 코드를 좀더 이쁘게 바꿔야지 의식의 흐름대로 쓴 코드인거 다 티난다.