이게… 그러니까




Open Live Writer 공개 시점 이후로

티스토리에서 게시물 읽기 API를 변경한것 같다.

게시물 읽기에서 오류가 생기네..




수정해서 올려 놓는다.





사용방법 :

압축 풀어서 Open Live Writer 폴더에 복사.


patch_2018.06.25.zip



주위의 지인이 랜섬웨어에 감염되어 자료를 전부 날렸다라는 말을 들었다.

그래서 왠지 모를 불안감에 나도 감염되어 있을 것 같아서 온갖 다양한 무료 백신들 설치와 함께 검사를

시도했었는데 다행이 나의 콤퓨타는 무사함을 확인 할 수 있었다.

그래도 언젠가(?) 어떻게 랜섬웨어에 노출 될 수도 있을거라 생각되어

(모두 이런 불안감에 설치할 것이다…. 바이러스는 예방이 중요한거니..)






   

안랩 안티랜섬웨어 툴을 설치했다.

   

그 후 이틀 뒤… 윈도우가 이상해졌다.

프로그램 실행도 늦고 어떤 프로그램은 실행 조차 되지 않는 상황에 이르렀다.

바이러스 걸린 걸로 알고 윈도우즈를 발칵 뒤집어 놨다.

보호 모드 , 프로그램 삭제, 레지스트리 삭제 … 휴~~~



생각만 해도 끔찍하다…

할 수 있는 방법은 다 했다.


갖은 삽질끝에 안티랜섬웨어 툴 이 놈이 문제..


아~~~~~~~~~~~~~ 그 깊은 빡침이란….




 

OpenLiveWriter-0.6.2.zip


Open Live Writer 올리고 잊고 지내다

우연히 블로그를 들렀는데 .. 댓글에 내가 만들어 올린 Open Live Writer가 구글 블로그에

접속이 안된다는 글을 보았다.


차일 피일 미루다가 수정해서 올린다..


난… 게으르니까..이해 바랍니다.



# 수정 사항

- 구글 블로그 지원.



* 첨부 파일 적용 방법.

http://openlivewriter.org 사이트에서 영문 오리지널 open live writer를 설치했다면

C:\사용자\계정ID\AppData\Local\OpenLiveWriter\app-0.6.2 폴더에 첨부 된 압축 파일을 복사 하면 됩니다.




OpenLiveWriter-0.6.2.zip

사용법#1 에서는 티스토리에서 Open Live Writer를 사용하기 위한 준비를 했다. 이제는 Open Live Writer 설치 및 환경설정을 설명한다. (간단하다)

1. 이 블로그에 첨부된 OpenLiveWriter-0.6.2.zip 압축 파일을 다운 받는다.

2. 압축 받은 파일을 적당한 폴더에 압축을 푼다.

3. OpenLiveWriter.exe를 실행한다.

1


[기타 서비스]를 선택 한 후 [다음] 버튼을 클릭한다.

2


블로그 웹 주소 : 블로그 웹 주소를 입력한다.

사용자 이름 : 티스토리 아이디를 입력한다.

비밀번호 : 티스토리 비밀번호를 입력한다.

암호 저장 :  암호 저장을 꼭 선택한다. (※안 하면.. 계정이 잠길 수도 있다)

모두 입력 후 [다음] 을 선택한다.

3


[블로그 유형 선택] 에서 [Tistory OAuth]를 선택한다.


4


위에 빨간 상자 부분이 제일 중요한 부분이다.

https://www.tistory.com/oauth/authorize?client_id=[메모장에 적어 놓은 client_id]&redirect_uri=http://[클라이언트 등록할때 Callback 경로]&response_type=token


위에서 [ … ] 부분을 채워 넣는다. 제대로 입력된 예시는 다음과 같다.


https://www.tistory.com/oauth/authorize?client_id=ABCDEFGHIJKLMNOPQRSTUVWXYZ&redirect_uri=http://www.manggong.org&response_type=token




모두 입력 되었다면 [다음] 버튼을 선택한다.


이렇게 해서 Open Live writer 적용 방법을 마친다.

그렇다… 여기에 더 내 시간을 투자하기 싫어 진거다..

여기에 묶여서 2주라는 시간을 버렸다 ㅠㅠ








* 개선사항

- 블로그 최신 게시물이 10개 이상 안되는 문제

- Open Live Writer에 버그가 많다. (Windows Live Writer에서는 이렇지 않았는데..흠)

- 기타…


티스토리 사이트 준비 사항

