OS를 만듭시다. 어때요~ 참 쉽죠? (6)
OS. 영어로 풀어서 Operating System. 한자어로 번역해서 운영체제. 이것을 만든다고 하면 사람들은 굉장히 어렵게 생각한다. 리눅스나 윈도우같은 OS를 비교대상으로 본다면 OS를 만드는것은 정말 어렵고 힘들고, 개인이 만들기엔 어쩌면 불가능에 가까운 도전일지도 모른다. 하지만 OS의 기본 개념들은 대학교 학부과정에서 가르칠 정도로 이미 보편화 되어 있고 그 개념 자체들은 그다지 어렵지 않다. 개념 구현을 중심으로 동작하는 것 자체에 의미를 둔 OS를 만드는 것은 어쩌면 도전 해 볼만 한 가치가 있는 시도가 아닐까.
목차
1회
2회
3회
4회
5회
6. OS timer 사용하기
저번 강좌에 이어서 다시 데이터시트를 열어놓자. 이번에 봐야 할 곳은 4.4.2 절에 있는 OS Timer Register Definitions 이다. OS timer 에 관련해서는 4개의 OSMR 과 OIER, OSCR, OSSR 의 이름을 가지는 레지스터들이 존재 한다. 이제부터 저 레지스터들을 어떻게 사용하는지 알아 보도록 하자.
데이터시트에 보면 OS timer 용으로 pxa255 는 3.6864Mhz의 오실레이터 클럭입력을 받는다고 써 있다. 무슨 말인고 하니 1초에 클럭이 3686400 번 뛰는 입력이 들어온다는 것이다. 무슨말인지 몰라도 상관없다. 그냥 여기 까지만 알아두면 나중에 써먹을 수 있으니 3686400 이 1초다 라고만 알아두자.
먼저나오는 레지스터설명은 OSMRx 라고 되어 있다. x 는 번호다. 즉 OSMR0, OSMR1, OSMR2, OSMR3 이렇게 네개의 OS timer Match Register 가 제공된다. 전 강좌에서 설명 했듯이 pxa255는 모두 네개의 OS timer를 제공한다. 여기서도 네개의 Match Register를 제공한다. 뭔가 아귀가 들어 맞지 않는가.
OSMR은 말 그대로 Match Register 이다. 무언가와 값을 맞춰보기 위해 존재하는 레지스터이다. 좀더 자세히 설명하자면 잠시후에 설명할 OSCR의 값이 OSMR에 설정된 값과 일치하게 되면 해당 OS timer 는 인터럽트를 발생시키게 된다. 물론 인터럽트가 그냥 발생되지는 않는다. 바로 다음에 설명할 OIER에 설정이 되어 있어야 한다.
다음은 OIER(Os timer Interrupt Enable Register) 이다. 그냥 레지스터의 이름이 이 레지스터가 무엇을 하는 레지스터인지 딱 말해 준다. 한마디로 인터럽트를 활성화 시켜주는 레지스터이다. pxa255에서 제공하는 OS timer는 네개라고 여러번 강조한다. 그러므로 당연히 OIER에서 세팅할 수 있는 비트도 4개 이다. 각 비트를 1로 하면 해당 비트에 맞는 OS timer 의 인터럽트가 활성화 된다.
밑에 나오는 OWER은 무시하자. 그다음에 나오는 OSCR(OS timer Count Register)은 위에서 말한 3.6864Mhz의 클럭에 맞추어 무조건 1씩 올라가는 레지스터이다. 만약 OSCR의 값이 0 이라면 1초후에는 3686400 이 되어 있다. 당연히 0.1초 후에는 368640 일터이고, 0.01초 후에는 36864 일것이다. 같은 원리로 보다 세밀한 시간 조정이 가능하다.
마지막으로 OSSR(OS timer Status Register) 가 나온다. OSMR 의 값과 OSCR의 값이 같고 그순간에 OIER의 해당 비트가 1로 되어 있으면 OSSR에 1이 세팅된다. 그러면 인터럽트 컨트롤러는 전 강좌에서 설명한 순서를 거쳐서 최종적으로 소프트웨어에게 인터럽트 발생을 알려준다. 그리고 해당 비트에 다시 1을 쓰면 비트가 클리어 된다고 데이터시트에 나와 있다. 레지스터에 0 을 써넣는 것은 아무런 효과가 없다고 친절히 설명되어 있다.
정리해보면, 인터럽트 컨트롤러 관련 레지스터들이 다 세팅되었다는 가정하에 나빌눅스가 사용하려는 1번 OS timer를 1초 간격으로 발생하도록 세팅하고 싶다면, OSMR1 에는 OSCR+3686400 만큼의 값을 세팅해 놓고, OIER의 1번 비트를 1로 세팅한다음 인터럽트가 발생해서 IRQ Exception 핸들러 함수로 들어오고 나면 ICIP 레지시터의 27번 비트 (27번 비트가 1번 OS timer 인터럽트를 표시한는 것을 잊지 말아라) 가 세팅되었는지를 검사한다음 타이머 관련 작업을 해주고 OSSR의 1번 비트 에 1을 써 주어 OSSR을 클리어 한다.
여기까지 기본 지식을 최대한 대충 설명한다고 했는데도 이렇게 길어졌다. 자 이제 코드를 보자. 역시 개발자는 코드를 보는게 마음이 편하다.
void os_timer_init(void) { ICCR = 0x00; ICMR |= (1 << 27); ICLR &= ~(1 << 27); OSCR = 0; OSMR1 = OSCR + 3686400; }
위에서 그렇게도 설명했던 ICCR, ICMR, ICLR, OSMR, OSCR 에 대한 초기화 함수 이다. 이 코드를 보면 뭔가 이상하지 않은가? 이상한점을 발견해야 한다. 아무런 의심없이 위 코드를 받아들이면 안된다! 정말 안되는데... 자! 생각할 시간을 주겠다.
:
:
:
생각 해 봤는가? 발견했으리라 믿는다. 무엇인고 하니 어디선간 선언한적도 없는 것 같은 ICCR이니 ICMR이니 하는 레지스터 이름을 마치 변수인양 그냥 막 쓰고 있다. 분명 선언했다는 말은 없는데 말이다. 컴파일러가 ARM 컴파일러니깐 알아서 해주는 것일까? 절대 그렇지 않다.
다시 데이터시트를 잘 보자. 각 레지스터의 비트 설명하는 네모난 그림 위에 Physical Address 라고 각 레지스터들이 어느 주소에 매핑되어 있는지 나온다. 즉 데이터시트에 나와 있는 저 주소에 포인터 접근을 해야 해당 레지스터에 값을 읽거나 쓸 수 있다는 말이다. 그런데 우리는 그런걸 하나도 해 주지 않았는데 그냥 레지스터 이름으로 접근하고 있다. 어찌된 조화일까.
정답은 하나! 어딘가에 그걸 해 놓은게 있다는 말이다. 다시 상기시켜 보자. 나빌눅스는 처음에 베이스 코드로 이지부트의 소스를 가져왔다. 그럼 이지부트의 소스 어딘가에 레지스터들을 설정해 놓은 파일이 있을 것이다.
역시나 grep으로 찾아도 상관없지만 파일이름을 보고 포스를 느껴보자. include 디렉토리에 있는 pxa255.h 가 왠지 의심 스럽다. 주저하지 말고 열어보자.
: : #define ICCR0 __REG(0x40800000) // ICP Control Register 0 #define ICCR1 __REG(0x40800004) // ICP Control Register 1 #define ICCR2 __REG(0x40800008) // ICP Control Register 2 #define ICDR __REG(0x4080000c) // ICP Data Register #define ICSR0 __REG(0x40800014) // ICP Status Register 0 #define ICSR1 __REG(0x40800018) // ICP Status Register 1 #define OSMR0 __REG(0x40A00000) // #define OSMR1 __REG(0x40A00004) // #define OSMR2 __REG(0x40A00008) // #define OSMR3 __REG(0x40A0000C) // #define OSCR __REG(0x40A00010) // OS Timer Counter Register #define OSSR __REG(0x40A00014) // OS Timer Status Register #define OWER __REG(0x40A00018) // OS Timer Watchdog Enable Register #define OIER __REG(0x40A0001C) // OS Timer Interrupt Enable Register : :
파일 내용만 봐도 굉장히 귀찮아 보이는 작업들이 모두 다 되어 있다. 저렇게 미리 다 define이 되어 있기에 나빌눅스의 소스에서는 아무런 추가작업 없이 그냥 데이터시트에 있는 레지스터 이름을 그대로 가져다가 직관적으로 사용해도 잘 동작하는 것이다. 오픈소스는 참 좋은 것이다.
추가로 ARM프로세서의 IRQ를 활성화 하거나 비활성화 하는 코드와 타이머를 시작시키는 함수를 작성한다. IRQ를 활성화/비활성화 세팅은 cpsr에서 I 플래그를 1로 하면 IRQ까 비활성화 되고 0으로 하면 활성화 된다. 역시나 자세한 내용은 구글에서 ARM의 cpsr에 대해 검색해보면 아주 잘 나와 있다.
void os_timer_start(void) { OIER |= (1<<1); OSSR = OSSR_M1; } void irq_enable(void) { __asm__("msr cpsr_c,#0x40|0x13"); } void irq_disable(void) { __asm__("msr cpsr_c,#0xc0|0x13"); }
OIER 의 1번 비트를 1로 세팅하면 1번 OS timer에 대해 인터럽트를 사용한다는 의미 이다. OSSR 의 1번 비트에 1을 써 주면 비트클리어가 된다. 즉 인터럽트가 클리어 되면서 더불어 ICIP 와 ICPR에 있는 Pending Interrupt 도 클리어 된다. 대기중인 인터럽트를 클리어 해야 인터럽트를 시작 할 수 있다.
irq_enable() 과 irq_disable() 함수는 한줄짜리 어셈블리 코드 이다. cpsr의 I 비트는 7번째 비트이다. 그리고 0~5번 비트는 프로세서 모드 설정이다. 0x13 (1 0011)은 SVC모드로 설정하는 것이다. 그래서 irq_enable 은 cpsr의 7번째 비트를 0으로 하고 하위 5개 비트를 SVC모드로 설정하는 한줄이고, irq_disable 은 cpsr 의 7번째 비트를 1로 하고 하위 5개 비트를 SVC 모드로 설정하는 것이다.
타이머는 OS의 시작과 함께 같이 동작해야 하므로 main()함수의 시작 부분에 초기화 코드를 호출하는 한줄을 넣어주자.
int main(void) { os_timer_init(); os_timer_start(); irq_enable(); while(1){ __asm__("swi 77"); msleep(1000); } return 0; }
이제 나빌눅스가 부팅되면서 타이머를 초기화 할 것이다. 하지만 초기화만 했다고 사용할 수 있느냐. 당연히 아니다. 핸들러 함수를 작성해 주어야 한다. navilnux.c 에 있는 irqHandler 함수를 수정하자.
void irqHandler(void) { if( (ICIP&(1<<27)) != 0 ){ OSMR1 = OSCR + 3686400; printf("Timer Interrupt!!!\n"); OSSR = OSSR_M1; } }
IRQ가 뜨면 일단 무조건 irqHandler 함수 까지는 들어 간다. 그럼 어떤 IRQ인지는 핸들러 함수에서 결정해야 한다. IRQ 인터럽트는 최종적으로 ICIP에 기록된다고 하였다. OS timer는 27번 비트라 하였다. 그렇다면 ICIP의 27번 비트가 1인지 확인하면 OS timer가 발생해서 들어온건지 알 수 있다. 위 코드에서는 그냥 타이머가 발생했음을 알기 위해 메시지 한줄 출력한다. 우리가 목표로 하는 나빌눅스 설계범위 안에서도 실제 타이머 핸들러 안에서는 커널전역타이머카운터를 올리는 작업과 스케줄러를 호출하는 부분정도가 타이머 핸들러 안에서 해주어야 하는 일일 것이다.
자! 이제 빌드하고 보드에 올려보면 동작할것인가. 아직 조금더 남았다. 인내심을 가져라. Software Interrupt 부분을 작업할때 다루웠던 것 처럼 Core_irqHandler 부분에 어셈블리 코드도 작성 해 주어야 한다. Core_swiHandler 를 보고 작성하면 된다. 하지만 entry.S 의 코드가 전체적으로 조금 많이 바뀌었다. 일단 코드를 보자
.globl _ram_entry _ram_entry: b kernel_init b _ram_entry b Core_swiHandler b Core_irqHandler #define svc_stack 0xa0300000 #define irq_stack 0xa0380000 #define sys_stack 0xa0400000 .global kernel_init kernel_init: msr cpsr_c,#0xc0|0x13 //SVC mode ldr r0,=svc_stack sub sp,r0,#4 msr cpsr_c,#0xc0|0x12 //IRQ mode ldr r0,=irq_stack sub sp,r0,#4 msr cpsr_c,#0xc0|0x1f //SYSTEM mode ldr r0,=sys_stack sub sp,r0,#4 msr cpsr_c,#0xc0|0x13 bl main b _ram_entry .global Core_swiHandler Core_swiHandler: stmfd sp!,{r0-r12,r14} mrs r1,spsr stmfd sp!,{r1} ldr r10,[lr,#-4] bic r10,r10,#0xff000000 mov r0,r10 bl swiHandler ldmfd sp!,{r1} msr spsr_cxsf,r1 ldmfd sp!,{r0-r12,pc}^ .global Core_irqHandler Core_irqHandler: sub lr,lr,#4 stmfd sp!,{lr} stmfd sp!,{r0-r14}^ mrs r1,spsr stmfd sp!,{r1} bl irqHandler ldmfd sp!,{r1} msr spsr_cxsf,r1 ldmfd sp!,{r0-r14}^ ldmfd sp!,{pc}^
entry.S 의 내용이 뭔가 조금 많아지지 않았는가? Software Interrupt 를 처리할때는 ARM 이 기본 모드가 SVC라서 swi 로 인터럽트 핸들러로 들어간다 하여도 같은 SVC모드이기 때문에 그다지 세심한 주의를 기울이지 않아도 동작을 하였는데, IRQ 는 모드가 바뀌기 때문에 결정적으로 r13(sp)레지스터를 세팅해주어야 한다. 그러지 않는다면 동작을 예상 할 수 없다. (보통 그냥 멈춰 버린다.)
그래서 이전에는 _ram_entry 에서 바로 main() 함수로 진입했지만 이번부터는 kernel_init 레이블로 가서 각 모드별 스택영역을 초기화 해 준 다음 main() 함수로 들어가게 된다. 각 모드별 스택영역에 대한 내용은 다음 강좌에서 다룰 메모리 맵 부분에서 자세히 설명할 예정이니 지금은 저 코드를 그대로 받아들이기 바란다.
Core_irqHandler 는 전체적으로 봤을때 Core_swiHandler 와 크게 다르지 않다. 세세한 부분이 조금 다를 뿐이다. 우선 리턴어드레스를 가지고 있는 lr 에서 4바이트를 뺀다. 이유는 swi 명령을 이용해서 인터럽트에 진입하는 Software Interrupt 와 하드웨어적으로 발생하는 IRQ와의 결정적인 차이 때문이다.
이를 이해 하기 위해서는 ARM 의 pipe line 구조와 각 Exception 이 발생하는 시점에 대한 이해가 필요하다. 여기서 필요 한 것은 Software Interrupt와 IRQ뿐이므로 그 둘에 대해서만 설명 하겠다.
본 강좌에서 나빌눅스의 타겟 플랫폼은 pxa255칩이다. pxa255 칩은 ARM9 아키텍쳐 이다. ARM9 아키텍쳐는 5단계 pipe line 구조를 가진다. 5단계 pipe line 은 아래와 같다.
Fetch - Decode - Execute - Memory - WriteBack
Fetch 단계는 메모리에서 ARM 명령어 만큼의 4byte를 읽어오는 작업이고 Decode 는 읽어온 명령이 어떤 instruction 인지 구분하는 작업을 한다. 여기서 instruction과 매개변수등을 구분한다. Execute는 해당 instruction을 실제로 수행하는 작업(더하기, 빼기등)을 한다. Memory 는 메모리로 부터 데이터를 읽어오는 과정이고 WriteBack은 결과를 레지스터에 쓰는 작업이다.
5단계 파이프라인이 각각 무엇을 하는지는 물론 중요하지만 나빌눅스를 제작하는데 있어서는 그다지 중요하지 않다. 우리가 관심을 가지는 것은 바로 다섯단계에 걸쳐서 명령어가 파이프라인을 이동한다는 것이다.
PC는 현재 실행중인 명령 바로 다음 명령어를 가르킨다고 했다. 맞는말이다. 하지만 파이프라인 수준으로 좀더 가까이 다가가 보면 현재 실행중인 명령 바로 다음 명령은 Decode 상태에 있는 명령이다. 정확히 말하면 PC는 Fetch 단계 바로 앞의 명령을 가르키고 있다.
그리고 ARM 은 Exception 이 발생하여 프로세서 동작모드가 변할때에 하드웨어적으로 현재 pc에서 4를 뺀 값을 변환되는 동작모드의 lr 로 자동으로 복사한다. 예를 들어 user 모드에서 swi 로 Software Interrupt가 발생한다면
lr_svc = pc - 4
위와 같은 작업이 하드웨어 적으로 이루워진다.
: : add r0,r0,#3 swi 77 sub r1,r0,#2 orr r0,r0,#0xff : :
SWI 명령은 연산작업을 필요로 하지 않는다. ARM core 가 SWI라는 명령을 알아차리는 그 순간 Software Interrupt를 발생시키면 된다. 그래서 SWI는 Execute 단계가 아니라 Decode 가 끝나는 단계에서 발생한다. 위의 코드를 예를 들자면, SWI 77명령이 Decode 단계가 끝나는 지점에 있게 되면 PC는 orr r0,r0,#0xff 명령의 주소를 가지고 있다. 그리고 Decode 가 끝나는 시점에서 SWI 로 인해 Software Interrupt 가 발생하게 되면, 하드웨어 적으로 pc-4 의 값이 lr_svc 에 복사 되므로, lr_svc 에는 sub r1,r0,#2 가 들어가게 된다. SWI 를 하고 Software Interrupt 에 들어갔다가 복귀 하고 나서 다시 실행해야 할 명령은 sub r1,r0,#2 이므로 복귀 할때 lr 을 그대로 사용하는 것이다.
하지만 IRQ의 경우는 조금 다르다.
: : add r0,r0,#3 and r0,r0,#0x8f <---- 여기를 하다가 IRQ 발생 sub r1,r0,#2 orr r0,r0,#0xff add r0,r0,#1 : :
IRQ와 FIQ는 5단계 pipe line 에서 Execute 가 완료되는 시점마다 한번씩 검사를 하게 된다. 그래서 위 코드처럼 and r0,r0,#0x8f 에서 IRQ 가 발생한다는 것은 and r0,r0,#0x8f 가 완전히 Execute 되고 나서 Memory 단계의 pipe line 으로 넘어갈때에 Exception 이 발생한다.
Execute 단계가 끝나는 시점에서의 pc 는 위 코드의 경우라면 add r0,r0,#1 위치에 있게 된다. Exception 이 발생하고 Execute 가 끝나는 시점에서 IRQ Exception 이 서비스되는 순간 lr_irq 에는 pc-4 의 값이 들어가므로, lr_irq 에는 orr r0,r0,#0xff 에 해당하는 메모리 영역주소값이 들어가게 된다. 하지만 IRQ Exception 을 처리하고 나서 복귀하여 수행 해야 할 명령은 sub r1,r0,#2 이다. 그러므로 IRQ 에서 복귀 할때는 lr_irq 의 값을 그대로 사용하는 것이 아니라 lr_irq - 4 를 하여, IRQ Exception 이 발생한 명령 바로 직전 명령어로 pc 가 되돌아가게끔 조정 해 주는 것이다.
이렇게 SWI 와 IRQ 에서의 복귀주소에 대한의문은 풀었다. 이제 Exception 모드에 진입하기 직전의 컨텍스트 상태를 백업하고 리스토아 하는 작업을 하면 되는 것이다. 좀더 자세한 내용은 이후에 컨텍스트 스위칭을 설명할때 할것이니 본 편에서는 그냥 맛배기로 받아들이기 바란다.
USER모드의 레지스터를 스택에 복사한다. stmfd 할때 뒤에 꺽쇠(^)를 붙이면 복사대상 레지스터는 USER모드의 레지스터가 된다. Core_irqHandler 는 현재 IRQ 모드이다. IRQ모드에서 USER모드의 레지스터를 백업,복구할려면 뒤에다가 ^를 붙여서 주소지정을 해 주어야 한다.
Core_swiHandler 와 마찬가지로 spsr 을 백업한다음 irqHandler 로 들어가서 관련 처리를 하고, 나오면서 스택에 백업한 역순으로 복구 한다. 그런다음 이전 실행위치로 되돌아 간다.
자! 이제 나빌눅스는 OS timer 를 갖추게 되었다. 조금씩 OS에 가까워 지고 있다. 빌드 한 다음 보드에 올려서 부팅 해 보자 아래와 같은 실행 결과를 얻을 것이다.
system call 77 Timer Interrupt!!! system call 77 Timer Interrupt!!! system call 77 Timer Interrupt!!! system call 77 Timer Interrupt!!! system call 77 Timer Interrupt!!! system call 77 Timer Interrupt!!! system call 77
Software Interrupt 는 msleep() 에 의해서 무한루프를 돌면서 1초에 한번씩 실행되고, OS timer 는 OSMR의 값을 3686400 마다 Match 되게 하였으므로 역시 1초에 한번씩 실행된다. 결과적으로 번갈아 나오게 된다.
다음편에서는 본격적인 커널 작성에 앞서 메모리 맵을 설계 해 보도록 하자.
이번 회 강좌에서는 나빌눅스의 코드를 수정하였다. 현 강좌 진행부분 만큼의 수정되 코드를 첨부 하오니, 강좌를 이해하는데 도움이 되었으면 한다.
이 글은 http://raonlife.com/navilera/blog/view/80/ 에 동시 연재 됩니다.
첨부 | 파일 크기 |
---|---|
navilnux_chap6.tgz | 75.08 KB |
댓글
6편이 떴군요 ^^ 돈이
6편이 떴군요 ^^
돈이 없는 저는,,, 빨리 이 강의가 완결되고
에뮬레이터 편으로 넘어가기를 목빠지게 기다리고 있답니다 ☆_☆
그러면 거기서는 GRUB을 고치는게 되겠네요 ㅎㅎㅎ;;
연재가
연재가 끝나고
에뮬레이터 포팅을 꼭 하지는 않습니다.
다만 고려 사항중 하나일 뿐이지요.
왜냐하면, 저도 에뮬레이터는 사용 해 본적이 없거든요..^^;
조금 저렴한 (4~5만원) 보드에 포팅은 진지하게 고려 중입니다.
---
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
이번편도
이번편도 잘봤습니다.
고생이 많으세요.. ㅎ 감사합니다.
--------------------------------------
으휴
mail@ystory.kr
--------------------------------------
으휴
조금씩 짬내서 보고 있습니다만.
이런 저런 일을 하다가, 문득...
큰 제목만 쭉 적어보면 어떨까 싶습니다.
이런 식이겠죠.
1. Hello, World
시리얼로 "Hello, World\r\n"를 계속 찍는다.
2. LED를 켠다.
시리얼로 메시지를 보내는 대신 LED를 켜거나 깜빡인다.
3. 인터럽트 핸들러를 만든다.
swi에 제대로 응답하는 핸들러를 만든다.
4. 타이머를 돌린다.
100ms? 10ms? 주기적으로 돌아가는 타이머를 만들어본다.
...
OS를 만들거나 포팅하거나 하는 작업을 보면, 아주 아래단이나 아주 윗단은
책들도 많고 정보도 많은데, 그 가운데 단에 대한 글이 없어서 다가가기가
쉽지 않은 것 같습니다. 이런 말하는 저도 대충 손만 대다가 여러가지 이유로
그만 두고는 하는데요.
위에 네개를 만든 다음에, 위 네개와 비슷한 정도로 다음 강의를 하려면
뭘 해야될지 저로서는 잘 생각이 안나네요. 저기서 컨텍스트 스위칭을 바로
해버리면 갑자기 난이도가 올라갈 것 같다는 생각도 들고, 뭐, 그정도면
사실 어려운건 아니니까 쉽게 넘어갈 것 같다는 생각도 들고...
적당히 알고 있는 후배들한테 숙제로 줄 수 있는 정도로 OS 만들기를 잘게
나눠본다면 "참 쉽게" OS를 만들 수 있지 않을까 생각해봅니다.
짬내서 제가 해볼 생각이긴 하지만, 저보다 뛰어나신 분들이 혹시나 해주시지
않을까 생각하면서(^^;) 딴엔 아이디어라고 올려봅니다. 좀 모자라더라도... ^^;
--------------------------------------
재미없는 일은 하지 말자는 인간 쓰레기.
-.-;
--------------------------------------
재미없는 일은 하지 말자는 인간 쓰레기.
-.-;
인용: 적당히 알고
감사합니다. antibug 님의 저 한문장은 제가 만들고 있는 OS 와 이 강좌의 정체성을 잘 설명한 한 문장이라고 볼 수 있습니다.
이미 저는 OS를 다 만들어 놓은 상태에서, 강좌에 맞게 OS 코드를 최소화 하고,
OS자체의 개념적 구현외에 부가적으로 따라가는 여러가지 예외처리 부분등은 모두 없앤채로
가장 최소화한 코드를 만들어가는 과정을 지금 연재중인 강좌로 설명하고 있습니다.
언젠가는 강좌가 끝이 날터이고, 그때에 antibug 님이 만족할만한 강좌로 끝이 났으면 좋겠네요.. :)
--------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
:)
잘보고있어요. 수고많으시네요;
이렇게 꾸준히 쓰기가; 참 쉬운일이 아니던데 말이죠 +ㅅ+ 으히히.
개인적으로는 컨텍스트 스위칭 부터 막혓었던지라 ㅠㅠ 빨리 그부분에대해서 써주시길 고대하고 있습니다 ㅠㅠ
======================================
솔직함은 배려의 측면에서 보면 양날의 칼이다.
강의 너무 잘보고
강의 너무 잘보고 있습니다. 감사합니다.
ldm을 사용할 때 ^의 용도가 내용에 없어서 첨부 기록합니다.
ldm에서 ^는 pc가 register에 있다면 spsr을 cpsr로 복사해주는 역활을 합니다. 주로 특권 모드에서
user모드로 복귀할 때 많이 사용합니다. 만약 pc가 없다면 {}안의 레지스터들이 user모드의 레지스터란 이야기입니다.
stm에서 ^와 pc의 사용은 implementation defined입니다. 자세한 내용은 arm reference manual을 보시면 됩니다.
그리고, 익셉션 발생시 pc값의 설명은 초보자를 위해 하신 부분 같지만 제가 아는 것과 달라 말씀드립니다.
( 아래 내용은 arm 9에서 유효한 내용입니다. 제가 arm 11은 전혀 몰라사요. )
arm에서 IRQ, FIQ 익셉션의 발생은 pipe의 excution 완료시점에서 체크를 합니다.
그 당시 이미 pc 값은 pc+12의 값으로 되어 있습니다. arm 9이 5단 pipe이므로 F-D-E-M-W 라고 할때
E단계에 있을 때 이미 pc값은 F단계를 가르키고 있어야 하므로 이미 PC+8이 됩니다.
E 단계가 끝나는 시점에서는 이미 PC+12가 되고 ARM은 LR을 저장할 떄 pc-4의 값이 저장되도록 하드위에적으로 구성되어
있습니다. 따라서 IRQ, FIQ 익셉션 발생시 lr에 저장되는 값은 다음에 저장할 명령어 주소 + 4가 됩니다.
add r0,r0,#3
sub r1,r0,#2
swi 77
orr r0,r0,#0xff
:
위 예제에서 sub r1,r0, #2를 실행하고 있다면 pc값은 orr r0,r0, #0xff를 가르키고 있습니다.
sub r1,r0, #2 실행중에 IRQ, FIQ 익셉션이 발생했다면, 이 명령의 excution의 완료 단계에서 IRQ, FIQ의 발생여부를 체크하게 \
됩니다. 이 상태에서 PC는sub r1,r0, #2 + 12를 가르키고 있습니다. lr에는 arm 이 알아서 -4를 해서
orr r0,r0,#0xff 를 카르키게 합니다.
설명이 좀 부실한것 같습니다. 고수님께서 좀 수정해주세요. 혹시 틀린 부분 있으시면 수정해주시구요.
다시 한번 강의 감사드리구요. 절대 꼬투리 잡을려고 쓴 글 아니니 오해하지 말아 주시기 바랍니다.
즐거운 하루 되세요.
감사합니다. ^ 에
감사합니다.
^ 에 해당하는 주소지정방식에 대한 설명은 나중에 컨텍스트 스위칭을 설명할때 쓰려고 했었는데, 역시나 지적을 받네요...^^;
그리고 익셉션 발생시 pc 값에 대한 설명은 저도 어설프게 알고 있던 지식을 바로 잡아 주셔서 감사합니다. 혹시나 문제가 되지 않는다면 익명님의 해당 설명을 강좌 본문에 포함시켜 수정 시켜도 되겠습니까?
댓글로 허락해 주신다면 본문 수정하겠습니다.
읽어주시고 지적해 주셔서 다시 한번 감사합니다.
-----
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
익명으로 글을 쓸
익명으로 글을 쓸 생각이 아니었는데 익명으로 글이 올라갔습니다.
죄송합니다. 강좌 감사드리구요. 유익한 내용은 아니지만 강좌에 포함시켜 주신다니
제가 영광입니다. 다시 제 댓글을 보니 이해가 어려운데 나빌레라 님께서 정리해주시면
다른 분들에게도 좋을 것 같습니다. 특히 제 글에서 pc와 excution 단계의 주소가
참 헛갈리게 글이 작성되었습니다. 제가 말주변이 없어서 설명이 어려운 것 같습니다.
다시 한번 강좌 감사드리구요 다음 강좌 기대하겠습니다.
즐거운 하루 되세요.
본문 수정
본문 수정 하였습니다. ^^;
감사합니다.
덕분에 pipe line 과 그에 따른
exception mode 별 복귀주소에 대해 진지하게 공부해 볼 기회가 되었습니다.
다시 한번 감사합니다.
---
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라
강의를 따라하는 학생입니다.^^
안녕하세요^^
일주일전부터 메일을 몇차례 드려도 답문이 없어서 답답한마음에 실례를 무릅쓰고 여기에 글을 남깁니다...
기분이 나쁘시다면 삭제하셔도 됩니다..ㅜ.ㅜ
다름이 아니오라, 다른 보드(S3C2440)을 사용하여 구현하는데 있어서 OS TIMER 가아닌 PWM TIMER를 사용하는데,
타이머구현부분은 수행이되는데, 컨텍스트 스위칭이 않되서 WHILE문수행이 되지 않는것 같습니다.
컨텍스트 스위칭에 대해서 자세한 설명좀 부탁드릴수 있을까해서 글을 남깁니다...ㅠ
부탁드립니다...ㅠ
댓글 달기