/** * 콘솔 초기화 */ void kInitializeConsole( int iX, int iY ) { // 콘솔 자료구조 초기화 kMemSet( &gs_stConsoleManager, 0, sizeof( gs_stConsoleManager ) ); // 화면 버퍼 초기화 kMemSet( &gs_vstScreenBuffer, 0, sizeof( gs_vstScreenBuffer ) ); if( kIsGraphicMode() == FALSE ) { // 그래픽 모드로 시작한 것이 아니면 비디오 메모리를 화면 버퍼로 설정 gs_stConsoleManager.pstScreenBuffer = ( CHARACTER* ) CONSOLE_VIDEOMEMORYADDRESS; } else { // 그래픽 모드로 시작했으면 그래픽 모드용 화면 버퍼를 설정 gs_stConsoleManager.pstScreenBuffer = gs_vstScreenBuffer; // 그래픽 모드에서 사용할 키 큐와 뮤텍스를 초기화 kInitializeQueue( &( gs_stConsoleManager.stKeyQueueForGUI ), gs_vstKeyQueueBuffer, CONSOLE_GUIKEYQUEUE_MAXCOUNT, sizeof( KEYDATA ) ); kInitializeMutex( &( gs_stConsoleManager.stLock ) ); } // 커서 위치 설정 kSetCursor( iX, iY ); }
/** * 파라미터를 이용해서 TCB를 설정 */ void kSetUpTask( TCB* pstTCB, QWORD qwID, QWORD qwFlags, QWORD qwEntryPointAddress, void* pvStackAddress, QWORD qwStackSize ) { // 콘텍스트 초기화 kMemSet( pstTCB->stContext.vqRegister, 0, sizeof( pstTCB->stContext.vqRegister ) ); // 스택에 관련된 RSP, RBP 레지스터 설정 pstTCB->stContext.vqRegister[ TASK_RSPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize; pstTCB->stContext.vqRegister[ TASK_RBPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize; // 세그먼트 셀렉터 설정 pstTCB->stContext.vqRegister[ TASK_CSOFFSET ] = GDT_KERNELCODESEGMENT; pstTCB->stContext.vqRegister[ TASK_DSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_ESOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_FSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_GSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_SSOFFSET ] = GDT_KERNELDATASEGMENT; // RIP 레지스터와 인터럽트 플래그 설정 pstTCB->stContext.vqRegister[ TASK_RIPOFFSET ] = qwEntryPointAddress; // RFLAGS 레지스터의 IF 비트(비트 9)를 1로 설정하여 인터럽트 활성화 pstTCB->stContext.vqRegister[ TASK_RFLAGSOFFSET ] |= 0x0200; // ID 및 스택, 그리고 플래그 저장 pstTCB->qwID = qwID; pstTCB->pvStackAddress = pvStackAddress; pstTCB->qwStackSize = qwStackSize; pstTCB->qwFlags = qwFlags; }
/** * TSS 세그먼트의 정보를 초기화 */ void kInitializeTSSSegment( TSSSEGMENT* pstTSS ) { kMemSet( pstTSS, 0, sizeof( TSSSEGMENT ) ); pstTSS->qwIST[ 0 ] = IST_STARTADDRESS + IST_SIZE; // IO 를 TSS의 limit 값보다 크게 설정함으로써 IO Map을 사용하지 않도록 함 pstTSS->wIOMapBaseAddress = 0xFFFF; }
/** * 파라미터를 이용해서 TCB를 설정 */ static void kSetUpTask( TCB* pstTCB, QWORD qwFlags, QWORD qwEntryPointAddress, void* pvStackAddress, QWORD qwStackSize ) { // 콘텍스트 초기화 kMemSet( pstTCB->stContext.vqRegister, 0, sizeof( pstTCB->stContext.vqRegister ) ); // 스택에 관련된 RSP, RBP 레지스터 설정 pstTCB->stContext.vqRegister[ TASK_RSPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize - 8; pstTCB->stContext.vqRegister[ TASK_RBPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize - 8; // Return Address 영역에 kExitTask() 함수의 어드레스를 삽입하여 태스크의 엔트리 // 포인트 함수를 빠져나감과 동시에 kExitTask() 함수로 이동하도록 함 *( QWORD * ) ( ( QWORD ) pvStackAddress + qwStackSize - 8 ) = ( QWORD ) kExitTask; // 세그먼트 셀렉터 설정 pstTCB->stContext.vqRegister[ TASK_CSOFFSET ] = GDT_KERNELCODESEGMENT; pstTCB->stContext.vqRegister[ TASK_DSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_ESOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_FSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_GSOFFSET ] = GDT_KERNELDATASEGMENT; pstTCB->stContext.vqRegister[ TASK_SSOFFSET ] = GDT_KERNELDATASEGMENT; // RIP 레지스터와 인터럽트 플래그 설정 pstTCB->stContext.vqRegister[ TASK_RIPOFFSET ] = qwEntryPointAddress; // RFLAGS 레지스터의 IF 비트(비트 9)를 1로 설정하여 인터럽트 활성화 pstTCB->stContext.vqRegister[ TASK_RFLAGSOFFSET ] |= 0x0200; // 스택과 플래그 저장 pstTCB->pvStackAddress = pvStackAddress; pstTCB->qwStackSize = qwStackSize; pstTCB->qwFlags = qwFlags; }
/** * 파일 시스템을 초기화 */ BOOL kInitializeFileSystem( void ) { // 자료구조 초기화와 동기화 객체 초기화 kMemSet( &gs_stFileSystemManager, 0, sizeof( gs_stFileSystemManager ) ); kInitializeMutex( &( gs_stFileSystemManager.stMutex ) ); // 하드 디스크를 초기화 if( kInitializeHDD() == TRUE ) { // 초기화가 성공하면 함수 포인터를 하드 디스크용 함수로 설정 gs_pfReadHDDInformation = kReadHDDInformation; gs_pfReadHDDSector = kReadHDDSector; gs_pfWriteHDDSector = kWriteHDDSector; } else { return FALSE; } // 파일 시스템 연결 if( kMount() == FALSE ) { return FALSE; } return TRUE; }
// 사용한 핸들을 반환 static void kFreeFileDirectoryHandle(FILE* pstFile) { // 전체 영역을 초기화 kMemSet(pstFile,0,sizeof(FILE)); // 비어 있는 타입으로 설정 pstFile->bType = FILESYSTEM_TYPE_FREE; }
/** * 콘솔 초기화 */ void kInitializeConsole( int iX, int iY ) { // 자료구조를 모두 0으로 초기화 kMemSet( &gs_stConsoleManager, 0, sizeof( gs_stConsoleManager ) ); // 커서 위치 설정 kSetCursor( iX, iY ); }
// 파일을 삭제 int kRemoveFile(const char* pcFileName) { DIRECTORYENTRY stEntry; int iDirectoryEntryOffset; int iFileNameLength; // 파일 이름 검사 iFileNameLength = kStrLen(pcFileName); if((iFileNameLength>(sizeof(stEntry.vcFileName)-1))||(iFileNameLength==0)) { return NULL; } // 동기화 kLock(&(gs_stFileSystemManager.stMutex)); // 파일이 존재하는지 확인 iDirectoryEntryOffset = kFindDirectoryEntry(pcFileName,&stEntry); if(iDirectoryEntryOffset==-1) { // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); return -1; } // 다른 태스크에서 해당 파일을 열고 있는지 핸들 풀을 검색하여 확인 파일이 열려 있으면 삭제할 수 없음 if(kIsFileOpened(&stEntry)==TRUE) { // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); return -1; } // 파일을 구성하는 클러스터를 모두 해제 if(kFreeClusterUtilEnd(stEntry.dwStartClusterIndex)==FALSE) { // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); return -1; } // 디렉터리 엔트리를 빈 것으로 설정 kMemSet(&stEntry,0,sizeof(stEntry)); if(kSetDirectoryEntryData(iDirectoryEntryOffset,&stEntry)==FALSE) { // 동긱화 kUnlock(&(gs_stFileSystemManager.stMutex)); return -1; } // 동기화 kUnlock(&(gs_stFileSystemManager.stMutex)); return 0; }
/** * 태스크 풀 초기화 */ static void kInitializeTCBPool( void ) { int i; kMemSet( &( gs_stTCBPoolManager ), 0, sizeof( gs_stTCBPoolManager ) ); // 태스크 풀의 어드레스를 지정하고 초기화 gs_stTCBPoolManager.pstStartAddress = ( TCB* ) TASK_TCBPOOLADDRESS; kMemSet( TASK_TCBPOOLADDRESS, 0, sizeof( TCB ) * TASK_MAXCOUNT ); // TCB에 ID 할당 for( i = 0 ; i < TASK_MAXCOUNT ; i++ ) { gs_stTCBPoolManager.pstStartAddress[ i ].stLink.qwID = i; } // TCB의 최대 개수와 할당된 횟수를 초기화 gs_stTCBPoolManager.iMaxCount = TASK_MAXCOUNT; gs_stTCBPoolManager.iAllocatedCount = 1; }
/** * TCB를 해제함 */ static void kFreeTCB( QWORD qwID ) { int i; // 태스크 ID의 하위 32비트가 인덱스 역할을 함 i = GETTCBOFFSET( qwID ); // TCB를 초기화하고 ID 설정 kMemSet( &( gs_stTCBPoolManager.pstStartAddress[ i ].stContext ), 0, sizeof( CONTEXT ) ); gs_stTCBPoolManager.pstStartAddress[ i ].stLink.qwID = i; gs_stTCBPoolManager.iUseCount--; }
/** * 램 디스크의 정보를 반환 */ BOOL kReadRDDInformation( BOOL bPrimary, BOOL bMaster, HDDINFORMATION* pstHDDInformation ) { // 자료구조 초기화 kMemSet( pstHDDInformation, 0, sizeof( HDDINFORMATION ) ); // 총 섹터 수와 시리얼 번호, 그리고 모델 번호만 설정 pstHDDInformation->dwTotalSectors = gs_stRDDManager.dwTotalSectorCount; kMemCpy( pstHDDInformation->vwSerialNumber, "0000-0000", 9 ); kMemCpy( pstHDDInformation->vwModelNumber, "MINT RAM Disk v1.0", 18 ); return TRUE; }
/** * 파라미터를 이용해서 TCB를 설정 */ static void kSetUpTask( TCB* pstTCB, QWORD qwFlags, QWORD qwEntryPointAddress, void* pvStackAddress, QWORD qwStackSize ) { // 콘텍스트 초기화 kMemSet( pstTCB->stContext.vqRegister, 0, sizeof( pstTCB->stContext.vqRegister ) ); // 스택에 관련된 RSP, RBP 레지스터 설정 pstTCB->stContext.vqRegister[ TASK_RSPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize - 8; pstTCB->stContext.vqRegister[ TASK_RBPOFFSET ] = ( QWORD ) pvStackAddress + qwStackSize - 8; // Return Address 영역에 kExitTask() 함수의 어드레스를 삽입하여 태스크의 엔트리 // 포인트 함수를 빠져나감과 동시에 kExitTask() 함수로 이동하도록 함 *( QWORD * ) ( ( QWORD ) pvStackAddress + qwStackSize - 8 ) = ( QWORD ) kExitTask; // 세그먼트 셀렉터 설정 // 커널 태스크인 경우는 커널 레벨 세그먼트 디스크립터를 설정 if( ( qwFlags & TASK_FLAGS_USERLEVEL ) == 0 ) { pstTCB->stContext.vqRegister[ TASK_CSOFFSET ] = GDT_KERNELCODESEGMENT | SELECTOR_RPL_0; pstTCB->stContext.vqRegister[ TASK_DSOFFSET ] = GDT_KERNELDATASEGMENT | SELECTOR_RPL_0; pstTCB->stContext.vqRegister[ TASK_ESOFFSET ] = GDT_KERNELDATASEGMENT | SELECTOR_RPL_0; pstTCB->stContext.vqRegister[ TASK_FSOFFSET ] = GDT_KERNELDATASEGMENT | SELECTOR_RPL_0; pstTCB->stContext.vqRegister[ TASK_GSOFFSET ] = GDT_KERNELDATASEGMENT | SELECTOR_RPL_0; pstTCB->stContext.vqRegister[ TASK_SSOFFSET ] = GDT_KERNELDATASEGMENT | SELECTOR_RPL_0; } // 유저 태스크인 경우는 유저 레벨 세그먼트 디스크립터를 설정 else { pstTCB->stContext.vqRegister[ TASK_CSOFFSET ] = GDT_USERCODESEGMENT | SELECTOR_RPL_3; pstTCB->stContext.vqRegister[ TASK_DSOFFSET ] = GDT_USERDATASEGMENT | SELECTOR_RPL_3; pstTCB->stContext.vqRegister[ TASK_ESOFFSET ] = GDT_USERDATASEGMENT | SELECTOR_RPL_3; pstTCB->stContext.vqRegister[ TASK_FSOFFSET ] = GDT_USERDATASEGMENT | SELECTOR_RPL_3; pstTCB->stContext.vqRegister[ TASK_GSOFFSET ] = GDT_USERDATASEGMENT | SELECTOR_RPL_3; pstTCB->stContext.vqRegister[ TASK_SSOFFSET ] = GDT_USERDATASEGMENT | SELECTOR_RPL_3; } // RIP 레지스터와 인터럽트 플래그 설정 pstTCB->stContext.vqRegister[ TASK_RIPOFFSET ] = qwEntryPointAddress; // RFLAGS 레지스터의 IF 비트(비트 9)를 1로 설정하여 인터럽트 활성화하고 // IOPL 비트(비트 12~13)를 3으로 설정하여 유저 레벨에서도 I/O 포트에 접근할 수 있도록 함 pstTCB->stContext.vqRegister[ TASK_RFLAGSOFFSET ] |= 0x3200; // 스택과 플래그 저장 pstTCB->pvStackAddress = pvStackAddress; pstTCB->qwStackSize = qwStackSize; pstTCB->qwFlags = qwFlags; }
/** * 램 디스크 디바이스 드라이버 초기화 함수 */ BOOL kInitializeRDD( DWORD dwTotalSectorCount ) { // 자료구조 초기화 kMemSet( &gs_stRDDManager, 0, sizeof( gs_stRDDManager ) ); // 램 디스크로 사용할 메모리를 할당 gs_stRDDManager.pbBuffer = ( BYTE* ) kAllocateMemory( dwTotalSectorCount * 512 ); if( gs_stRDDManager.pbBuffer == NULL ) { return FALSE; } // 총 섹터 수와 동기화 객체를 설정 gs_stRDDManager.dwTotalSectorCount = dwTotalSectorCount; kInitializeMutex( &( gs_stRDDManager.stMutex ) ); return TRUE; }
/** * TSS 세그먼트의 정보를 초기화 */ void kInitializeTSSSegment( TSSSEGMENT* pstTSS ) { int i; // 최대 프로세서 또는 코어의 수만큼 루프를 돌면서 생성 for( i = 0 ; i < MAXPROCESSORCOUNT ; i++ ) { // 0으로 초기화 kMemSet( pstTSS, 0, sizeof( TSSSEGMENT ) ); // IST의 뒤에서부터 잘라서 할당함. (주의, IST는 16바이트 단위로 정렬해야 함) pstTSS->qwIST[ 0 ] = IST_STARTADDRESS + IST_SIZE - ( IST_SIZE / MAXPROCESSORCOUNT * i ); // IO Map의 기준 주소를 TSS 디스크립터의 Limit 필드보다 크게 설정함으로써 // IO Map을 사용하지 않도록 함 pstTSS->wIOMapBaseAddress = 0xFFFF; // 다음 엔트리로 이동 pstTSS++; } }
// 파일을 Count만큼 0으로 채움 BOOL kWriteZero(FILE* pstFile,DWORD dwCount) { BYTE* pbBuffer; DWORD dwRemainCount; DWORD dwWriteCount; // 핸들이 NULL이면 실패 if(pstFile==NULL) { return FALSE; } // 속도 향상을 위해 메모리를 할당받아 클러스터 단위로 쓰기 수행 메모리를 할당 pbBuffer = (BYTE*)kAllocateMemory(FILESYSTEM_CLUSTERSIZE); if(pbBuffer==NULL) { return FALSE; } // 0으로 채움 kMemSet(pbBuffer,0,FILESYSTEM_CLUSTERSIZE); dwRemainCount = dwCount; // 클러스터 단위로 반복해서 쓰기 수행 while(dwRemainCount!=0) { dwWriteCount = MIN(dwRemainCount,FILESYSTEM_CLUSTERSIZE); if(kWriteFile(pbBuffer,1,dwWriteCount,pstFile)!=dwWriteCount) { kFreeMemory(pbBuffer); return FALSE; } dwRemainCount ==dwWriteCount; } kFreeMemory(pbBuffer); return TRUE; }
// 파일 시스템을 초기화 BOOL kInitializeFileSystem(void) { BOOL bCacheEnable = FALSE; // 자료구조 초기화와 동기화 객체 초기화 kMemSet(&gs_stFileSystemManager,0,sizeof(gs_stFileSystemManager)); kInitializeMutex(&(gs_stFileSystemManager.stMutex)); /* // 하드 디스크를 초기화 if(kInitializeHDD()==TRUE) { // 초기화가 성공하면 함수 포인터를 하드 디스크용 함수로 설정 gs_pfReadHDDInformation = kReadHDDInformation; gs_pfReadHDDSector = kReadHDDSector; gs_pfWriteHDDSector = kWriteHDDSector; // 캐시를 활성화함 bCacheEnable = TRUE; } else*/ if(kInitializeRDD(RDD_TOTALSECTORCOUNT)==TRUE) { // 초기화가 성공하면 함수 포인터를 램디스크요여 함수로 설정 gs_pfReadHDDInformation = kReadRDDInformation; gs_pfReadHDDSector = kReadRDDSector; gs_pfWriteHDDSector = kWriteRDDSector; // 램 디스크는 데이터가 남아 있지 않으므로 매번 파일 시스템을 생성함 if(kFormat() == FALSE) { return FALSE; } } else { return FALSE; } // 파일 시스템 연결 if(kMount()==FALSE) { return FALSE; } // 핸들을 위한 공간을 할당 gs_stFileSystemManager.pstHandlePool = (FILE*) kAllocateMemory(FILESYSTEM_HANDLE_MAXCOUNT*sizeof(FILE)); // 메모리 할당이 실패하면 하드 디스크가 인식되지 않은 것으로 설정 if(gs_stFileSystemManager.pstHandlePool == NULL) { gs_stFileSystemManager.bMounted = FALSE; return FALSE; } // 핸들 풀을 모두 0으로 설정하여 초기화 kMemSet(gs_stFileSystemManager.pstHandlePool,0,FILESYSTEM_HANDLE_MAXCOUNT*sizeof(FILE)); if(bCacheEnable==TRUE) { gs_stFileSystemManager.bCacheEnable=kInitializeCacheManager(); } return TRUE; }
// 하드 디스크에 파일 시스템을 생성 BOOL kFormat(void) { HDDINFORMATION* pstHDD; MBR* pstMBR; DWORD dwTotalSectorCount,dwRemainSectorCount; DWORD dwMaxClusterCount,dwClusterCount; DWORD dwClusterLinkSectorCount; DWORD i; // 동기화 처리 kLock(&(gs_stFileSystemManager.stMutex)); //========================================================================================= // 하드 디스크 정보를 읽어서 메타 영역의 크기와 클러스터의 개수를 계산 //========================================================================================= // 하드 디스크의 정보를 얻어서 하드 디스크의 총 섹터 수를 구함 pstHDD = (HDDINFORMATION*)gs_vbTempBuffer; if(gs_pfReadHDDInformation(TRUE,TRUE,pstHDD)==FALSE) { // 동기화 처리 kUnlock(&(gs_stFileSystemManager.stMutex)); return FALSE; } dwTotalSectorCount = pstHDD->dwTotalSectors; // 전체 섹터 수를 4KB, 즉 클러스터 크기로 나누어 최대 클러스터 수를 계산 dwMaxClusterCount = dwTotalSectorCount / FILESYSTEM_SECTORPERCLUSTER; // 최대 클러스터의 수에 맞춰 클러스터 링크 테이블의 섹터 수를 계산 // 링크 데이터는 4바이트이므로, 한 섹터에는 128개가 들어감. 따라서 총 개수를 // 128로 나눈 후 올림하여 클러스터 링크의 섹터 수를 구함 dwClusterLinkSectorCount = (dwMaxClusterCount+127)/128; // 예약된 영역은 현재 사용하지 않으므로, 디스크 전체 영역에서 MBR 영역과 클러스터 // 링크 테이블 영역의 크기를 뺀 나머지가 실제 데이터 영역이 됨 // 해당 영역을 클러스터 크기로 나누어 실제 클러스터의 개수를 구함 dwRemainSectorCount = dwTotalSectorCount - dwClusterLinkSectorCount -1; dwClusterCount = dwRemainSectorCount/FILESYSTEM_SECTORPERCLUSTER; // 실제 사용 가능한 클러스터 수에 맞춰 다시 한 번 계산 dwClusterLinkSectorCount = (dwClusterCount+127)/128; //========================================================================================= // 계산된 정보를 MBR에 덮어 쓰고, 루트 디렉터리 영역까지 모두 0으로 초기화하여 // 파일 시스템을 생성 //========================================================================================= // MBR 영역 읽기 if(gs_pfReadHDDSector(TRUE,TRUE,0,1,gs_vbTempBuffer)==FALSE) { // 동기화 처리 kUnlock(&(gs_stFileSystemManager.stMutex)); return FALSE; } // 파티션 정보와 파일 시스템 정보 설정 pstMBR = (MBR*)gs_vbTempBuffer; kMemSet(pstMBR->vstPartiton,0,sizeof(pstMBR->vstPartiton)); pstMBR->dwSignature = FILESYSTEM_SIGNATUR; pstMBR->dwReservedSectorCount = 0; pstMBR->dwClusterLinkSectorCount = dwClusterLinkSectorCount; pstMBR->dwTotalClusterCount = dwClusterCount; // MBR 영역에 1 섹터를 씀 if(gs_pfWriteHDDSector(TRUE,TRUE,0,1,gs_vbTempBuffer)==FALSE) { // 동기화 처리 kUnlock(&(gs_stFileSystemManager.stMutex)); return FALSE; } // MBR 이후부터 루트 디렉터리까지 모두 0으로 초기화 kMemSet(gs_vbTempBuffer,0,512); for(i=0;i<(dwClusterLinkSectorCount+FILESYSTEM_SECTORPERCLUSTER);i++) { // 루트 디렉터리(클러스터 0)는 이미 파일 시스템이 사용하고 있으므로, 할당된 것으로 표시 if(i==0) { ((DWORD*)(gs_vbTempBuffer))[0]=FILESYSTEM_LASTCLUSTER; } else { ((DWORD*)(gs_vbTempBuffer))[0]=FILESYSTEM_FREECLUSTER; } // 1섹터씩 씀 if(gs_pfWriteHDDSector(TRUE,TRUE,i+1,1,gs_vbTempBuffer)==FALSE) { // 동기화 처리 kUnlock(&(gs_stFileSystemManager.stMutex)); return FALSE; } } // 캐시 버퍼를 모두 버림 if(gs_stFileSystemManager.bCacheEnable==TRUE) { kDiscardAllCacheBuffer(CACHE_CLUSTERLINKTABLEAREA); kDiscardAllCacheBuffer(CACHE_DATAAREA); } // 동기화 처리 kUnlock(&(gs_stFileSystemManager.stMutex)); return TRUE; }
/** * 파일 시스템 캐시를 초기화 */ BOOL kInitializeCacheManager( void ) { int i; // 자료구조 초기화 kMemSet( &gs_stCacheManager, 0, sizeof( gs_stCacheManager ) ); // 접근 시간 초기화 gs_stCacheManager.vdwAccessTime[ CACHE_CLUSTERLINKTABLEAREA ] = 0; gs_stCacheManager.vdwAccessTime[ CACHE_DATAAREA ] = 0; // 캐시 버퍼의 최댓값 설정 gs_stCacheManager.vdwMaxCount[ CACHE_CLUSTERLINKTABLEAREA ] = CACHE_MAXCLUSTERLINKTABLEAREACOUNT; gs_stCacheManager.vdwMaxCount[ CACHE_DATAAREA ] = CACHE_MAXDATAAREACOUNT; // 클러스터 링크 테이블 영역용 메모리 할당, 클러스터 링크 테이블은 512바이트로 관리함 gs_stCacheManager.vpbBuffer[ CACHE_CLUSTERLINKTABLEAREA ] = ( BYTE* ) kAllocateMemory( CACHE_MAXCLUSTERLINKTABLEAREACOUNT * 512 ); if( gs_stCacheManager.vpbBuffer[ CACHE_CLUSTERLINKTABLEAREA ] == NULL ) { return FALSE; } // 할당 받은 메모리 영역을 나누어서 캐시 버퍼에 등록 for( i = 0 ; i < CACHE_MAXCLUSTERLINKTABLEAREACOUNT ; i++ ) { // 캐시 버퍼에 메모리 공간 할당 gs_stCacheManager.vvstCacheBuffer[ CACHE_CLUSTERLINKTABLEAREA ][ i ]. pbBuffer = gs_stCacheManager.vpbBuffer[ CACHE_CLUSTERLINKTABLEAREA ] + ( i * 512 ); // 태그를 유효하지 않은 것으로 설정하여 빈 것으로 만듦 gs_stCacheManager.vvstCacheBuffer[ CACHE_CLUSTERLINKTABLEAREA ][ i ]. dwTag = CACHE_INVALIDTAG; } // 데이터 영역용 메모리 할당, 데이터 영역은 클러스터 단위(4 Kbyte)로 관리함 gs_stCacheManager.vpbBuffer[ CACHE_DATAAREA ] = ( BYTE* ) kAllocateMemory( CACHE_MAXDATAAREACOUNT * FILESYSTEM_CLUSTERSIZE ); if( gs_stCacheManager.vpbBuffer[ CACHE_DATAAREA ] == NULL ) { // 실패하면 이전에 할당 받은 메모리를 해제해야 함 kFreeMemory( gs_stCacheManager.vpbBuffer[ CACHE_CLUSTERLINKTABLEAREA ] ); return FALSE; } // 할당 받은 메모리 영역을 나누어서 캐시 버퍼에 등록 for( i = 0 ; i < CACHE_MAXDATAAREACOUNT ; i++ ) { // 캐시 버퍼에 메모리 공간 할당 gs_stCacheManager.vvstCacheBuffer[ CACHE_DATAAREA ][ i ].pbBuffer = gs_stCacheManager.vpbBuffer[ CACHE_DATAAREA ] + ( i * FILESYSTEM_CLUSTERSIZE ); // 태그를 유효하지 않은 것으로 설정하여 빈 것으로 만듦 gs_stCacheManager.vvstCacheBuffer[ CACHE_DATAAREA ][ i ].dwTag = CACHE_INVALIDTAG; } return TRUE; }
//============================================================================= // Code for shell //============================================================================= // Main loop void kStartConsoleShell( void ) { char vcCommandBuffer[CONSOLESHELL_MAXCOMMANDBUFFERCOUNT]; int iCommandBufferIndex = 0; BYTE bKey; int iCursorX, iCursorY; // Print prompt kPrintf( CONSOLESHELL_PROMPTMESSAGE ); while( 1 ) { // Wait for key bKey = kGetCh(); // If backspace if ( bKey == KEY_BACKSPACE ) { if ( iCommandBufferIndex > 0 ) { // Get current cursor point, move back on point // print white space, // delete last character in command buffer kGetCursor( &iCursorX, &iCursorY ); kPrintStringXY( iCursorX - 1, iCursorY, " " ); kSetCursor( iCursorX - 1, iCursorY ); iCommandBufferIndex--; } } // Process enter key else if ( bKey == KEY_ENTER ) { kPrintf( "\n" ); if ( iCommandBufferIndex > 0 ) { // Execute command in buffer vcCommandBuffer[iCommandBufferIndex] = '\0'; kExecuteCommand( vcCommandBuffer ); } // Print prompt and Initialize command buffer kPrintf( "%s", CONSOLESHELL_PROMPTMESSAGE ); kMemSet( vcCommandBuffer, '\0', CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ); iCommandBufferIndex = 0; } // Ignore Shift key, Caps lock, Num lock, Scroll lock else if ( ( bKey == KEY_LSHIFT ) || ( bKey == KEY_RSHIFT ) || ( bKey == KEY_CAPSLOCK ) || ( bKey == KEY_NUMLOCK ) || ( bKey == KEY_SCROLLLOCK ) ) { ; } else { // Switch TAB to white space if ( bKey == KEY_TAB ) { bKey = ' '; } // If buffer have room if ( iCommandBufferIndex < CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ) { vcCommandBuffer[iCommandBufferIndex++] = bKey; kPrintf( "%c", bKey ); } } } }
/** * 현재 생성된 모든 태스크의 정보를 출력 */ static void kShowTaskList( const char* pcParameterBuffer ) { int i; TCB* pstTCB; int iCount = 0; int iTotalTaskCount = 0; char vcBuffer[ 20 ]; int iRemainLength; int iProcessorCount; // 코어 수만큼 루프를 돌면서 각 스케줄러에 있는 태스크의 수를 더함 iProcessorCount = kGetProcessorCount(); for( i = 0 ; i < iProcessorCount ; i++ ) { iTotalTaskCount += kGetTaskCount( i ); } kPrintf( "================= Task Total Count [%d] =================\n", iTotalTaskCount ); // 코어가 2개 이상이면 각 스케줄러 별로 개수를 출력 if( iProcessorCount > 1 ) { // 각 스케줄러 별로 태스크의 개수를 출력 for( i = 0 ; i < iProcessorCount ; i++ ) { if( ( i != 0 ) && ( ( i % 4 ) == 0 ) ) { kPrintf( "\n" ); } kSPrintf( vcBuffer, "Core %d : %d", i, kGetTaskCount( i ) ); kPrintf( vcBuffer ); // 출력하고 남은 공간을 모두 스페이스바로 채움 iRemainLength = 19 - kStrLen( vcBuffer ); kMemSet( vcBuffer, ' ', iRemainLength ); vcBuffer[ iRemainLength ] = '\0'; kPrintf( vcBuffer ); } kPrintf( "\nPress any key to continue... ('q' is exit) : " ); if( kGetCh() == 'q' ) { kPrintf( "\n" ); return ; } kPrintf( "\n\n" ); } for( i = 0 ; i < TASK_MAXCOUNT ; i++ ) { // TCB를 구해서 TCB가 사용 중이면 ID를 출력 pstTCB = kGetTCBInTCBPool( i ); if( ( pstTCB->stLink.qwID >> 32 ) != 0 ) { // 태스크가 6개 출력될 때마다, 계속 태스크 정보를 표시할지 여부를 확인 if( ( iCount != 0 ) && ( ( iCount % 6 ) == 0 ) ) { kPrintf( "Press any key to continue... ('q' is exit) : " ); if( kGetCh() == 'q' ) { kPrintf( "\n" ); break; } kPrintf( "\n" ); } kPrintf( "[%d] Task ID[0x%Q], Priority[%d], Flags[0x%Q], Thread[%d]\n", 1 + iCount++, pstTCB->stLink.qwID, GETPRIORITY( pstTCB->qwFlags ), pstTCB->qwFlags, kGetListCount( &( pstTCB->stChildThreadList ) ) ); kPrintf( " Core ID[0x%X] CPU Affinity[0x%X]\n", pstTCB->bAPICID, pstTCB->bAffinity ); kPrintf( " Parent PID[0x%Q], Memory Address[0x%Q], Size[0x%Q]\n", pstTCB->qwParentProcessID, pstTCB->pvMemoryAddress, pstTCB->qwMemorySize ); } } }
/** * 셸의 메인 루프 */ void kStartConsoleShell( void ) { char vcCommandBuffer[ CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ]; int iCommandBufferIndex = 0; BYTE bKey; int iCursorX, iCursorY; // 프롬프트 출력 kPrintf( CONSOLESHELL_PROMPTMESSAGE ); while( 1 ) { // 키가 수신될 때까지 대기 bKey = kGetCh(); // Backspace 키 처리 if( bKey == KEY_BACKSPACE ) { if( iCommandBufferIndex > 0 ) { // 현재 커서 위치를 얻어서 한 문자 앞으로 이동한 다음 공백을 출력하고 // 커맨드 버퍼에서 마지막 문자 삭제 kGetCursor( &iCursorX, &iCursorY ); kPrintStringXY( iCursorX - 1, iCursorY, " " ); kSetCursor( iCursorX - 1, iCursorY ); iCommandBufferIndex--; } } // 엔터 키 처리 else if( bKey == KEY_ENTER ) { kPrintf( "\n" ); if( iCommandBufferIndex > 0 ) { // 커맨드 버퍼에 있는 명령을 실행 vcCommandBuffer[ iCommandBufferIndex ] = '\0'; kExecuteCommand( vcCommandBuffer ); } // 프롬프트 출력 및 커맨드 버퍼 초기화 kPrintf( "%s", CONSOLESHELL_PROMPTMESSAGE ); kMemSet( vcCommandBuffer, '\0', CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ); iCommandBufferIndex = 0; } // 시프트 키, CAPS Lock, NUM Lock, Scroll Lock은 무시 else if( ( bKey == KEY_LSHIFT ) || ( bKey == KEY_RSHIFT ) || ( bKey == KEY_CAPSLOCK ) || ( bKey == KEY_NUMLOCK ) || ( bKey == KEY_SCROLLLOCK ) ) { ; } else { // TAB은 공백으로 전환 if( bKey == KEY_TAB ) { bKey = ' '; } // 버퍼에 공간이 남아있을 때만 가능 if( iCommandBufferIndex < CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ) { vcCommandBuffer[ iCommandBufferIndex++ ] = bKey; kPrintf( "%c", bKey ); } } } }
/** * MP 설정 테이블을 분석해서 필요한 정보를 저장하는 함수 */ BOOL kAnalysisMPConfigurationTable( void ) { QWORD qwMPFloatingPointerAddress; MPFLOATINGPOINTER* pstMPFloatingPointer; MPCONFIGURATIONTABLEHEADER* pstMPConfigurationHeader; BYTE bEntryType; WORD i; QWORD qwEntryAddress; PROCESSORENTRY* pstProcessorEntry; BUSENTRY* pstBusEntry; // 자료구조 초기화 kMemSet( &gs_stMPConfigurationManager, 0, sizeof( MPCONFIGRUATIONMANAGER ) ); gs_stMPConfigurationManager.bISABusID = 0xFF; // MP 플로팅 포인터의 어드레스를 구함 if( kFindMPFloatingPointerAddress( &qwMPFloatingPointerAddress ) == FALSE ) { return FALSE; } // MP 플로팅 테이블 설정 pstMPFloatingPointer = ( MPFLOATINGPOINTER* ) qwMPFloatingPointerAddress; gs_stMPConfigurationManager.pstMPFloatingPointer = pstMPFloatingPointer; pstMPConfigurationHeader = ( MPCONFIGURATIONTABLEHEADER* ) ( ( QWORD ) pstMPFloatingPointer->dwMPConfigurationTableAddress & 0xFFFFFFFF ); // PIC 모드 지원 여부 저장 if( pstMPFloatingPointer->vbMPFeatureByte[ 1 ] & MP_FLOATINGPOINTER_FEATUREBYTE2_PICMODE ) { gs_stMPConfigurationManager.bUsePICMode = TRUE; } // MP 설정 테이블 헤더와 기본 MP 설정 테이블 엔트리의 시작 어드레스 설정 gs_stMPConfigurationManager.pstMPConfigurationTableHeader = pstMPConfigurationHeader; gs_stMPConfigurationManager.qwBaseEntryStartAddress = pstMPFloatingPointer->dwMPConfigurationTableAddress + sizeof( MPCONFIGURATIONTABLEHEADER ); // 모든 엔트리를 돌면서 프로세서의 코어 수를 계산하고 ISA 버스를 검색하여 ID를 저장 qwEntryAddress = gs_stMPConfigurationManager.qwBaseEntryStartAddress; for( i = 0 ; i < pstMPConfigurationHeader->wEntryCount ; i++ ) { bEntryType = *( BYTE* ) qwEntryAddress; switch( bEntryType ) { // 프로세서 엔트리이면 프로세서의 수를 하나 증가시킴 case MP_ENTRYTYPE_PROCESSOR: pstProcessorEntry = ( PROCESSORENTRY* ) qwEntryAddress; if( pstProcessorEntry->bCPUFlags & MP_PROCESSOR_CPUFLAGS_ENABLE ) { gs_stMPConfigurationManager.iProcessorCount++; } qwEntryAddress += sizeof( PROCESSORENTRY ); break; // 버스 엔트리이면 ISA 버스인지 확인하여 저장 case MP_ENTRYTYPE_BUS: pstBusEntry = ( BUSENTRY* ) qwEntryAddress; if( kMemCmp( pstBusEntry->vcBusTypeString, MP_BUS_TYPESTRING_ISA, kStrLen( MP_BUS_TYPESTRING_ISA ) ) == 0 ) { gs_stMPConfigurationManager.bISABusID = pstBusEntry->bBusID; } qwEntryAddress += sizeof( BUSENTRY ); break; // 기타 엔트리는 무시하고 이동 case MP_ENTRYTYPE_IOAPIC: case MP_ENTRYTYPE_IOINTERRUPTASSIGNMENT: case MP_ENTRYTYPE_LOCALINTERRUPTASSIGNMENT: default: qwEntryAddress += 8; break; } } return TRUE; }
/** * 시스템의 상태를 감시하여 화면에 표시하는 태스크 */ void kSystemMonitorTask( void ) { QWORD qwWindowID; int i; int iWindowWidth; int iProcessorCount; DWORD vdwLastCPULoad[ MAXPROCESSORCOUNT ]; int viLastTaskCount[ MAXPROCESSORCOUNT ]; QWORD qwLastTickCount; EVENT stReceivedEvent; WINDOWEVENT* pstWindowEvent; BOOL bChanged; RECT stScreenArea; QWORD qwLastDynamicMemoryUsedSize; QWORD qwDynamicMemoryUsedSize; QWORD qwTemp; //-------------------------------------------------------------------------- // 그래픽 모드 판단 //-------------------------------------------------------------------------- // MINT64 OS가 그래픽 모드로 시작했는지 확인 if( kIsGraphicMode() == FALSE ) { // MINT64 OS가 그래픽 모드로 시작하지 않았다면 실패 kPrintf( "This task can run only GUI mode~!!!\n" ); return ; } //-------------------------------------------------------------------------- // 윈도우를 생성 //-------------------------------------------------------------------------- // 화면 영역의 크기를 반환 kGetScreenArea( &stScreenArea ); // 현재 프로세서의 개수로 윈도우의 너비를 계산 iProcessorCount = kGetProcessorCount(); iWindowWidth = iProcessorCount * ( SYSTEMMONITOR_PROCESSOR_WIDTH + SYSTEMMONITOR_PROCESSOR_MARGIN ) + SYSTEMMONITOR_PROCESSOR_MARGIN; // 윈도우를 화면 가운데에 생성한 뒤 화면에 표시하지 않음. 프로세서 정보와 메모리 정보를 // 표시하는 영역을 그린 뒤 화면에 표시 qwWindowID = kCreateWindow( ( stScreenArea.iX2 - iWindowWidth ) / 2, ( stScreenArea.iY2 - SYSTEMMONITOR_WINDOW_HEIGHT ) / 2, iWindowWidth, SYSTEMMONITOR_WINDOW_HEIGHT, WINDOW_FLAGS_DEFAULT & ~WINDOW_FLAGS_SHOW, "System Monitor" ); // 윈도우를 생성하지 못했으면 실패 if( qwWindowID == WINDOW_INVALIDID ) { return ; } // 프로세서 정보를 표시하는 영역을 3픽셀 두께로 표시하고 문자열을 출력 kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + 15, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + 15, RGB( 0, 0, 0 ) ); kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + 16, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + 16, RGB( 0, 0, 0 ) ); kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + 17, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + 17, RGB( 0, 0, 0 ) ); kDrawText( qwWindowID, 9, WINDOW_TITLEBAR_HEIGHT + 8, RGB( 0, 0, 0 ), WINDOW_COLOR_BACKGROUND, "Processor Information", 21 ); // 메모리 정보를 표시하는 영역을 3픽셀 두께로 표시하고 문자열을 출력 kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 50, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 50, RGB( 0, 0, 0 ) ); kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 51, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 51, RGB( 0, 0, 0 ) ); kDrawLine( qwWindowID, 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 52, iWindowWidth - 5, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 52, RGB( 0, 0, 0 ) ); kDrawText( qwWindowID, 9, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 43, RGB( 0, 0, 0 ), WINDOW_COLOR_BACKGROUND, "Memory Information", 18 ); // 윈도우를 화면에 표시 kShowWindow( qwWindowID, TRUE ); // 루프를 돌면서 시스템 정보를 감시하여 화면에 표시 qwLastTickCount = 0; // 마지막으로 측정한 프로세서의 부하와 태스크 수, 그리고 메모리 사용량은 모두 0으로 설정 kMemSet( vdwLastCPULoad, 0, sizeof( vdwLastCPULoad ) ); kMemSet( viLastTaskCount, 0, sizeof( viLastTaskCount ) ); qwLastDynamicMemoryUsedSize = 0; //-------------------------------------------------------------------------- // GUI 태스크의 이벤트 처리 루프 //-------------------------------------------------------------------------- while( 1 ) { //---------------------------------------------------------------------- // 이벤트 큐의 이벤트 처리 //---------------------------------------------------------------------- // 이벤트 큐에서 이벤트를 수신 if( kReceiveEventFromWindowQueue( qwWindowID, &stReceivedEvent ) == TRUE ) { // 수신된 이벤트를 타입에 따라 나누어 처리 switch( stReceivedEvent.qwType ) { // 윈도우 이벤트 처리 case EVENT_WINDOW_CLOSE: //-------------------------------------------------------------- // 윈도우 닫기 이벤트이면 윈도우를 삭제하고 루프를 빠져나가 태스크를 종료 //-------------------------------------------------------------- // 윈도우 삭제 kDeleteWindow( qwWindowID ); return ; break; // 그 외 정보 default: break; } } // 0.5초마다 한번씩 시스템 상태를 확인 if( ( kGetTickCount() - qwLastTickCount ) < 500 ) { kSleep( 1 ); continue; } // 마지막으로 측정한 시간을 최신으로 업데이트 qwLastTickCount = kGetTickCount(); //---------------------------------------------------------------------- // 프로세서 정보 출력 //---------------------------------------------------------------------- // 프로세서 수만큼 부하와 태스크 수를 확인하여 달라진 점이 있으면 화면에 업데이트 for( i = 0 ; i < iProcessorCount ; i++ ) { bChanged = FALSE; // 프로세서 부하 검사 if( vdwLastCPULoad[ i ] != kGetProcessorLoad( i ) ) { vdwLastCPULoad [ i ] = kGetProcessorLoad( i ); bChanged = TRUE; } // 태스크 수 검사 else if( viLastTaskCount[ i ] != kGetTaskCount( i ) ) { viLastTaskCount[ i ] = kGetTaskCount( i ); bChanged = TRUE; } // 이전과 비교해서 변경 사항이 있으면 화면에 업데이트 if( bChanged == TRUE ) { // 화면에 현재 프로세서의 부하를 표시 kDrawProcessorInformation( qwWindowID, i * SYSTEMMONITOR_PROCESSOR_WIDTH + ( i + 1 ) * SYSTEMMONITOR_PROCESSOR_MARGIN, WINDOW_TITLEBAR_HEIGHT + 28, i ); } } //---------------------------------------------------------------------- // 동적 메모리 정보 출력 //---------------------------------------------------------------------- // 동적 메모리의 정보를 반환 kGetDynamicMemoryInformation( &qwTemp, &qwTemp, &qwTemp, &qwDynamicMemoryUsedSize ); // 현재 동적 할당 메모리 사용량이 이전과 다르다면 메모리 정보를 출력 if( qwDynamicMemoryUsedSize != qwLastDynamicMemoryUsedSize ) { qwLastDynamicMemoryUsedSize = qwDynamicMemoryUsedSize; // 메모리 정보를 출력 kDrawMemoryInformation( qwWindowID, WINDOW_TITLEBAR_HEIGHT + SYSTEMMONITOR_PROCESSOR_HEIGHT + 60, iWindowWidth ); } } }
/** * GUI 버전의 콘솔 셸 태스크 */ void kGUIConsoleShellTask( void ) { static QWORD s_qwWindowID = WINDOW_INVALIDID; int iWindowWidth, iWindowHeight; EVENT stReceivedEvent; KEYEVENT* pstKeyEvent; RECT stScreenArea; KEYDATA stKeyData; TCB* pstConsoleShellTask; QWORD qwConsoleShellTaskID; //-------------------------------------------------------------------------- // 그래픽 모드 판단 //-------------------------------------------------------------------------- // MINT64 OS가 그래픽 모드로 시작했는지 확인 if( kIsGraphicMode() == FALSE ) { // MINT64 OS가 그래픽 모드로 시작하지 않았다면 실패 kPrintf( "This task can run only GUI mode~!!!\n" ); return ; } // GUI 콘솔 셸 윈도우가 존재하면 생성된 윈도우를 최상위로 만들고 태스크 종료 if( s_qwWindowID != WINDOW_INVALIDID ) { kMoveWindowToTop( s_qwWindowID ); return ; } //-------------------------------------------------------------------------- // 윈도우를 생성 //-------------------------------------------------------------------------- // 전체 화면 영역의 크기를 반환 kGetScreenArea( &stScreenArea ); // 윈도우의 크기 설정, 화면 버퍼에 들어가는 문자의 최대 너비와 높이를 고려해서 계산 iWindowWidth = CONSOLE_WIDTH * FONT_ENGLISHWIDTH + 4; iWindowHeight = CONSOLE_HEIGHT * FONT_ENGLISHHEIGHT + WINDOW_TITLEBAR_HEIGHT + 2; // 윈도우 생성 함수 호출, 화면 가운데에 생성 s_qwWindowID = kCreateWindow( ( stScreenArea.iX2 - iWindowWidth ) / 2, ( stScreenArea.iY2 - iWindowHeight ) / 2, iWindowWidth, iWindowHeight, WINDOW_FLAGS_DEFAULT, "Console Shell for GUI" ); // 윈도우를 생성하지 못했으면 실패 if( s_qwWindowID == WINDOW_INVALIDID ) { return ; } // 셸 커맨드를 처리하는 콘솔 셸 태스크를 생성 kSetConsoleShellExitFlag( FALSE ); pstConsoleShellTask = kCreateTask( TASK_FLAGS_LOW | TASK_FLAGS_THREAD, 0, 0, ( QWORD ) kStartConsoleShell, TASK_LOADBALANCINGID ); if( pstConsoleShellTask == NULL ) { // 콘솔 셸 태스크 생성에 실패하면 윈도우를 삭제하고 종료 kDeleteWindow( s_qwWindowID ); return ; } // 콘솔 셸 태스크의 ID를 저장 qwConsoleShellTaskID = pstConsoleShellTask->stLink.qwID; // 이전 화면 버퍼를 초기화 kMemSet( gs_vstPreviousScreenBuffer, 0xFF, sizeof( gs_vstPreviousScreenBuffer ) ); //-------------------------------------------------------------------------- // GUI 태스크의 이벤트 처리 루프 //-------------------------------------------------------------------------- while( 1 ) { // 화면 버퍼의 변경된 내용을 윈도우에 업데이트 kProcessConsoleBuffer( s_qwWindowID ); // 이벤트 큐에서 이벤트를 수신 if( kReceiveEventFromWindowQueue( s_qwWindowID, &stReceivedEvent ) == FALSE ) { kSleep( 0 ); continue; } // 수신된 이벤트를 타입에 따라 나누어 처리 switch( stReceivedEvent.qwType ) { // 키 이벤트 처리 case EVENT_KEY_DOWN: case EVENT_KEY_UP: // 여기에 키보드 이벤트 처리 코드 넣기 pstKeyEvent = &( stReceivedEvent.stKeyEvent ); stKeyData.bASCIICode = pstKeyEvent->bASCIICode; stKeyData.bFlags = pstKeyEvent->bFlags; stKeyData.bScanCode = pstKeyEvent->bScanCode; // 키를 그래픽 모드용 키 큐로 삽입하여 셸 태스크의 입력으로 전달 kPutKeyToGUIKeyQueue( &stKeyData ); break; // 윈도우 이벤트 처리 case EVENT_WINDOW_CLOSE: // 생성한 셸 태스크가 종료되도록 종료 플래그를 설정하고 종료될 때까지 대기 kSetConsoleShellExitFlag( TRUE ); while( kIsTaskExist( qwConsoleShellTaskID ) == TRUE ) { kSleep( 1 ); } // 윈도우를 삭제하고 윈도우 ID를 초기화 kDeleteWindow( s_qwWindowID ); s_qwWindowID = WINDOW_INVALIDID; return ; break; // 그 외 정보 default: // 여기에 알 수 없는 이벤트 처리 코드 넣기 break; } } }
/** * 셸의 메인 루프 */ void kStartConsoleShell( void ) { char vcCommandBuffer[ CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ]; int iCommandBufferIndex = 0; BYTE bKey; int iCursorX, iCursorY; CONSOLEMANAGER* pstConsoleManager; // 콘솔을 관리하는 자료구조를 반환 pstConsoleManager = kGetConsoleManager(); // 프롬프트 출력 kPrintf( CONSOLESHELL_PROMPTMESSAGE ); // 콘솔 셸 종료 플래그가 TRUE가 될 때까지 반복 while( pstConsoleManager->bExit == FALSE ) { bKey = kGetCh(); // 콘솔 셸 종료 플래그가 설정된 경우 루프를 종료 if( pstConsoleManager->bExit == TRUE ) { break; } if( bKey == KEY_BACKSPACE ) { if( iCommandBufferIndex > 0 ) { // 현재 커서 위치를 얻어서 한 문자 앞으로 이동한 다음 공백을 출력하고 // 커맨드 버퍼에서 마지막 문자 삭제 kGetCursor( &iCursorX, &iCursorY ); kPrintStringXY( iCursorX - 1, iCursorY, " " ); kSetCursor( iCursorX - 1, iCursorY ); iCommandBufferIndex--; } } else if( bKey == KEY_ENTER ) { kPrintf( "\n" ); if( iCommandBufferIndex > 0 ) { // 커맨드 버퍼에 있는 명령을 실행 vcCommandBuffer[ iCommandBufferIndex ] = '\0'; kExecuteCommand( vcCommandBuffer ); } // 프롬프트 출력 및 커맨드 버퍼 초기화 kPrintf( "%s", CONSOLESHELL_PROMPTMESSAGE ); kMemSet( vcCommandBuffer, '\0', CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ); iCommandBufferIndex = 0; } // 시프트 키, CAPS Lock, NUM Lock, Scroll Lock은 무시 else if( ( bKey == KEY_LSHIFT ) || ( bKey == KEY_RSHIFT ) || ( bKey == KEY_CAPSLOCK ) || ( bKey == KEY_NUMLOCK ) || ( bKey == KEY_SCROLLLOCK ) ) { ; } else if( bKey < 128 ) { // TAB은 공백으로 전환 if( bKey == KEY_TAB ) { bKey = ' '; } // 버퍼가 남아있을 때만 가능 if( iCommandBufferIndex < CONSOLESHELL_MAXCOMMANDBUFFERCOUNT ) { vcCommandBuffer[ iCommandBufferIndex++ ] = bKey; kPrintf( "%c", bKey ); } } } }
/** * 인터럽트 자료구조 초기화 */ void kInitializeHandler( void ) { kMemSet( &gs_stInterruptManager, 0, sizeof( gs_stInterruptManager ) ); }