1. 티스토리 웹에서 로그인. (http://www.tistory.com)

2. [계정 관리] 로 이동

3. [보안] 메뉴에서 [로그인 기기 관리] 선택

0


모든 기기에서 로그인을 허용합니다.
를 선택한 후 변경사항을 저장을 선택한다.

이렇게 하지 않으면 글 게시가 않된다. (Open live writer에서 로그인 시 간혹 가다가 권한을 허용하느니 마느니 웹 창이 떠서 귀찮게 한다.)

4. 티스토리 [이용가이드] 메뉴에서  [오픈 API 가이드] 탭으로 이동한다. (http://www.tistory.com/guide/api/oauth) 

4. 티스토리가 개편되면서 URL도 변경되었다.
(https://tistory.com/guide/api/manage/register)

image


여기에서 클라이언트 등록을 선택한다.

   


서비스 URL : 티스토리 URL 입력
  

Callback 경로 : 도메인 있을 경우 도메인. 없으면 티스토리 URL을 입력한다. 이 Callback 경로는 꼭 기억해야 한다.
       

[등록] 버튼을 선택한다.

    

5. 다시 티스토리 [이용가이드] 메뉴에서  [오픈 API 가이드] 탭으로 이동한다.

5. 다시 티스토리 메뉴에서  [앱관리] 탭으로 이동한다.
(https://tistory.com/guide/api/manage/list)

           image
          
         
[앱관리] 를 선택하면 방금 등록한 서비스 명으로 목록이 나온다.

인증관리 부분 설정을 클릭한다.

image


설정을 클릭하면 위와 같은 목록이 나오는데 Client ID App ID 부분을 복사해서 메모장에 저장한다.

       

귀찮다 ~~

다음편에서 계속-


* 티스토리 개편으로 URL 변경되고 화면이 바뀌어서 수정함. (2018.10.23)

티스토리에서 OAuth 2.0을 지원하면서(?) 기존에 windows live writer가 사용이 불가능 해졌다.

뭐 일 때문에 바빠서 블로그에 글을 안쓰고 있었지만 막상 기존 metablog api 를 이용해서 블로그에 글을 포스팅 할 수 없다고 하니 좀 아쉬워 졌다. 뭔가 뺏긴듯한 느낌이라고 할까?? (웹 에디터 사용에 대한 반감일수도 ~ ^^)

그래서 Windows live writer를 사용할 만한 블로그를 찾아봤는데, 딱히 갈만한 곳이 없고 옮기는 작업도 귀찮다. (그렇다고 정형화 된 네이버나, 다음 블로그로 가기는 그렇잖아~)

고민만 하다가 일 때문에 또 잊고 지내다가 도메인 만료 되었다는 문자 메시지에 도메인 연장하면서 티스토리를 들렸다. 시간이 한참 지난터라 티스토리에 포스팅 할 수 있는 있는 프로그램 생길 것 같아서 검색해 봤더니 여전히 없었다. (아~ 검색해 보니 하나 정도 검색된다)

뭐, 목 마름 사람이 우물 판다고~

때마침 , Windows live writer 소스도 Open live writer라는 이름으로 공개되었다고 하니 티스토리 지원하게끔 해야지~ 라고 가벼운 마음으로 시작했다.


Open Live Writer 소스 분석

GitHub에서 Open live writer 소스 받고 , 분석해 보니 워낙 많은 블로그를 지원하게끔 만든터라 티스토리 지원도 쉬웠다. 그냥 클래스 상속 받아서 각 API에 맞는 기능만 구현해주면 된다. 뭐 그 과정중에서 티스토리 로그인 이라던지 이런 문제가 있었지만, 미숙한 내 잘못과 절차 상 문제가 있었다.


TISTORY OAUTH 2.0

티스토리 OAUTH API를 하다가 OAUTH 기술에 대해서 공부하게 되었는데, 티스토리는 많이 생략? 된듯 한 API로 지원한다. (물론 , 내가 스터디 한 내용이 워낙 기능 위주로 흝고 넘어가서 그렇게 생각 할 수도 있다)


짠~~ 대충 컴파일 해서 돌려 보니 기본 동작은 된다. 

image

Open Live Writer 한글화

막상 기능 추가 하고 보니 , 영어로 나오니 한글화가 아쉬워 졌다. 그래서 또 부랴부랴 한글화 지원하려고 Open Live Writer 소스 보니 한글로 번역된 문서가 있네? 그런데 확장자가 lcl 이다. (이거 뭔 확장자야?) 그래서 lcl 에서 검색해 봤더니 Microsoft Localization tool 에서 생성한 파일이란다. 이 Tool을 사용하면 언어 리소스 파일이 생성되는 것 같아 어둠의 경로로 다운 받아서 lcl 파일을 읽어 봤지만, 안 읽어 진다. 어떻게 해야 할지 막막해졌다. 그래서 한글 리소스 추가 하고 일일이 문자열을 노가다로 손수 변경했다. 이 작업을 하면서 내가 뭐하는 짓인지 모르겠더라. 오래 걸렸다. ㅠㅠ  (누가 lcl 파일 적용 관련해서 알려 줬으면 좋겠다 ㅠㅠ)


Open Live Writer 배포

Open Live Writer 티스토리 지원한다고 포스팅을 하니 개인적으로 배포좀 해달라고 메일이 왔다. 뭐 딱히 사람들이 쓸 것 같진 않았는데 , 나처럼 기존 Windows Live Writer로 쓰는 사람이 있나 보다. 혼자만 쓰려고 했는데 배포좀 해달라 하니….흠

Open live writer에 컴파일 하면 바로 압축되어서 배포 되도록 되어 있는 것 같아서 배포 작업을 시작했다. 그런데 NuGet을 이용하여 Packing 하고 squirrel을 이용하여 자체 실행 배포 프로그램을 만드는것 같은데 잘 안 된다. 그래서 squirrel에 대해서 분석하고 NuGet 사용법도 배우고 했지만 쉬운 문제가 아니다…(뭐 더이상 시간 뺏기기 싫은 것도 있었고…)

그냥 압축 파일로 배포!!.

IDT까지 어찌어찌 해서 처리는 해 놓은 것 같다. 그런데 갈수록 함수가 늘고 이것저것 변수들도 늘고 이러니 메인 파일이 지저분 하다. “뭐… 언제 시간 나면 한번 정리 해야지..~

그런데… 다음에 할 내용이 조금 무겁고 어렵다.. 페이징. 많이 어렵다. 이걸 구현 하느리 기존 소스 정리나 하는 게 나을 것 같다. 쉴겸…..~~

우선.. StartKernel() 함수를 좀더 간단하게 정리했다.

int  StartKernel(int argc, char *argv[])
{
	char *hello = "Hello OS!";
	char *complete = "complete.";
	BYTE* vidmem = (BYTE*)0xB8000;
	BYTE data = 0;
	int b = 5;
	int c = 0;


	kprint(hello);

	InitPIC();
	Init_IDT();
	Init_kbd();
	
	while(1) ;
	return 0;
}

InitPIC() PIC 초기화 함수

Init_IDT() IDT 초기화 함수

Init_kbd() 키보드 관련 초기화 함수.

많이 간단해졌다. 

printf 함수도 다시 구현하였다… 커널에서 프린트 한다는 의미로 kprint (많은 OS 들도 kprint 라고 하더라 ^^ ㅋㅋㅋ. 그래서 이름을 차용했다.)로 함수명을 바구고.. 문자열만이 아닌 가변 인자를 받아 출력 할 수 있도록 수정하였다.

문자열 관련 함수들 . strlen, strcpy, strcmp, memcpy, memcmp, memset 이런 함수들은 그냥 기존 코드들을 가져왔다. 이런걸로 시간 뺏기기 싫어서..(라고 쓰고… 만들 줄 모르고… 다시 작성한다는게 귀찮아서~^^)..^^

그리고 IDT 최종 키보드 입력 부분까지 구현했었는데..

문제는 대문자와 특수문자( !~@#등) 출력이 되지 않았다… 그래서 키보드 테이블을 대문자와 특수문자를 출력 할 수 있도록 SHIFT키와 CAPS LOCK키를 지원하도록 수정했다.

#include "stdio.h"
#include "keyboard.h"
#include "8042.h"
#include "asm.h"

BOOL IsLShift = FALSE;
BOOL IsRShift = FALSE;
BOOL IsCapslock = FALSE;
BOOL IsAlt = FALSE;
BOOL IsCtrl = FALSE;
BOOL IsNumLock = FALSE;


KeyboardInfo kbd_scancode[] = 
{
	{0x00,	0x00, 0x00},	// ESC
	{'1','!',	0x00, 0x00},
	{'2','@',	0x00, 0x00},
	{'3','#',  	0x00, 0x00},
	{'4','$', 	0x00, 0x00},
	{'5','%', 	0x00, 0x00},
	{'6','^',	0x00, 0x00},
	{'7','&',	0x00, 0x00},
	{'8','*',	0x00, 0x00},
	{'9','(',	0x00, 0x00},
	{'0',')',	0x00, 0x00},
	{'-','_',	0x00, 0x00},
	{'=','+',	0x00, 0x00},
	{0x00,0x00, 	0x00, 0x00},	// BACKSPACE
	{0x00,0x00, 	0x00, 0x00},	// TAB
	{'q','Q', 	0x00, 0x00},
	{'w','W', 	0x00, 0x00},
	{'e','E', 	0x00, 0x00},
	{'r','R', 	0x00, 0x00},
	{'t','T', 	0x00, 0x00},
	{'y','Y', 	0x00, 0x00},
	{'u','U', 	0x00, 0x00},
	{'i','I', 	0x00, 0x00},
	{'o','O', 	0x00, 0x00},
	{'p','P', 	0x00, 0x00},
	{'[','{', 	0x00, 0x00},
	{']','}', 	0x00, 0x00},
	{0x00,0x00, 	0x00, 0x00},	// ENTER
	{0x00,0x00, 	0x00, 0x00},	// CTRL
	{'a','A', 	0x00, 0x00},
	{'s','S', 	0x00, 0x00},
	{'d','D', 	0x00, 0x00},
	{'f','F', 	0x00, 0x00},
	{'g','G', 	0x00, 0x00},
	{'h','H', 	0x00, 0x00},
	{'j','J', 	0x00, 0x00},
	{'k','K', 	0x00, 0x00},
	{'l','L', 	0x00, 0x00},
	{';',':', 	0x00, 0x00},
	{'\'','"', 	0x00, 0x00},
	{'`','~', 	0x00, 0x00},
	{0x00,0x00, 	0x00, 0x00},	// Left Shift
	{'\\','|', 	0x00, 0x00},
	{'z','Z', 	0x00, 0x00},
	{'x','X', 	0x00, 0x00},
	{'c','C', 	0x00, 0x00},
	{'v','V', 	0x00, 0x00},
	{'b','B', 	0x00, 0x00},
	{'n','N', 	0x00, 0x00},
	{'m','M', 	0x00, 0x00},
	{',','<', 	0x00, 0x00},
	{'.','>', 	0x00, 0x00},
	{'/','?', 	0x00, 0x00},
	{0x00,0x00,	0x00, 0x00},	// right shift
	{0x00,0x00, 	0x00, 0x00},	// PrtSc
	{0x00,0x00, 	0x00, 0x00},	// ALT
	{' ',' ', 	0x00, 0x00},	// space
	{0x00,0x00, 	0x00, 0x00},	// caps
	{0x00,0x00, 	0x00, 0x00},	// F1
	{0x00,0x00, 	0x00, 0x00},	// F2
	{0x00,0x00, 	0x00, 0x00},	// F3
	{0x00,0x00, 	0x00, 0x00},	// F4
	{0x00,0x00, 	0x00, 0x00},	// F5
	{0x00,0x00, 	0x00, 0x00},	// F6
	{0x00,0x00, 	0x00, 0x00},	// F7
	{0x00,0x00, 	0x00, 0x00},	// F8
	{0x00,0x00, 	0x00, 0x00},	// F9
	{0x00,0x00, 	0x00, 0x00},	// F10
	{0x00,0x00, 	0x00, 0x00},	// number lock
	{0x00,0x00, 	0x00, 0x00},	// scroll
	{0x00,0x00, 	0x00, 0x00},	// home { numlook = 7 }
	{0x00,0x00, 	0x00, 0x00},	// up	{ numlook = 8 }
	{0x00,0x00, 	0x00, 0x00},	// pgup	{ numlook = 9 }
	{'-','-', 	0x00, 0x00},	// -
	{0x00,0x00, 	0x00, 0x00},	// left	{ numlook = 4 }
	{0x00,0x00, 	0x00, 0x00},	// center	{ numlook = 5 }
	{0x00,0x00, 	0x00, 0x00},	// right	{ numlook = 6 }
	{'+','*', 	0x00, 0x00},	
	{0x00,0x00, 	0x00, 0x00},	// end	{ numlook = 1 }
	{0x00,0x00, 	0x00, 0x00},	// down	{ numlook = 2 }
	{0x00,0x00, 	0x00, 0x00},	// pgdn	{ numlook = 3 }
	{0x00,0x00, 	0x00, 0x00},	// ins	{ numlook = 0 }
	{0x00,0x00, 	0x00, 0x00},	// del	{ numlook = . }
	{'/','/', 	0x00, 0x00},	// /
	{0x00,0x00, 	0x00, 0x00},	// enter
	{0x00,0x00, 	0x57, 0xD7},	// F11
	{0x00,0x00, 	0x58, 0xD8},	// F12
	{0x00,0x00, 	0x52, 0xD2},	// ins
	{0x00,0x00, 	0x53, 0xD3},	// del
	{0x00,0x00, 	0x47, 0xC7},	// home
	{0x00,0x00, 	0x4F, 0xCF},	// end
	{0x00,0x00, 	0x49, 0xC9},	// pgup
	{0x00,0x00, 	0x51, 0xD1},	// pgdn
	{0x00,0x00, 	0x4B, 0xCB},	// left
	{0x00,0x00, 	0x4D, 0xCD},	// right
	{0x00,0x00, 	0x48, 0xC8},	// up
	{0x00,0x00, 	0x50, 0xD0},	// down
	{0x00,0x00, 	0x38, 0xB8},	// right alt
	{0x00,0x00, 	0x1D, 0x9D},	// right ctrl
	{0x11,0x00, 	0x00, 0x00}};	// pause	// 99 index

void Init_kbd()
{
	int i = 0;

	for(i = 0; i < 0x54; i++ )
	{
		kbd_scancode[i].Press = i+1;
		kbd_scancode[i].Release = 0x81 + i;
	}

	Write_port_byte(0x21, 0xFD);
}

int GetScanCodeInfo(BYTE code, KeyboardInfo *pkbdInfo)
{
	int i;

	if( code > 0xD9 )	// Unknown code
		return UNKNOWN_SCANCODE;

	for( i = 0; i < 0x64; i++ )
	{
		if( kbd_scancode[i].Press == code )
		{
			*pkbdInfo = kbd_scancode[i];
			return PRESS_SCANCODE;
		}

		if(kbd_scancode[i].Release == code)
		{
			*pkbdInfo = kbd_scancode[i];
			return RELEASE_SCANCODE;
		}
	}

	return UNKNOWN_SCANCODE;
}

void Kbd_ScanCode()
{
	BYTE scancode;
	int scancode_type;
	KeyboardInfo	Info;

	scancode = GetKeyboardScanCode();

	scancode_type = GetScanCodeInfo(scancode, &Info);
		
	if(scancode_type == UNKNOWN_SCANCODE )
	{
		return;
	}

	if( scancode_type == RELEASE_SCANCODE )
	{
		switch(Info.Press)
		{
		case KEY_LSHIFT:
			IsLShift = FALSE;
		case KEY_RSHIFT:
			IsRShift = FALSE;
			break;
		case KEY_ALT:
			IsAlt = FALSE;
			break;
		case KEY_CTRL:
			IsCtrl = FALSE;
			break;
		}
		return;
	}

	if( scancode_type == PRESS_SCANCODE )
	{
		switch(Info.Press)
		{
		case KEY_LSHIFT:
			IsLShift = TRUE;
			break;
		case KEY_RSHIFT:
			IsRShift = TRUE;
			break;
		case KEY_ALT:
			IsAlt = TRUE;
			break;
		case KEY_CTRL:
			IsCtrl = TRUE;
			break;
		case KEY_CAPSLOCK:
			IsCapslock = !IsCapslock;
			break;
		case KEY_NUMBERLOCK:
			IsNumLock = !IsNumLock;
			break;
		case KEY_ENTER:
			kprint("\n");
			return;
		}

		if( IsCtrl || IsAlt )
		{
			// function key process
		}

		if( IsNumLock )
		{
			switch( Info.Press )
			{
			case 0x47:
				putc('7');
				return;
			case 0x48:
				putc('8');
				return;
			case 0x49:
				putc('9');
				return;
			case 0x4B:
				putc('4');
				return;
			case 0x4C:
				putc('5');
				return;
			case 0x4D:
				putc('6');
				return;
			case 0x4F:
				putc('1');
				return;
			case 0x50:
				putc('2');
				return;
			case 0x51:
				putc('3');
				return;
			case 0x52:
				putc('0');
				return;
			case 0x53:
				putc('.');
				return;
			}
		}

		if( IsCapslock )
		{
			if( Info.Lowercase >= 'a' && Info.Lowercase <= 'z')
			{
				if( IsLShift || IsRShift )
					putc(Info.Lowercase);
				else
					putc(Info.Uppercase);

				return;
			}
		}
		if( IsLShift || IsRShift )
		{
			if(Info.Lowercase != 0x00 )
				putc(Info.Uppercase);
			else
			{
				// function key process

				// otherwise
			}

			return;
		}

		if( Info.Lowercase != 0x00 )
			putc(Info.Lowercase);
	}
}

잘 된다.

그후 이것저것 바꿨다.

 

전번에 IDT를 구성하고 커널까지 컴파일 하고 부팅까지 해 보았다. 물론 아무런 기능도(?) 넣지 않아 눈으로 보기에는 아무 변화도 없었다. 재부팅 안하는게 어디야~~~. 우선 인터럽트 동작이 잘 동작 하는지 확인 해 보는 코드를 넣어서 내가 만든게 잘 동작하는지 확인해 보잣!!!! 아자~


int  StartKernel(int argc, char *argv[])
{
	char *hello = "Hello OS!";
	char *complete = "complete.";
	unsigned char* vidmem = (unsigned char*)0xB8000;
	unsigned char data = 0;
	int b = 5;
	int c = 0;


	printf(hello);

	InitPIC();
	Init_IDT();

	b = b/0;
	
	while(1) ;
	return 0;
}


void _declspec(naked) interrupt_handler()
{
	_asm pushad;

	printf("interrupt handler");
	_asm {
		popad
		iretd
	}		
}

인터럽트 중에 0으로 나누면 예외상황 인터럽트가 발생하는 인터럽트가 있었다. 그래서 0으로 나누면 분명히 인터럽트가 발생 할것이고 interrupt_handler함수에서 인터럽트가 발생하면 interrupt handler라는 문구를 찍도록 해보았다. 자~~ 컴파일..

헉!!!!! interrupt handler!! 무한 출력 후 재부팅 된다.

결과야 어찌되었든 인터럽트가 발생하여 화면에 출력이 되었다는 거에 만족하자~~ ㅋㅋㅋㅋㅋ 대충 했는데도 된다… ㅋ 오늘은 확인 했으니 이만 잘까??? 음… 뭐 IDT를 구현하게 된데에는 키보드 입력 받아서 출력 하는데 목적을 두었으니 키보드로 입력하면 키출력 하는데까지 하고 자야 겠다.

우선 0으로 나누는 부분을 지우고!~ 

키가 눌려지면 interrupt_handler함수가 호출 될테고 전번 포스팅 에서 했었던 것 처럼 0x60 포트를 읽으면 될것이다. 그러면 기존 코드를 붙여서..


void _declspec(naked) interrupt_handler()
{
	char keycode;

	_asm pushad;


	keycode = Read_port_byte(0x60);
	if(keycode >= 0 )
	{
		putc((char)kbd_scancode[keycode]);
	}
	_asm {
		popad
		iretd
	}		
}

짠,,… 컴파일은 잘 된다… 자 그럼!~

5..4..3..2..1 ……. 음… 안돼! 키 입력해도 아무런 변화가 없어!~~

왜???????????????????????????????????????????????????????????????????????????

IDT가 잘못 구성 되었나?? ….

소스를 봐도 뭐가 잘못 된 건지 모르겠다.. 디버깅도 안되고…ㅠㅠ 키보드 관련 검색부터 해보자..흠..

아….INIT_PIC함수에서 잘못 되었나? 그러고 보니 하드웨어 인터럽트 즉.. 8259 PIC는 하드웨어 인터럽트와 충돌이 나서 주소를 옮겨야 된다고 했다. 안 옮겨줬나?? 아닌데… 키보드 입력 되었는데… 너무 인터넷에서 긁어서 복사만 했나~~~ 흠. 그러면 다시 INIT_PIC 함수를 분석해보자 ..

void InitPIC()
{
	 
	Write_port_byte(0x20, 0x11);       
	Write_port_byte(0x21, 0x20);       
	Write_port_byte(0x21, 0x04);       
	Write_port_byte(0x21, 0x01);       
	Write_port_byte(0x21, 0xFF);         

	
	Write_port_byte(0xA0, 0x11);       
	Write_port_byte(0xA1, 0x28);       
	Write_port_byte(0xA1, 0x02);       
	Write_port_byte(0xA1, 0x01);       
	Write_port_byte(0xA1, 0xFF);        
}
      

Write_port_byte 함수야.. 뭐..첫번째 인자는 포트이고 두번째는 데이터…라는 것이고

0x20 포트에 0x11 데이터를 쓴다…. 왜?? 음.. 그냥 첫번째 PIC 아니 마스터 PIC 너를 초기화 할것이다. 라는 의미인것 같다.

Write_port_byte(0x21, 0x20) 이건 너의 인터럽트 시작 주소는 0x20 이다 라고 지정해주는 것이고.
Write_port_byte(0x21, 0x04) 요것은 음.. 마스터 PIC 3번째하고 슬레이브 PIC가 연결되어 있다라는걸 설정하는 것이란다. 3번째 인데 왜 4냐고?? PIC는 8개 비트로 구성되어 있는데~~~ 3번재 연결 핀이..

8bit 7bit 6bit 5bit 4bit 3bit 2bit 1bit
          1    

4가 된다..
Write_port_byte(0x21, 0x01) 이것은 8086 모드라는 것인데… 모르겠다.. 1로 설정 할 경우는 8086. 0인경우 80/85 모드라는데 .. 모르겠다. ㅡㅡ;;;;

Write_port_byte(0x21, 0xFF) ?????? 마스터 PIC 에서 모든 인터럽트를 막는다????? 이것 때문에 키보드가 입력 안되었던 것인가

Write_port_byte(0xA0, 0x11)  슬레이브 PIC 너를 초기화 해주겠어
Write_port_byte(0xA1, 0x28)  인터럽트 시작주소는 28 이다…
Write_port_byte(0xA1, 0x02);  넌 마스터PIC와 두번째 핀과 연결되어 있다.
Write_port_byte(0xA1, 0x01)  ?? 8086 ㅡㅡ;;;;;
Write_port_byte(0xA1, 0xFF)   모든 인터럽트를 막는다!!!!

그러니까… 저기 뻘건색으로 줄쳐진 이놈들 때문에 키보드가 동작하지 않은 것인가??? 왜???? 왜 막아야 하는건가??? 모르겠다… 지랄같은 영어.. 여튼.. 키보드는 마스터 PIC 두번째 핀에 연결되어 있다고 하니 0xFF를 0xFD로 바꿔보자… 그리고 컴파일 . 확인.

오!!!!!!!!!!!!!!

보라… Hello OS! 옆에 작은 a 으흐흐흐 동작한다… IDT 구성은 문제 없고 키보드 인터럽트도 잘 받고…??? 어라 그런데 한번만 입력된다…. 검색해보니 이러더라 EOI 를 보내라고 …. 그냥 EOI를 보내서 PIC 를 리셋 시켜야 된다고 한다.  마스터 PIC에서 인터럽트가 발생했으면 0x20 포트에다가 보내고… 슬레이브 PIC에서 발생했으면 0xA0과 , 마스터 PIC 0x20 둘다 보내야 한다고 한다. 그러면 인터럽트가 발생하면 발생한 인터럽트 IRQ를 알아야 마스터인지 슬래이브 인지 아는것 아닌가…흠… CPU가 인자로 넘겨주나??? 그런가 보다.. 넘겨주는 듯… 귀찮으니 우선은 키보드만 입력 받고… EOI를 보내라고 했으니 마스터PIC에 0x20을 보내고 다시 테스트.

흠…

잘 된다..


 

 

8042 키보드 컨트롤러

모르는건 인터넷에서 검색하다가 그것마저 귀찮으면 소스 찾아서 긁어서 사용하다 보니, 진행하다 보면 이게 뭐지? 하는 내용들이 종종 생긴다. “이것까지 내가 알아야 하나?” 하고 어물쩡 넘어갔는데 그런게 너무 반복 되다 보니  “내가 지금 뭐하고 있지?” 라는 생각이 요즘 많이 든다. 단순히 OS 만들것이면 인터넷에 널려 있는 소스들 수정해서 만들면 된다. 그냥 내가 목표로 하는 OS만 결과로 던져 내면 되는 것이다.  자… 그러면 난 지금 무엇을 하고 있는 것인가? OS를 만드는 것인가… OS를 만들기 위해서 공부를 하고 있는 것인가… 흠 그러다가 OS 만들기의 대단원의 시작인 첫 포스팅 글을 방금 다시 한번 찾아봤다.

OS를 만들기 위해 부랴부랴 인터넷 검색을 해봤다. 우와! 책도 많고 관련 정보들이 상당하다. 수준급인 OS 부터 기초 정보 또한 대단히 많다. ‘그냥 이거 가져다 수정하면서 공부해 보면 되겠네…’ 라고 생각했다가 접었다.. 왜? 내 코드가 아니고 내 구조가 아니고… 내 영혼(?)이 아니다. 그냥 하나 하나 내가 부딪치며 만들어야 내것 같다는 생각이 들어서다. 또 뭔가 고비가 있어야 내 지식이지, 단순히 복사 & 붙이기는 그냥 영혼없는 결과물 만들기일 뿐이라고 생각해서 이다.

ㅎㅎㅎ 무척 단순한 생각으로 시작했다. 남의 코드는 내것이 아니므로….^^ 영혼까지 언급했다.

복사 & 붙이기 로 결과물을 만들지 말자고 했는데 지금은 복사 & 붙이기 로 만들고 있다….. 그래… 다 공부해서 만들기로 했었지..~~~ㅎㅎㅎ

내가 왜 이런 심각한 고민을 하게 된건 , 8042 키보드 컨트롤러가 키보드 관련해서 검색해 보다가 등장해서 이다. 키보드에서 인터럽트가 발생하게 될 경우, 8259 에서 인터럽트를 CPU에 알리고 다시 0x60 포트에서 키 값을 읽으면 된다. 라는 이 부분에서 0x60 이 포트가 궁금해서 찾아보다가 찾았다. 그냥 0x60에서 키 값을 읽으면 된다 라고 하고 넘어갈까 말까 망설였었다. 왜?? 귀찮으니까~~~

ㅎㅎㅎㅎ

여하튼.. 그냥 하자!!!~~~~~~

키보드와 마우스는 시리얼 통신을 한다고 배웠고 그렇게 되어 있다고 한다. 이 키보드와 마우스는 우리가 쉽게 얘기하는 PS/2 라고 불리우는 8042 컨트롤러와 연결 되어 있고 말이다. 키보드/마우스 제어 외에도 앞선 포스팅에서 언급한 주소 확장 관련해서 A20 Enable 기능도 8042 컨트롤러가 제어한다고 한다.

위 그림은 8042와 8259PIC와 CPU 연결을 도식화 한 것이다. 키보드나 마우스 입력 시 8042는 8259 PIC 마스터나 슬레이브에 IRQ 신호를 보내고 8259는 이를 CPU에 보낸다. 또 CPU는 8042를 0x60 또는 0x64 포트를 통해 데이터를 읽던지 제어를 한다고 한다.

IO 포트

접근 구분

용도

0x60 Read/Write 데이터 읽고 쓰기
0x64 Read Status 읽기
0x64 Write 명령 요청

전번 포스팅에서 키보드에 데이터 입력이 있는지 없는지 알기 위해서 0x64 포트의 Status를 읽어서 사용한 적이 있었다.

또 키보드 관련해서 알아야 할 내용이 생겼다. Set1, Set2, Set3… 이게 뭐냐면.. IBM 에서 콤퓨타를 만들어 낼 때 마다 새로운 키보드 인터페이스를 만들었었는데 XT 키보드, AT 키보드, PS/2 키보드 등으로 구분된다고 한다. 또한 이 키보드 타입 들은 같은 문자에 따라 다른 값들을 보낸다고 한단다… 그래서 각 값들을 Set1, Set2, Set3에 맞게 찾아서 문자를 대입해야 한다고 한다. Set1은 XT , Set2는 AT, Set3은 PS/2.
내가 코드에서 사용했던 건 Set1 이다. 8042를 통해 현재 사용하고 있는 키보드의 인터페이스를 얻어 낼 수 있고 지정 할 수 있다고 한다.

음.. 8042 명령어들과 기능들도 있는데 이건 필요할 때 마다 참조 하는 것으로 하고 8042에 대해서 여기서 마쳐야 겠다.

Tistory 태그: ,,,,

저번에 Interrupt Descriptor Table에 대해서 대충(?) 알아봤다. 그래서 이번에는 구현해 보기로 했다. 막상 구현하려고 하니 뭘 해야 할지 답답… ㅎㅎㅎ 우선 저번에 간단하게 작성해 놓은 IDT 구조체 다시 한번 작성해 놓고..

typedef struct _IDTDesc
{
	unsigned short	Offset_low;
	unsigned short	Selector;
	unsigned char	Unused;
	unsigned char	Access;
	unsigned short	Offset_high;
} IDTDesc;

음… 이제… 이 구조체가 여러개 존재 한다고 하니… 배열로… 구성해서…근데 몇개??? 몇개를 해야 하지??? 음… 그냥 1바이트 255개..ㅡㅡ;;;;; 대충해 보자.. 그래….

#define MAX_IDT	255

IDTDesc IDT[MAX_IDT];

음…그리고….에.. 그러니까.. 테이블을 만들었으니까 GDT 처럼 GDTR 이라는 레지스터에 이 테이블 주소를 넣어주는 …아.. 그래 IDTR에 이 테이블 주소를 넣어줘야지!!! ㅎㅎㅎ 

그러면 IDTR 구조.

32bit 16bit            0bit
IDT의 메모리상에서 위치 IDT의 크기

뭐… 별거 없다.. GDTR 구조와 같다…그러면..

typedef struct _IDTRegistor
{
	unsigned short	Size;
	unsigned int	Address;
} IDTRegistor;

IDTRegistor	IDTR;

음… 이렇게 만들었으면 예외상황 인터럽트, 하드웨어 인터럽트, 시스템콜 들을 등록 하라고 하는데 ….. ??? 어떻게 하지?? 검색해 보자…!!!!!!…………………………………………………………

저번에 포스팅한 예외상황 인터럽트 번호 0 부터 … 채울 수 있을 때까지 채우란다.. 시스템콜들은 뭐라뭐라 하는데 그냥 건너뛰고… 예외상황 하고 하드웨어 입력….!!! 그런데 말이다…. IDT 각각의 항목이 뭔지를 알아야 채우지~~~

Offset_low(2Byte)
Offset_high(2Byte)

요 두 놈들은 인터럽트 발생 시 인터럽트가 해야 할 (ISR이라고 저번에 적었지!~~^^ 잊어버렸었다.) 작업 위치 란다. 즉, 해당 함수의 메모리 상 위치.

Selector(2Byte)

요놈은 보호모드 진입시 GDT 테이블에 적어 놓은 CODE, DATA 셀렉터를 입력하는 놈이라는 데… 난 아직도 CODE와 DATA가 어떤 의미인지 모르겠다.. 그냥, CODE 셀렉터… 음… GDT 테이블에서 0x08 가 CODE 니까.. 저긴 0x08로 입력하는 걸로.

Unused(1Byte)

요넘은 사용 안하니 패쓰하고

Access(1Byte)

요놈은 그러니까… 전번에 한번 적었던 기억이 나는데…...http://manggong.org/41 여기…

P, DPL, S, TYPE 요렇게 되어 있고. P는 1로 하라고 하니 1. DPL 특권 레벨에 대한 것이라고 하고 레벨 0, 유저는 3이라고 하는데 0. S는 그냥 0.
TYPE은 여러 종류가 있는 것 같은데 보호 모드로 진입해서 32비트 라고 하고 Trap Gate는 소프트웨어 인터럽트나 예외 인터럽트, Interrupt Gate는 하드웨어 인터럽트. 그러면 0xE 아니면 0xF 인것 같다.

자, 그러면 Access 이놈한테 줄 수 있는 값은 10001110(0x8E : 소프트웨어 인터럽트, 예외인터럽트), 또는 10001111(0x8F : 하드웨어 인터럽트)

흠.. 이제 IDT를 채워보자.

아… 그러고 보니 Offset_low, high에 입력 해 줄 인터럽트 서비스 루틴(ISR) 함수가 없다.. 음… 더미 함수 하나 만들어 보고……근데 그냥 만들면 되나??? ……….이거 뭐 하나 쉽게 진행이 안되니…
http://wiki.osdev.org/Interrupt_Service_Routines에 의하면

void _declspec(naked) interrupt_handler()
{
    _asm pushad;
 
    /* do something */
 
    _asm{
        popad
        iretd
    }
}

이런식으로 만들면 된다고 한다. 그래 그냥 저 함수 저대로 쓰자~~ ^^

자 그러면.. 입력!

void Init_IDT()
{
	int i;
	unsigned int high, low;
	
	for(i = 0; i < MAX_IDT; i++ )
	{
		IDT[i].Selector = 0x08;
		if( i < 0x14 )
			IDT[i].Access = 0x8E;		// 예외 인터럽트
	    else
			IDT[i].Access = 0x8F;		// 하드웨어

		IDT[i].Unused = 0x00;

		low = (unsigned int)&interrupt_handler;
		low = low & 0xFFFF;

		high = (unsigned int)&interrupt_handler;
		high = (high >> 16);

		IDT[i].Offset_high = (unsigned short)high;
		IDT[i].Offset_low = (unsigned short)low;
	}
}

그리고 내친김에 IDTR도…

	IDTR.Address = (unsigned int)&IDT;
	IDTR.Size  = MAX_IDT * sizeof( IDTDesc );

다 입력했다… 마지막으로 이제 어셈블리어 LIDT 로 IDTR을 로딩시켜 주면…~~~~~~~ 된다고 하는데 … 어셈은 어려워 ㅠㅠ … 대충 해보자….

void LoadIDTR(unsigned int addr)
{
	_asm
	{
		mov	eax, [addr]
		lidt	[eax]
		sti
	}
}

ㅎㅎㅎㅎ lidt에 idtr 주소 넣어 주고 sti 명령어로 인터럽트를 활성화 시켜주면 된다고 한다. 자…. 한번 해볼까??

void InitPIC();
void Init_IDT();
void interrupt_handler();
void LoadIDTR(unsigned int addr);

unsigned char Read_port_byte(unsigned short port);
void Write_port_byte(unsigned short port, unsigned char data);


typedef struct _IDTDesc
{
	unsigned short	Offset_low;
	unsigned short	Selector;
	unsigned char	Unused;
	unsigned char	Access;
	unsigned short	Offset_high;
} IDTDesc;

typedef struct _IDTRegistor
{
	unsigned short	Size;
	unsigned int	Address;
} IDTRegistor;


#define MAX_IDT		255

IDTDesc	IDT[MAX_IDT];
IDTRegistor	IDTR;

unsigned char	*Screen = (unsigned char*)0xB8000;

#define	KEY_F1		0x80
#define	KEY_F2		(KEY_F1 + 1)
#define	KEY_F3		(KEY_F2 + 1)
#define	KEY_F4		(KEY_F3 + 1)
#define	KEY_F5		(KEY_F4 + 1)
#define	KEY_F6		(KEY_F5 + 1)
#define	KEY_F7		(KEY_F6 + 1)
#define	KEY_F8		(KEY_F7 + 1)
#define	KEY_F9		(KEY_F8 + 1)
#define	KEY_F10		(KEY_F9 + 1)
#define	KEY_F11		(KEY_F10 + 1)
#define	KEY_F12		(KEY_F11 + 1)

#define	KEY_INS		0x90
#define	KEY_DEL		(KEY_INS + 1)
#define	KEY_HOME	(KEY_DEL + 1)
#define	KEY_END		(KEY_HOME + 1)
#define	KEY_PGUP	(KEY_END + 1)
#define	KEY_PGDN	(KEY_PGUP + 1)
#define	KEY_LFT		(KEY_PGDN + 1)
#define	KEY_UP		(KEY_LFT + 1)
#define	KEY_DN		(KEY_UP + 1)
#define	KEY_RT		(KEY_DN + 1)
#define	KEY_PRNT	(KEY_RT + 1)
#define	KEY_PAUSE	(KEY_PRNT + 1)
#define	KEY_LWIN	(KEY_PAUSE + 1)
#define	KEY_RWIN	(KEY_LWIN + 1)
#define	KEY_MENU	(KEY_RWIN + 1)

	static const unsigned char kbd_scancode[] =
	{
0,	0x1B,	'1',	'2',	'3',	'4',	'5',	'6',
'7',	'8',	'9',	'0',	'-',	'=',	'\b',	'\t',
'q',	'w',	'e',	'r',	't',	'y',	'u',	'i',

'o',	'p',	'[',	']',	'\n',	0,	'a',	's',
'd',	'f',	'g',	'h',	'j',	'k',	'l',	';',

'\'',	'`',	0,	'\\',	'z',	'x',	'c',	'v',
'b',	'n',	'm',	',',	'.',	'/',	0,	0,
0,	' ',	0,	KEY_F1,	KEY_F2,	KEY_F3,	KEY_F4,	KEY_F5,
KEY_F6,	KEY_F7,	KEY_F8,	KEY_F9,	KEY_F10,0,	0,	KEY_HOME,
KEY_UP,	KEY_PGUP,'-',	KEY_LFT,'5',	KEY_RT,	'+',	KEY_END,
KEY_DN,	KEY_PGDN,KEY_INS,KEY_DEL,0,	0,	0,	KEY_F11,
KEY_F12
	};

void printf( char *msg )
{

	while(*msg != '\0')
	{
		*Screen++ = *msg++;
		*Screen++ = 7;
	}
}

void putc(char Code)
{
	*Screen++ = Code;
	*Screen++ = 7;
}



int  StartKernel(int argc, char *argv[])
{
	char *hello = "Hello OS!";
	char *complete = "complete.";
	unsigned char* vidmem = (unsigned char*)0xB8000;
	unsigned char data = 0;
	int b = 5;
	int c = 0;


	printf(hello);

	InitPIC();
	Init_IDT();


	while(1) ;
	return 0;
}

unsigned char Read_port_byte(unsigned short port)
{
	unsigned char KeyCode = 0;

	__asm
	{
		mov		dx, port
		xor		eax, eax
		in		ax, dx
		lea		ebx, KeyCode
		mov		[ebx], al
	}

	return KeyCode;
}

void Write_port_byte(unsigned short port, unsigned char data)
{
	__asm
	{
        mov		dx, [ebp+8]
        mov		al, [ebp+12]
        out		dx, al
	}
}

void InitPIC()
{
	 
	Write_port_byte(0x20, 0x11);       
	Write_port_byte(0x21, 0x20);       
	Write_port_byte(0x21, 0x04);       
	Write_port_byte(0x21, 0x01);       
	Write_port_byte(0x21, 0xFF);         

	
	Write_port_byte(0xA0, 0x11);       
	Write_port_byte(0xA1, 0x28);       
	Write_port_byte(0xA1, 0x02);       
	Write_port_byte(0xA1, 0x01);       
	Write_port_byte(0xA1, 0xFF);        
}


void _declspec(naked) interrupt_handler()
{
	_asm pushad;


	_asm {
		popad
		iretd
	}		
}

void Init_IDT()
{
	int i;
	unsigned int high, low;
	
	for(i = 0; i < MAX_IDT; i++ )
	{
		IDT[i].Selector = 0x08;
		if( i < 0x14 )
			IDT[i].Access = 0x8E;		// 예외 인터럽트
	    else
			IDT[i].Access = 0x8F;		// 하드웨어

		IDT[i].Unused = 0x00;

		low = (unsigned int)&interrupt_handler;
		low = low & 0xFFFF;

		high = (unsigned int)&interrupt_handler;
		high = (high >> 16);

		IDT[i].Offset_high = (unsigned short)high;
		IDT[i].Offset_low = (unsigned short)low;
	}

	IDTR.Address = (unsigned int)&IDT;
	IDTR.Size  = MAX_IDT * sizeof( IDTDesc );

	LoadIDTR((unsigned int)&IDTR);
}

void LoadIDTR(unsigned int addr)
{
	_asm
	{
		mov	eax, [addr]
		lidt	[eax]
		sti
	}
}


예전에 키보드 입력 받았던 코드에서 PIC를 초기화 해주고…!!! (하드웨어 인터럽트 발생해야 하니깐…) 컴파일 해서 확인!!!

아무 반응 없다…

뭐… 재부팅 안된것만 해도 다행이다.

키보드 입력을 받았으면 좋겠는데… 피곤해서 오늘은 그냥 여기까지…

다음시간에는 키보드 입력 루틴까지..

 

회사에서 시간 나면 Windows live writer를 이용하여 간간히 블로깅을 했었는데.. 퇴사하면서 계정 정보를 삭제하려 했더니 지워지지가 않더라!~~~ 엠병.

Windows live writer에 계정이 하나 있으면 삭제 안되는 버그(?) 인듯..그렇다고
임의의 블로그 계정을 생성 할 수도 없고…
검색해도 안나오고….

연속 삽질 끝에..

HKEY_CURRENT_USER\Software\Microsoft\Windows Live\Writer\Weblogs

위치에 내 계정 정보가 있었다.

그래서 이걸 삭제하면 되는듯..

 





또 글을 작성하다 보면 엔터를 치면 <P> 태그가 생성된다. 작성 당시에는 보기 좋아도 실제 포스팅 하면 별로 간격이 맘에 들지 않는다.

소스에서 일일이 <P>를 <BR>로 수정하기도 힘들고…

방금 알아냈다..

SHIFT + ENTER 치면 <BR> 태그로 입력되는걸…




+ Recent posts