Part13. Tutorial1-프레임워크에 기능을 추가해 보자
원문 : http://kkamagui.springnote.com/pages/353530
들어가기 전에...
- 이 글은 kkamagui에 의해 작성된 글입니다.
- 마음껏 인용하시거나 사용하셔도 됩니다. 단 출처(http://kkamagui.tistory.com, http://kkamagui.springnote.com)는 밝혀 주십시오.
- 기타 사항은 mint64os at gmail.com 이나 http://kkamagui.tistory.com으로 보내주시면 반영하겠습니다.
- 상세한 내용은 책 "64비트 멀티코어 OS 구조와 원리"를 참고하기 바랍니다.
0.시작하면서...
프레임워크를 컴파일-링크해서 이미지를 만든 다음 Virtual Box로 실행하면 까마귀 프레임워크가 시작되었다는 말과 함께 아래에 Edge Task가 돌면서 우측 상단에는 타이머 인터럽트(붉은 색으로 계속 화면에 바뀌어 찍히는 것)가 발생되고 있는 것을 볼 수 있다.
<프레임워크 실행화면>
1.키 입력 및 메시지 출력
자 그럼 이제 프레임워크에 본격적으로 기능을 몇가지 추가해 보자. 일단 아래에서 돌고 있는 태스크는 무시하고 프레임워크 시작 시에 키 입력을 대기하고 키 입력이 되면 커널 쉘 기능과 태스크를 실행하도록 해보자.
일단 키 입력을 받아야 하는데, 참고. 프레임워크 주요 함수들의 새창으로 띄워서 보면 키 입력에 관련된 함수를 볼 수 있다. 잘 살펴보면 kGetCh() 라는 함수가 있는데, 이 함수를 이용하면 키를 얻어올 수 있다. 이를 이용해서 키 입력을 대기하였다가 키가 입력이 되면 그 키 값을 화면에 표시하고 정상적으로 쉘과 태스크를 실행하도록 수정해 보자.
프레임워크 엔트리(void FrameWorkEntry( void )) 함수가 프레임워크에서 처음으로 불리는 함수 이므로 이 부분을 수정하면 된다.
- 파일명 : Custom/Framework.c
- void FrameWorkEntry( void )
{
BYTE bCh; - // 인사말을 찍는다.
kPrintxy( 1, 7, "KKAMAGUI OS FrameWork Start" ); - // 키 입력을 대기하고 키가 입력되면 키 값을 찍는다.
kPrintxy( 10, 8, "Wait For Key Input.... Please Input Anythig...");
bCh = kGetCh();
kPrintxy( 10, 9, "Your Input Is[ ]" );
kPrintchxy( 24, 9, bCh ); - // 간단한 쉘 실행
Shell();
}
위의 파란색 부분을 추가한 뒤, makekernel.bat, makeimg.bat를 차례로 실행시키거나 프레임워크 1.0.3 버전 이상 사용자라면 make를 실행하여 커널 이미지(disk.img)를 생성하자. 그후 Virtual Box에서 이미지를 실행하면 아래와 같이 나타난다.
<키 입력 전>
대기 메시지를 표시하고 키 입력을 기다리고 있는 화면이다. 우측 상단에는 타이머 인터럽트가 계속해서 발생함을 표시하고 있다.
아래는 키 A를 입력한 뒤 화면이다. 입력된 키값(a)이 표시되고 커널 쉘과 태스크가 정상적으로 실행 되었음을 알 수 있다.
<키 입력 후>
2.커널 쉘(Kernel Shell) 기능 추가
커널 쉘 파일은 콘솔을 구현하기위해 약간 복잡하게 되어있는데, 기능을 추가하기 전에 중요한 부분을 먼저 살펴보자.
커널 쉘은 키보드에서 값을 입력받아서 엔터까지를 한 라인으로 보고 라인을 분석하여 명령을 실행하는 구조로 되어있다. 아래 함수는 계속해서 키를 입력받고 엔터가 입력이되면 라인을 분석해서 명령을 실행하는 부분이다.
- /**
Shell을 처리하는 Loop
*/
void ShellLoop( void )
{
BYTE cCh;
int iBufferIndex;
char szCommandBuffer[256]; - // 커서를 설정한다.
kSetCursor( 0, 8 );
iBufferIndex = 0; - // 커맨드 라인을 출력한다.
PrintCommandLine(); - while(1)
{
cCh = kGetCh(); - ProcessKeyCode( cCh, szCommandBuffer, &iBufferIndex);
}
} - /**
키의 입력이 있으면 키 코드를 받아서 처리하는 함수
*/
void ProcessKeyCode( BYTE cCh, char* pcCommandBuffer, int* piBufferIndex )
{
// 엔터나 Back space 같은 경우는 버퍼에 넣지 않고 특별하게 처리한다.
if( ( cCh == KEY_ENTER ) || ( cCh == KEY_BSPACE ) )
{
ProcessSpecialKey( cCh, pcCommandBuffer, piBufferIndex );
return ;
} - // 만약 버퍼가 다 차지 않았으면 화면에 찍고 버퍼에 넣는다.
if( *piBufferIndex < COMMANDBUFFERSIZE )
{
pcCommandBuffer[ *piBufferIndex ] = cCh;
*piBufferIndex = *piBufferIndex + 1;
kPrintf( "%c", cCh );
}
return ;
} - /**
특수키에 대한 처리
*/
void ProcessSpecialKey( BYTE cCh, char* pcCommandBuffer, int* piBufferIndex )
{
int iX;
int iY;
// 만약 리턴이면 스크롤 시켜 본다.
if( cCh == KEY_ENTER )
{
kPrintf( "\n" );
// 버퍼에 든 명령을 실행
ProcessCommand( pcCommandBuffer, piBufferIndex );
*piBufferIndex = 0;
// 커맨드라인을 다시 출력한다.
PrintCommandLine();
}
// 만약 백 스페이스 이면 커서를 하나 지우고 뒤로 민다.
else if( cCh == KEY_BSPACE )
{
kGetCursor( &iX, &iY );
// 버퍼에 데이터가 입력되어 있으면
// 커서의 위치를 하나 감소하고
if( *piBufferIndex > 0 )
{
if( iX == 0 )
{
iX = 79;
iY = iY - 1;
}
else
{
iX = iX - 1;
} - // 문자를 살짝 지워준다.
kPrintchxy( iX, iY, ' ' );
kSetCursor( iX, iY );
*piBufferIndex = *piBufferIndex - 1;
}
}
} - /**
엔터가 쳐졌으면 버퍼의 내용으로 명령어를 처리한다.
*/
void ProcessCommand(char* vcCommandBuffer, int* piBufferIndex)
{
char vcDwordBuffer[ 8 ];
static DWORD vdwValue[ 10 ];
static int iCount = 0; - // 화면 지우는 함수
if( ( *piBufferIndex == 3 ) &&
( kMemCmp( vcCommandBuffer, "cls", 3 ) == 0 ) )
{
kClearScreen();
}
}
위에서 중요한 부분은 파란색으로 굵게 표시를 했다. 파란색 표시를 죽 따라가면 대충 어떻게 동작하는지에 대해서 알 수 있으므로 자세한 설명은 생략하고, 우리가 기능을 추가하려면 어디를 고쳐야 하는지 알아보자. 위에 붉은 색으로 따로 표시된 ProcessCommand()라는 함수가 있다.
이 함수의 아래를 보면 Clear Screen(cls) 명령에 대한 처리가 되어있음을 알 수 있다. 라인에 입력된 키 값이 3개이고 그 값이 "cls" 인가를 비교해서 화면을 지우는 간단한 코드이다. 뭔가 감이오지 않는가? 그렇다. 저 곳에 함수를 추가하면 된다.
자~ 그럼 메모리 총량을 표시하는 "showmem" 이라는 명령을 추가해 보자. 메모리 총량은 참고. 프레임워크 주요 함수들에 보면 kGetTotalRAMSize()라는 함수로 구현되어있다. 이제 명령라인을 추가할 때다.
- /**
엔터가 쳐졌으면 버퍼의 내용으로 명령어를 처리한다.
*/
void ProcessCommand(char* vcCommandBuffer, int* piBufferIndex)
{
char vcDwordBuffer[ 8 ];
static DWORD vdwValue[ 10 ];
static int iCount = 0; - // 화면 지우는 함수
if( ( *piBufferIndex == 3 ) &&
( kMemCmp( vcCommandBuffer, "cls", 3 ) == 0 ) )
{
kClearScreen();
}
// 메모리의 정보를 표시한다.
else if( ( *piBufferIndex == 7 ) &&
( kMemCmp( vcCommandBuffer, "showmem", 7 ) == 0 ) )
{
kPrintf( "%X\n", kGetTotalRAMSize() );
}
}
위와 같이 수정한 뒤에 빌드하여 커널을 실행하면 아래와 같은 화면이 나타난다(아래 화면은 cls 명령으로 화면을 지운뒤, showmem 명령을 실행한 것이다).
<showmem 명령 실행>
Virtual Box에 메모리 설정이 8Mbyte로 되어있어서 00000008 이라는 값이 표시되었다.
3.기타
커널에 기능을 추가하다보면 DWORD의 값을 화면에 출력해야 하는 일이 자주 발생한다. 디버깅 시에도 필수적인 부분인데 kPrintf() 함수를 이용하면 편리하게 할 수 있다.
4.마치면서...
이번에는 프레임워크에 직접적으로 기능을 추가하는 부분에 대해서 알아보았다. 내가 만든 쉘 코드나 프레임워크 시작 부분이 마음에 들지 않으면 위의 코드를 참조하여 얼마든지 수정해도 된다.
다른 새로운 기능 추가는 각자의 몫으로 남겨두고 다음에는 멀티태스킹에 대해서 구현해보도록 하자.
5.첨부
코드 첨부
- Custom/FrameWork.c
- Custom/KShell.c
이 글은 스프링노트에서 작성되었습니다.
이 글은 스프링노트에서 작성되었습니다.
'OS Kernel > 32bit OS Framework' 카테고리의 다른 글
Part15. Tutorial3-동기화(Synchronization) 기능을 추가해 보자 (0) | 2007.11.14 |
---|---|
Part14. Tutorial2-멀티 태스킹(Multi Tasking) 기능을 추가해 보자 (0) | 2007.11.14 |
Part12. 커널(Kernel) 및 프레임워크(Framework) 설명 (11) | 2007.11.14 |
Part11. 커널 로더(Kernel Loader) 설명 (34) | 2007.11.14 |
Part10. 부트 로더(Boot Loader) 설명 (26) | 2007.11.14 |