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비트 모드에

시동 거는 일만 남았다.

그리고 코드를 좀더 이쁘게 바꿔야지 의식의 흐름대로 쓴 코드인거 다 티난다.