Data Processing Instructions

Comparisons ( no results - just set condition codes )

 

'비교'를 '산술 연산' 다음에서야 다루는 이유는 '비교'에서 절대 빠질 수 없는 CPSR에 대한 개념을 '산술 연산'에서 한번 다루고 그때 배운 CPSR 개념을 사용해서 '비교'를 더 제대로 배우기 위함이다. '산술 연산'에서 CPSR 을 사용할때 어떤 방법을 사용하였는지 기억하는가? 

 

접미사 (Postfix) 'S' 를 산술 연산에 관련된 Instruction 에 붙여서 '산술 연산'을 진행시킨다음 그 결과로 나온 값에 대한 여러 특징들을 살펴보고, 각각 특정 조건을 갖는가?(1) 갖지 않는가?(0) 등의 조건에 대한 Flag 들을 세팅하고 이렇게 세팅된 Flag 값들은 다음 라인부터 사용 가능했다. 이 정도는 기억할 수 있을꺼라 믿는다!

 

   1. No postfix 'S' is needed

그런데 Comparison 은 Postfix 'S' 가 필요없다. 그냥 '비교' Instruction 자체가 'S' 를 포함하고 있다고 생각하면 된다. [ CMP = 'CMPS 이렇게 S를 포함하여 쓴거하고 똑같다고 보면 된다.' ] 아래 Operation 들을 보면 '비교'를 진행시킴과 동시에 그 결과로 나온 값을 이용하여, 여러 특징들을 갖는가? 갖지않는가? 등의 조건에 대한 Flag 들을 세팅하고 이렇게 세팅된 Flag 값들은 다음 라인부터 사용 가능하다는 것을 알 수 있다. ( postfix 'S'를 쓰지 않았지만, CPSR 의 조건 Flag 사용법과 완전 똑같다. )

 

   2. No destination register is required

그리고 우리가 rd 로 사용해 왔던 Destination register 가 이 '비교'에서는 필요가 없다. CMP에 대한 결과값을 Destination register (연산의 결과가 들어갈 목적 레지스터) 에 저장하는것이 아니라, CPSR의 Flag bits 자리에 넣기 때문이다. 그렇기 때문에 이 Instruction 을 사용할 때는 간단하게 비교할 두 대상만 써주면 된다. ( XXX r1, r2 / r1 : 비교될 대상 1, r2 : 비교될 대상 2 )

 

시스템 프로그래밍 - 4 (3) : Data Processing Instructions - Comparisons 

 

 

 - Operations

 

-    CMP    r0, r1         @ r0 - r1 to set flags

     r0 과 r1 을 비교한다 (비교 방법은 r0에서 r1 값을 뺀다) 그리고 그 결과에 대한 Flag 들을 설정한다.

 

-    CMN    r0, #9        @ r0 + 9 to set flags

     뒤엣 #9 (또는 레지스터 값이 들어올 수 있다)를 NOT 시킨 결과를 r0 에서 빼준다.

결국엔 #9 를 r0 에서 더해주는 연산과 다를바가 없다. 그리고 그 결과에 대한 Flag 들을 설정한다.

 

-    TST     r0, #4         @ r0 & 0100(2진수) to set flags

     r0과 #4 (또는 레지스터 값이 들어올 수 있다)를 2 진수 연산인 AND 를 시킨다.

그리고 그 결과에 대한 Flag 들을 설정한다.

 

-    TEQ     r0, r1         @ r0 ^ r1 to set flags

r0과 r1를 2 진수 연산인 OR 를 시킨다. 그리고 그 결과에 대한 Flag 들을 설정한다.

 

 

 

 - Branch Instructions

 

C 언어에서는 프로그램을 작성할 때 여러 함수들을 main 함수와 분리시켜 놓고, main 함수에서 특정한 기능들이 필요할 때 마다 우리가 만들어 놓았던 여러 함수들을 호출하면, 컴퓨터는 C 언어를 위에서 아래로 쭉 읽어나가다가 호출된 함수로 이동해서 해당 함수의 작업들을 끝내고, 다시 원래 읽어나가고 있던 자리로 돌아온다.

 

우리가 배우고 있는 이 ARM 프로그래밍 (시스템 프로그래밍)은 알다시피 '어셈블리어'이다. C 언어와 같이 우리가 고수준 언어로 여러 함수들을 호출, 리턴하는 작업들을 간단하게 작성했던것과 달리 우리는 컴퓨터의 작동 원리를 그대로 따라서 (컴퓨터처럼 생각해야한다.) 하나하나 일일이 다 작업해주어야한다.

 

  - 특정 함수를 호출하면 어느 Line에 그 함수가 있는지 알아내어 그 Line 으로 가라고 명령해야하고,

 

  - 리턴할때는 어떤 Line 으로 가야지 월래 컴퓨터가 실행하던 라인으로 다시 돌아가는지 알려주어야한다.

 

마치, 'A칸부터 D칸까지 순서대로 있는 책장'을 가리키며 갑이 을에게 '책장 C칸에 있는 'Hello'이라는 제목을 가진 책좀 가져다 줄래?' 라는 말을 '책장을 보면 오른쪽부터 왼쪽까지 A, B, C, D 칸이 있어, 거기서 오른쪽에서 순서대로 세 칸을 이동하면 거기에 C 칸이 존재하는데, 그 C 칸에서 오른쪽부터 123번째에 있는 책이 'Hello'이라는 제목을 가지고 있을거야. 그 책을 나에게 가져다 줘' 라고 귀찮게 일일이 다 말해주어야하는것과 같다.

 

Branch는 이 귀찮은 작업들을 조금 더 유용하게 해준다.

Branch Instruction 을 사용하기 위해서는 'Label' 과 'Branch'. 이 두 개를 이용한다.

 

 

 

 - Label

 

'책장을 보면 오른쪽부터 왼쪽까지 A, B, C, D 칸이 있어.'

'C칸에서 오른쪽부터 123번째에 있는 책이 'Hello'이라는 제목을 가지고 있을꺼야.'

 

Label 은 함수가 존재하는 Line 을 '2388 번째 Line' 이렇게 일일이 숫자를 붙혀 표현하면 힘들기 때문에 해당 2388번 Line에 말 그대로 Label (이름표)을 달아주는 것이다. 123 번째에는 Hello 라는 이름표를 붙여주어, 나중에 Hello 라는 책을 찾을때 몇 번째에 있는지 일일이 다 세어보지 않고서도 Label (이름표)를 찾기만 하면 된다.

 

 

 

 

 - Branch (B, BL)

 

Branch 의 언어적인 뜻은 '나뭇가지'이다. 어셈블리어에서 branch는 C 언어에서의 goto 와 비슷한 것으로 '위에서 아래로'라는 일반적인 컴퓨터의 실행 흐름에서 특정한 장소로 실행 위치를 이동하기 위함이다.

 

C 언어에서는 권장하지 않는 goto 문의 기능을 왜 어셈블리어에서는 굉장히 중요한 명령어로 취급할까? 그 이유는 바로 어셈블리어의 특징에 있다. 컴퓨터가 읽기 쉬운 형태로 만들어놓은 어셈블리어에는 자동적으로 실행 위치를 바꾸어주는(for while switch 등등) 복잡한 고급언어에 존재하는 명령어들이 없다.

 

for 이든 while 이든 switch 이든 실행라인 위치를 자동으로 변환시켜주는 이러한 고급언어의 명령어들은 실제로 어셈블리어로 어셈블리 되면, Branch 라는 (goto 와 유사) 명령어를 통해 일일이 '실행라인 이동 명령'들의 집합으로 구성되게 된다. Branch을 필요로 하는 상황들은 아래와 같다.

 

 

1. 컴퓨터의 일반적인 실행 방향인 '위에서 아래로'에서 특정한 조건에 따라 실행하기 싫은 Instruction 이 중간에 있다면, 그 Instruction을 뛰어 넘어야 할때 (예를 들어, 어떤 값이 음수이면 어떤 명령어는 실행하지 말아야할 때)

 

2. 특정한 위치에 내가 사용하고 싶은 특정한 Instruction 을 만들어 놓고, 그 Instruction 을 이용하고 싶을때 마다 그 Instruction의 위치로 이동하여 그것을 실행하고 싶을 때 (마치, C언어에서 함수를 호출하는 방법과 유사하다)

 

3. 혹은, 위에서 아래로 순서대로 읽어서 실행하는 어셈블리어에 있어서, 반복문 (Loop 문)을 넣고싶을 때, 한번 그 반복문을 돌고나서 반복문의 끝부분에서 다시 반복문의 처음부분으로 넘어가야할 상황. ( C 언어에서는 간단하게 for 나 while 문을 이용해서 { } 로 필드를 구성해주면 알아서 그 안에서 반복하게 되지만, 이 고급언어가 어셈블리어로 변환되면 컴퓨터가 읽기 위한 어셈블리어에는 이렇게 { } 필드 구성이 없게된다. 그래서 반복문의 끝 부분에 Branch를 넣어서 '반복문의 첫 부분으로 이동하라!' 라는 명령을 넣어야지만이 처음으로 돌아가 반복문을 반복 수행하게 된다. )

 

우리는 이 Branch에 (2)와 (3)의 첫 부분인 Comparison 와 Arithmetics operation 에서 배운 CPSR의 Condition Flag 값들을 이용해 Branch 라인의 전 라인의 Instruction 에서의 연산(혹은 비교) 결과 값이 음수인지 아닌지? (N Flag), 0인지 0이 아닌 값인지? (Z Flag)... 등등의 특징들을 조건으로 부가해줄수 있다. 

 

LOOP:   CMP     r0, #10            @ CMP 의 결과(r0 - #10)에 대한 Condition Flag 가 세팅된다.

BEQ     LOOP              @ r0 - #10 의 결과가 '0' 이라면 같다는 뜻이다 ( EQ 의 의미 )

    @ '0' 이면 (같으면) 'Z Flag = 1'로 세팅, EQ 는 'Z Flag = 1'이면 실행한다

    @ Z Flag = 1 (비교 결과 같다) > EQ 만족 > LOOP 의 Label로 이동하라

    @                                                   (이것이 Branch 의 의미)

 

@ EQ 는 오직 'Z Flag' 가 1인지 0인지만을 판단하는 조건이다.

 

N, Z, C, V 이 조건 Flag 들의 조합에 따라 다양한 '조건'들을 만들어 낼 수 있다.

N = 0, Z = 1, C = 1, V = 0        ( = 0110 라고 CPSR의 최상위 비트(MSB)의 4bits 자리에 새겨진다.)

이런 방식으로 0111, 0100, 1010 ... 많은 조건들을 단순하게 인간이 이해할 수 있는 표현언어로 만들었다.

이렇게 만들어진 표현언어는 <cond> (=Condition, 조건) 자리에 '조건'으로 자리잡게된다.

 

Branch 사용법, 표현법 :   

B<cond> LABEL

@ B = Branch

 

예시:

LOOP:     CMP      r0, #10

BEQ       LOOP

 

 

<cond>에 들어갈 Condition Field - 모든 조건들 모음 :

 

After CMP, CMN ...

 

EQ : equal                                                    NE : not equal

 

HS : unsigned higher or same                            GE : signed greater or equal

HI : unsigned higher                                       GT : signed greater

 

LS : unsigned lower or same                              LE : signed less or equal

LO : unsigned lower                                        LT : signed less

 

 

After TST, TEQ ... or Numeric Operation with S postfix

 

EQ : zero                                                     NE : non-zero

 

CS : carry-bit set                                            VS : overflow

CC : carry-bit clear                                          VC : no overflow

 

MI : negative                                                PL : positive or zero

 

[ 조건 조합에 관한 블로그 : http://blog.naver.com/yosiba?Redirect=Log&logNo=60058803504 ]

 

 

Branch 확장 - Procedure Call (프로시져 콜) Basic :

BL<cond> LABEL

@ BL = Boy's Love (xD) = Branch with Link

...

...

MOV pc, lr

@ 돌아갈때 lr 에 저장해두었던 LABEL 다음 Line 을 pc에다 넣는다.

그냥 Branch 는 B 뒤에 LABEL 로 이동하는 작업'만' 한다. 그런데 BL 은 뜻에서도 알 수 있듯이 B 뒤에 LABEL 로 이동함과 '동시에' BL 명령어 다음 Line 을 저장한다. 예를 들어 BL 이 Line 30 번에 있으면 Line 31번 을 lr 에 복사해 넣고, 이동한 LABEL ( Line 55라고 가정, LABEL의 끝은 Line 60 이라고 가정 )에서 모든 작업이 끝나면 lr 에 저장되었던 Line 31를 바로 pc에 넣는다. pc 값은 'Line 60' 이었다가 'Line 31'로 바뀌어서 다시 BL<cond> LABEL 다음 Instruction 으로 이동하게 된다.

 

예시:

                    BL         FUNC

                 ...

FUNC:         ...

                 ...

         MOV      pc, lr

 

 

 

 

 - Pointer Initialization

 

Branch 말고도 LABEL 을 이용하는 Instruction 이 하나 또 있다. Pointer Initialization 이라고 하며, 프로그램의 끝 부분에 여러 문자들이나 문장들을 써넣으면 그 문장을 특정 메모리 주소에 저장하고 포인터를 갖게 되는데 그 포인터(주소)를 우리가 원하는 레지스터(예를 들어, r1 과 같은)에 저장하는 것이다.

 

Pointer Initialization 사용법, 표현법 :

ADR      rd, LABEL

 

예시:

ADR           r0, HELLO

......

HELLO:                                         

.asciz "Hello, world! \n"

 

ADR 은 실제로는 ARM Instruction 가 아니라 ADD 와 같은 다른 Instruction 들의 조합으로 만들어(emulated) pseudo Instruction (수도, 가짜 명령어) 이다.

 

지금까지 (1), (2), (3) 에 걸쳐서 Data Processing Instruction 들에 대하여 알아보았다. 이 4장을 통해 우리는 이제서야 제대로 된 ARM 프로그래밍을 할 수 있다. 지금까지 배운 명령어들과 1, 2, 3에서 배운 기초적이면서도 매우 basic한 지식들을 기반으로 ARM Assembly Language 를 이용해서 몇 간단한 프로그램을 작성할것이다.

 

Hello, World 출력 프로그램과  Hello, World 구문의 길이(String Length)를 계산하는 프로그램.

 

4장을 시작할때 ARM Instruction 은 매우 방대한데, Data Processing Instruction 이 전체 ARM Instruction 의 대부분을 차지한다고 설명하였었다. 다음 장은 4장에서 배운 Data Processing 관련 명령어가 아닌 기타 다른 Basic ARM Instruction 에 대해 알아보고 우리가 작성한 위 2개의 간단한 프로그램보다 조금더 복잡한 (추가로 배울 Basic ARM Instruction 들을 더 추가로 사용하여 작성한) 프로그램들을 살펴볼것이다.

 

 

 

 

 

 

Posted by 하늘_


 

Data Processing Instructions

Arithmetic Operations

 

앞에서는 논리적인 연산들 (Bolean / AND (&), OR (^) 등) 에 대해 알아보았다. 이번에는 논리 연산이 아닌 직접적인 수와 수 사이의 산술에 대한 연산 ( ADD (+), SUB (-)) 들에 대해 알아볼것이다.

 

시스템 프로그래밍 - 4 (1) : Data Processing Instructions - Logical operations

 

+ 모든 Data Processing Instructions 은 오직 레지스터에서만 실행된다. 절대로 메모리에서 실행되지 않는다.

 

 - Basic Arithmetic Operations

 

Add : 덧셈

-    ADD    r0, r1, r2        @ r0 := memory [r5]

 

Subtract : 뺄셈

-    SUB     r0, r1, #3       @ r0 := memory [r5]

 

Reverse Subtract : 역 뺄셈

-    RSB     r0, r1, r2        @ r0 := memory [r5]

 

  왜? Subtract 가 있는데 Reverse-Subtract 라는 것을 따로 만들었을까?

이유는, 모든 Instruction 들은 기본적인 사용 형식이 있다. ( 4 (1)에서 설명 ) XXX rd, rm, op 와 같이 각각 rd, rm, op 에 들어갈 수 있는 것들이 따로 정의되어 있는데 rm 의 부분에는 #3과 같은 상수값이 들어갈 수가 없다 (오직 레지스터만 들어갈 수 있다.). 그래서 SUB r0, r1, #3 대신 SUB r0, #3, r1 이렇게 자리를 바꾸어서 [ 상수(#7) - 레지스터안의 값(r1) ] 형태로 SUB을 쓸 수 없기에 RSB를 사용하는 것이다. 

 

 

 

 - Condition Code Flags

 

Condition 은 굉장히 중요한 부분이면서, ARM 프로그래밍에 있어서 여러 코드들을 프로그래머 마음대로 이용할 수 있게 만들어 주는 유용한 코드이다. Condition 코드는 다른 Instruction set 들과 똑같이 32 bits 레지스터를 할당받는데, Conditon 코드 전체 32 bits 의 각 비트는 산술 및 논리 연산의 결과를 저장하여 조건 분기 명령의 조건을 표시한다. 조건 분기 명령의 조건을 표시한다는 점에서, 조건 분기가 많이 쓰이는 프로그래밍 분야에서 이것이 얼마나 중요하고, 유용한 코드인지 알 수 있다. 

 

사용자 수준(User Mode)의 프로그램에서는 일반적으로 레지스터가 어떻게 구성되어 있는지 자세히 알 필요는 없다. Condition 코드(PSR = CPSR)는 전체 32 bits의 '방'을 제공받으며, 상태 레지스터(PSR)라고도 불리우며, 32bits 의 '방'은 Flag bits 와 Control bits 로 나누어져있다. PSR(=CPSR) 에서 우리가 공부할 파트인 '사용자 수준(User Mode)의 프로그램'에서 알아야할 것은 Flag bits 뿐이다.

 

 

 

 - CPSR ( Corrent Program Status Register )

 

CPSR 은 PSR 이라는 상태 레지스터 (Statue register) 이며 월래 본 명칭은 PSR 이지만, CPSR 로도 부른다. PSR 에는 위에서도 말했듯이 Flag bits 부분과 Control bits 부분으로 나누어지지만 여기에서는 우리에게 필요한 Condition Code Flags 만을 알아보자.

 

CPSR 의 전체 32bits 의 '방'에서 최상위 부분(MSB)에 있는 4 bits 가 Flags bits 이다. ( CPSR의 상위 MSB '4 비트' = N, Z, C, V ) Flag는 말 그대로 깃발이라는 뜻으로, 어떠한 정보를 청기(1) 혹은 백기(0)를 들어서 특정 성질의 유무를 쉽게 알아볼 수 있게 만든것이다. 다음 Flag 들은 특정 정보가 맞으면 '1' 이라는 값을 갖고, 틀리면 '0'이라는 값을 가진다.

 

N : Negative result - 바로 이전의 Computation 에서 결과 값이 음수인가 아닌가?

Z : Zero result - 바로 이전의 Computaion 에서 결과 값이 제로(영)인가 아닌가?

C : Carried out - 바로 이전의 Computaion 에서 Carry out 이 발생하였는가?

V : oVerflowed - 바로 이전의 Computaion 에서 oVerflow 가 발생하였는가?

 

어떤 특정한 Computation 의 결과로 발생하는 N, Z, C, V 에 대한 Flag 값들을 읽어내기 위해 그 특정 Computation 을 실행하는 Instruction 에 접미어 S 를 붙이면 그 Computation 이후에 여러 조건들(N, Z, C, V)에 해당하는 Condition flag 에 값들을 1과 0으로 세팅하게 된다. (Postfix "S") 그리고 우리는 그 세팅된 flag 값들을 이용하기만 하면 된다.

 

ex. ADD    r2, r2, r0 / ADDS    r2, r2, r0 - S 가 붙은 후자의 Instruction 에서만 Flag 값들이 설정된다.

 

 

 

 

 - Arithmetic Operations with Carry Bit

 

위에서 어떤 Computation 을 하는 Instruction 에 Postfix S 를 붙임으로써 Condition Code Flags 를 이용하였다.

예를 들어, SUBS    r2, r2, r0 ß S 를 붙여서 condition flags 세팅하였다. 다음 라인부터 이 Flags 를 이용가능하다.

 

이렇게 Flag를 Postfix S 를 이용하여 사용할 수 도 있지만, 아예 Computation 자체 결과에서 (다음 라인까지 갈 필요없이) Flag 를 세팅하여 그 Flag 값을 적용하기 위해서는 따로 S 를 붙일 필요없이 특정 Instruction 을 사용하면된다. ( 단, Carry out 에 관련된 C Flag 에 국한된다. ) 예를 들어, SBC    r3, r3, r1 ß SUB 연산을 하는 동시에 그에 대한 결과를 이용햐 C Flag 를 세팅하고 그렇게 세팅된 C Flag 를 SUB 연산의 결과에 바로 적용시킨다.

 

ADC r3, r3, r1               / ADC ADD + Carry bit 표현

                                / ADD 의 결과 값이 기본 32bits를 넘어설 경우 발생하는 Carry를 같이 표현해주기 위함.

 

ADD    r0, r1, r2            @ r0 ß r1 + r2

ADC    r0, r1, r2            @ r0 ß r1 + r2 + C    

 

SUB    r0, r1, r2            @ r0 ß r1 - r2

SBC    r0, r1, r2            @ r0 ß r1 - r2 + C - 1

 

RSB    r0, r1, r2            @ r0 ß r2 - r1

RSC    r0, r1, r2            @ r0 ß r2 - r1 + C - 1

 

  왜? Subtract 연산에서는 Carry Bit 를 붙여준 후에 1을 빼줄까?

 

- 뺼셈 연산은 실제로 컴퓨터 안에서는 2 진수들의 덧셈 연산을 이용하고 우리에게 뺄셈의 결과를 보여주는 것이다. 그렇게 해서 발생한 Carry bit 는 덧셈에 대한 Carry bit 일 수 밖에 없다. 이렇게 컴퓨터의 연산방법에 의하여 내제적인 Carry bit의 문제점을 없애서 바로 잡아야한다. 그래서 이 뺼셈을 수행하는 구조적인 문제에서 발생한 Carry bit 를 마지막에서 빼주어 없애기 위해 '-1' 연산을 하는 것이다.

 

 

이렇게 지금까지 산술 연산 (Arithmetic operation)에 대해 알아보았다.

다음은 Comparisons '비교' Instruction에 대해 알아보자.

 

 

 

 

 

 

Posted by 하늘_


 

Data Processing Instructions

Logical Operations

 

Data Processing Instructions 은 ARM instructions 중에 가장 커다란 집합체로 많은 연산들이 있다. 다 다루지는 않고, 꼭 필요한, 많이 사용하는 명령어들을 간단하게 알아볼것이다. 가장 큰 집합체인 만큼, Data Processing Instructions 에는 몇 개의 Operations 로 나누어진다. 그 중 처음으로 알아볼 것은 Logical operations 이다. 

 

시스템 프로그래밍 - 4 (1) : Data Processing Instructions - Logical operations

 

+ 모든 Data Processing Instructions 은 오직 레지스터에서만 실행된다. 절대로 메모리에서 실행되지 않는다.

 

 

 - Operation examples ( #5 는 '상수 number' 5 를 뜻한다. )

 

-    MOV    r0, r1         @ r0 ß r1

r1 에 있는 값을 r0 에 넣는다 

-    MVN    r0, #7        @ r0 ß ~ 7

MOV + NOT = #7 을 NOT 한 결과를 r0 에 넣는다

-    AND    r0, r1, r2     @ r0 ß r1 & r2 

r1 과 r2 를 AND 한 결과를 r0 에 넣는다

-    ORR    r0, r1, #6     @ r0 ß r1 | 6

r1 과 #6 를 OR 한 결과를 r0 에 넣는다

-    EOR   r0, r1, r2       @ r0 ß r1 ^ r2

r1 과 r2 를 XOR(=Exclusive OR) 한 결과를 r0 에 넣는다

-    BIC   r0, r1, #7       @ r0 ß r1 & ~ 7

Bit Clear 라는 개념으로, 7 이 [00000111] 인데, 1이 있는 자리에서는 무조건 0 의 결과가 나오며

0이 있는 자리는 위에 피연산자인 r1 의 결과가 그대로 내려온다. (0이면 0, 1이면 1)

01101001 = r1 값 : Bit Clear 는 필터 개념으로 이해하면 쉽다.

01010101 ( 0인 곳은 위에 값을 아래로 내려보낸다. )

00101000 = BIC 의 결과

 

 

 - Basic Instruction form

 

위에 나열된 Instructions 를 보면 일반적으로 XXX (연산, 작업의 이름) + r1, r3, r2 이런 형식을 가졌다는 것을 알아볼 수 있다. 얼핏 보기에는 그저 원하는 연산이나 작업에 따라 r0 이나 #3 같은 것들을 나열한 것으로 보일 수도 있으나, 꼭 지켜야만 하는 정형화된 형태가 있다.

 

컴퓨터는 알다시피 두뇌를 가진 인간처럼 능동적으로 생각할 수 없는 기계에 불과하기에, 항상 정형화된 형태 form 에 맞추어 컴퓨터에게 하나 하나 꼼꼼하게 알려주어야지 그때서야 컴퓨터는 작동을 올바르게 수행한다.

 

ARM Instruction 을 사용하기 위한 Format 은 각 Instruction 의 종류에 따라 각각 32 bits 의 사용 가능한 '방'이 주어진다. 이 '방'에는 그 Instruction 실행에 대한 여러 옵션들을 추가해줄 수 있다. 예를들어 단순한 '+' 덧셈 (빨강)Instruction 에 '어떠한 조건이 만족되면 + 덧셈', '+ 덧셈 후 맨 첫번째가 0인지 1인지', '꼭 무엇과 무엇을 덧셈 +' 등 Instruction을 실행하는데 필요한 '추가적인 조건(cond)', '피연산자(operand : rm, rn...)', '목적지(destination : rd)' 등등의 요소들이 담길 장소들이 이 32 bits 의 전체 방에 각 자신이 들어가야할 위치를 지니게 된다.

 

[ 32 비트 구성 그림의 예시 ]

 

우리는 이에 따라 반드시 각자 할당된 장소에 따라 그 장소에 알맞은 값들 (cond? rm? rn? rd?) 을 넣어야 한다. 

 

기본적인 instruction form을 단순하게 정리하자면 아래와 같다.

( ARM 에는 정말 많은 instruction set 들이 있으며, 그 중 한 set 이 우리가 이번 4 장에서 배우는

Data Processing set 이다. 아래의 format 은 Data Processing / PSR Transfer 에 대한 포맷일 뿐이다.

다른 set 에 대한 instruction format 을 알고싶다면 인터넷 검색, 서적들을 찾아보길 권장한다.)

[ Formats of ARM Instruction set : http://blog.naver.com/suyguy17?Redirect=Log&logNo=146022731 ]

 

XXX    rd, rm, op               rd : destination 목적 register 가 들어가야한다 ( ex. r1 )

                                    rn : source register

                                    rm : source register - First operand 피연산자 register

                                    op : Second operand 피연산자 무엇이든지 된다. Constant, register 등등

 

( MOV 와 MVN 은 First operand 가 없고, Second operand 만 있으므로, Constant, register 무엇이든지 사용가능 )

 

이렇게해서 기초적인 Logical Operations 와 Basic Instruction form 를 알아보았다.

다음 장 4 (2) 에서는 산술 연산들을 알아보자.

 

 

 

 

 

 

Posted by 하늘_


 

System Data Structure 을 기반으로 여러 Instruction들을 사용하여, 많은 실행, 동작들을 할 수 있다. ARM의 특징은 Load / Save 라고 배웠으며, 따라서 ARM의 모든 동작은 메모리로부터, 메모리에게 Load 와 Save 를 하면서 여러 연산들은 레지스터에서 처리한다. 그럼 이제부터 모든 Instructions 의 기본이 되는 Load 와 Save Instructions 을 알아보자.

 

 

Load / Store instructions

 

- Single register data transfer ( LDR / STR : Register )

 

-    STR r0, [ r5 ]        @ r0 := memory [r5] / 방향 >

 

à레지스터 r5 (r5, r0 들은 레지스터 번지 수를 뜻한다.)’ 안에는 메모리 주소 값이 있다. 주소가 0x30000000메모리레지스터 r0’ 안에 있는 값인 0x12345678 (16 data)을 저장한다. ( [ x ] x 의 주소를 갖는 메모리가 가지고 있는 값을 뜻한다.)

 

r5 = 0x30000000  @ r5 레지스터에 '0x30..' 값은 '메모리 주소 값'이다.

r0 = 0x12345678  @ r0 레지스터에 '0x12..' 값이 들어있다. 이를 'r5 의 값'을 주소로 갖는 메모리에 작성한다.

 

 

-    LDR r1, [ r5 ]        @ memory [r5] := r1 / 방향 <

 

à 위 STR 에 이어, 주소가 (r5의 값) 0x30000000 인 메모리에서 Single Register에 해당하는 1 워드( 32비트 단위 )를 레지스터 번지 수 r1 으로 읽어낸다. r1 에 r5 값을 주소로 갖는 메모리에 있던 값이 들어간다.

 

r5 = 0x30000000 @ r5 레지스터에 '0x30..' 값은 '메모리 주소 값'이다.

r1 = 0x12345678 @ 'r5 의 값'을 주소로 갖는 메모리에 있는 값을 r1 레지스터에 넣는다.

 

 

 

 

- Block data transfer ( LDM / STM : Multiple  )

 

-    STMIA r0, { r2 - r9 }     move the words to mem[r0] / 방향 <

 

à STR 하고 하는 일은 유사하지만, 어디서 어디로 저장하는지에 대한 방향이 틀리다. r0 이 값을 받아내거나, 보류하는 기능을 하는 레지스터가 아니라 메모리 주소를 가리키는 포인터이다. LDMIA도 마찬가지이다. 그냥 STR 에서는 싱글 레지스터에 해당하는 작은 값 (단지 1 Word = 32 bits)을 저장하는 것이 아니라, { r2 에서 r9 까지 }의 8개의 words를 읽어서 r0 이 갖고 있는 '메모리 주소 값'이 가리키고 있는 메모리에 순차적으로 저장한다. 

 

r0 = 0x30000000    @ r0 레지스터에 '0x30..' 라는 '메모리 주소 값'을 갖는다.

이 r0 값이 가리키는 메모리부터 순서대로 8 words 만큼 저장하게 된다.

{ r2 - r9 }             @ r2 부터 r9 까지의 레지스터에 저장 되어있는 8 words 만큼을 읽어낸다.

 

 

-    LDMIA r1, { r2 - r9 }             @ move 8 words at mem[r0] ( MIA : Multiple In Array ) / 방향 >

 

à 8개 레지스터에 저장될 내용(8 words)을 r1이 가리키는 주소로부터 읽어내어 r2, r3, r4, ... , r9 에 저장한다. 방향이 LDR 과는 달리 반대 방향이다. 자세히 설명하자면, r1 이 값을 받아내거나, 보류하는 기능을 하는 레지스터가 아니라 메모리 주소를 갖는 포인터와 같은 개념이다. STMIA도 마찬가지이다.

 

r1 = 0x30000000    @ r1 레지스터에 '0x30..' 라는 '메모리 주소 값'을 갖는다.

이 r1 값이 가리키는 메모리부터 순서대로 8 words 만큼을 읽어내게 된다.

{ r2 - r9 }             @ r2 부터 r9 까지의 레지스터에 r1이 가리키는 메모리부터 8 words 만큼을 읽어 저장한다.

 

 

 

 

- Single Data Swap ( SWP )

 

-    Used for semaphore implementation

     SWP{cond} {B} Rd, Rm, [ Rn ]    @ Rd := [ Rn ], [ Rn ] := Rm

 

 

 

 

Load / Store for Bytes or Half-words

 

-    LDRB r1, [ r2 ]        r1 := mem[r2] In Byte / 방향 <

-    STRB r3, [ r4 ]        mem[r4] := r3 In Byte / 방향 >

 

-    LDRH r1, [ r2 ]        @ r1 := mem[r2] In Unsigned Short / 방향 <

-    STRH r3, [ r4 ]        @ mem[r4] := r3 In Unsigned Short / 방향 >

 

-    LDRSH r1, [ r2 ]      @ r1 := mem[r2] In Signed Short / 방향 <

-    STRSH r3, [ r4 ]      @ mem[r4] := r3 In Signed Short / 방향 >

 

Signed and Unsigned Integer

 

 

 

 

 

 

 

 

 

Posted by 하늘_



ARM을 공부, 개발하기 위한 개발환경을 앞 장에서 다 갖추었다. 이제 이것들을 이용하여 ARM의 명령어들을 배우고 본격적으로 프로그램 분석을 하기 이전에 ARM 프로그램이 작동하는 System 에서 특히 데이터 구조에 대해 알아볼 것이다. 기본적으로, 모든 기계는 0 과 1 으로 표현하는 2진수(Binary + Digit = Bit)를 기반으로 작동한다.

 


Bits :
비트는 [ 0 1 ], [ true false ]로 이루어져있다. 비트를 이용하게 된 이유는 다음과 같다.

 

-       철학적 기반 [ 진실과 거짓 ]

     George Boole 은 당 시대 수학적인 시스템들(정확히 표현하자면 논리학)을 표현하기에 and, or, not 이 기본적인 3가지 연산자와 일련의 Bits만 있으면 충분하다는 것을 발견하였다. 이렇게 논리학을 체계적으로 표현하기 위해 고안한 시스템을 불 대수(Boolean algebra)라 부르며, 이것이 Bits 개념의 시초이며, 이 불 대수는 현대 Bits 시스템의 철학적인 기반이 된다. 후에 C. Shannon2 가지 값만 갖는 불 대수를 연구하여 스위칭 대수’(Switching algebra) 시스템을 고안하였고, 이것이 현대의 디지털 컴퓨터의 근본 원리가 되고 있다. 철학에 기반하여, 효율적인 표현법으로 Bit 가 된것이다.

 

-       기술적 제한 [ 0.0V ~ 0.5V : 0 낮은 상태와 2.8V ~ 3.3V : 1 높은 상태 ]

트렌지스터의 전압상태는 크게 고(2.8V ~ 3.3V), (0.0V ~ 0.5V) 두 가지 상태로 양분될 수 있다. 이렇게 사이 전압 값을 유지하기가 어렵다는 점 때문에 고(1), (0) 두 가지 상태로 컴퓨터의 data를 표현하는 것이 제일 최선의 방법임을 찾아내었다.

 

< 최대 전압, 최소 전압. 이 두 가지 상태만이 확실하다. >

 

 

Memory Organization : Bits를 이용해 컴퓨터의 데이터들을 표현하고, 저장하기 위해 메모리를 사용한다.

 

-       메모리 Memory

메모리는 CPU와 제일 가까우며, 단일 기계 명령어(single language instruction)를 이용해 Load(호출), Save 등으로 '직접 접근 가능'한 가장 큰 저장장치이다. (디스크 저장장치는 따로 OS intervention을 필요로 한다.)

 

-      메모리 주소 Memory Address

메모리에 담긴 자료(content)를 인식하기 위하여 사용되는 주소로, 주소는 1byte 당 할당된다.

< 0x00...01/02/03 등등 하나의 주소당 1 Byte(=8 bits)가 할당되어있다. >

 

-      가상 메모리 Virtual Memory

가상 메모리는 Multicasting kernels을 위해 개발된 메모리 관리 기술로, 컴퓨터 아키텍처상에 존재하는 다양한 컴퓨터 데이터 저장소들(디스크, random-access memory)을 가상화하여 프로그램마다 할당되어 있는 프로세스(한 프로그램당 한 프로세스 할당)들에게 그들 자신만의 메모리 공간을 만들어준다. 이렇게 하여 각 프로세스들은 자신들만의 메모리 공간을 가지게 된다. 각 프로세스에서 같은 ‘가상 메모리 주소 값(virtual address을 가질지라도, 실제로는 각자 다른 자료들 '물리 메모리 주소 값(physical address)'을 가리키고 있다.

 

-      Memory Addresses of 16/32/64bit Words, 워드 단위에 따른 메모리 주소

워드(word)는 특정한 프로세서 디자인에 의해 사용되는 데이터 단위의 표현이다. 약간 구체적으로 설명하자면 워드는 프로세서의 하드웨어들이나 명령어(Instruction set)들에 의해 다루어지는 '기본 단위'로서, 기본적으로 고정된 크기(16/32/64)의 'bits 그룹'이다. 이 워드가 몇 bits 의 단위인지 하는 것은 (word size, word width, or word length) 특정 프로세서 디자인이나, 컴퓨터 아키텍쳐 (ARM 아키텍쳐도 이에 포함)에 매우 중요한 특징이기도 하다. 이유는 이 워드의 크기가 컴퓨터 구조나 연산에 대한 여러 방면에 많은 영향을 미친다. ; 프로세서 안에 있는 대부분의 레지스터는 그 '워드 크기(word size)'를 따르며, 단일 연산에서 작업중인 메모리에서 레지스터 사이를 오가는 큰 크기의 데이터들도 거의 대부분의 아키텍쳐에서(어느 아키텍쳐는 워드로 사용하지 않는다.) 워드 단위로 사용한다. 그렇기 때문에 우리는 프로그램을 작성할때 각 '단위'에 맞추어 align (정렬) 하는 능력이 필요하다. 만약 특정 아키텍쳐의 워드가 몇 비트인지 단위를 모르고 프로그래밍을 한다면, 자연히 '패딩'에 의해 메모리 사용에 있어 '비효율성 문제'가 발생하게된다.

 

< 기본적인 Address 표현에 따라 Words 단위들을 나눈다. >

 

-      데이터를 나열하는 법 Storing Words

8-bits word 단위의 메모리 주소를 갖는 아키텍쳐에서 0x01234567 이라는 자료를 저장하려고 한다. 아래 그림에서 어느 방법이 좋을까?

 

데이터를 나열하는데 있어서, 여러 종류의 방법이 있지만 무엇이 좋다고 단정지을 수 없다.  방법들에 대한 장단점들이 존재하기 때문이다. 처음부터 순서대로 나열하는 Big-Endian 과 역순으로 나열하는 Little-Endian 이 존재한다. 

 

1.     Big-Endian

Big 이라는 뜻은 '자료'에서 자리수가 가장 큰 자료인 MSB 를 시작으로 순서대로 나열한다는 의미이다. '3천 4백 2십 1'을 누구에게든 한번 작성해 보라고하면 종이에 '3421'을 적을 것이다. 이렇게 자료를 순서대로 배열하는 방법으로 우리들이 일반적으로 생각하고 있는 자연적인 나열법이다. 이 방법은 네트워크와 같은 분야에서 '자료들을 다른 쪽으로 전송할 때 받는 쪽에서 순서대로 전송되어야 하므로, 네트워크 분야에서 많이 사용한다. ( '안녕하세요?' 라는 문자를 보냈는데 '?요세하녕안'이라고 문자를 받아버리면 난감하다. )

네트워크 패킷 전송뿐만 아니라, Java(자바는 초기에 인터넷을 위해 개발된 언어였다.), 디버깅할 때 쓰인다,

 

2.     Little-Endian

Little 이라는 뜻은 '자료'에서 자리수가 가장 작은 자료인 LSB 를 시작으로 순서대로 나열한다는 의미이다.

X86 에서 사용되며 작은 자료값(예를 들어, 0x00000007)을 다룰때 Type-casting (타입 변환, 예를 들어 short(2byte)를 char(1byte)로 변환하거나 그 반대의 작업)시에 값이 변화하지 않고 그대로 값을 유지하기 때문에 매우 유용하다.  

 < Big-Endian 과 Little-Endian >

 

뒤로 갈수록 메모리 주소 값이 커진다고 가정하였을때, Big-Endian 으로 저장했을때는 [ 0x00 / 0x00 / 0x00 / 0x17 ] 이렇게 저장되고, Little-Endian 으로 저장했을 경우에는 뒤에 LSB 수부터 메모리에 저장되므로 [ 0x17 / 0x00 / 0x00 / 0x00 ] 이다. 2Byte 인 short 로 이 자료를 읽으면 [ 0x17 / 0x00 ] 이 읽히고, 1Byte 인 char 로 이 자료를 읽으면 [ 0x17 ] 이 읽힌다. 이렇게 작은 수들은 Type-casting 에서 값 변환 없이 자유롭다는 의미이다. '포인터'를 이용할때 포인터는 자료의 맨 앞부분을 가리키기 때문에 0x17 이라는 값을 바로 읽을 수 있는 Little-Endian 이 방법이 Bi-Endian을 채택하고 있는 ARM 에서 ‘Endian 설정 default 값이다. 그 이유는 ARM 프로세싱은 포인터를 이용하기 때문에 그렇다.

 

3.     Bi-Endian

H/W의 환경설정에 의해 Endian의 종류를 목적에 맞게 변화시킬 수 있다.

( ARM 은 Bi-Endian 을 택하고, default 값은 Little-Endian 이다. ) ARM PowerPC에서 사용된다.

 

 

 

Simplified View of ARM Computer in User-Mode*

 

[ 그림 자료 꼭 추가 ]

 

-       레지스터 Register

레지스터는 오직 논리/수학적인 연산에 ‘직접적’으로 사용되는 저장소이다. ‘어셈블리 프로그래밍 모델’에서 저장소는 오직 '레지스터' '메모리' 뿐이다. 어셈블리 프로그래밍 모델의 외부에 있는 (어셈블리 프로그래밍 모델에서 저장소로 간주하지 않는) 저장소로는 다음이 있다.

- 캐시 메모리는 성능을 위한 ‘투명한’ 중간지점의 메모리 시스템이다.

- Disk 컴퓨터 시스템 외부의 I/O 시스템에 존재한다.

 

 

-       ARM 레지스터

ARM의 레지스터는 ‘일반 범용 레지스터(R0 ~ R12), ‘특수 범용 레지스터(R13 ~ R15), '특수 레지스터(CPSR, SPSR)'들을 합쳐서 총 37개에 하나의 레지스터당 32 bits(4 byte)의 크기를 갖는다.

 

하지만 37개의 레지스터를 가질 때는 많은 모드들을 다 작동시켰을때 (FIQ, Undef, Supervisor 등등)의 개수이며, 일반적으로 User & System 모드에서 사용하는 레지스터는 17개이다. 우리는 위의 그림 Simplified View of ARM Computer in User-Mode 을 보면 알 수 있듯이, 오직 User-Mode 에서의 레지스터만을 다룰 것이다. 모든 모드에서 다루는 ARM 레지스터에 대해서는 아래 그림을 참조하고, 더 많은 내용(다른 Mode 예를들어 Supervisor 모드에서의 레지스터)은 한참 나중에 다룰것이나, 굳이 알고싶다면 아래 블로그들을 참조하여라.

 

 

l  일반 범용 레지스터

-       r0, r1, , r12 : 사용자 마음대로 자료를 Save, Load 할 수 있는 자유로운 레지스터.

-       일반 범용 레지스터특수 범용 레지스터를 합쳐서 총 r0부터 r15까지로 총 16개이므로 레지스터를 인식하는데(확인하는데) 4 bits 이면 충분하다. ( 4bits = 2^4 = 16개의 레지스터를 인식 가능하다.)

 

 

l  특수 범용 레지스터

-       SP (r13 : Stack Pointer) : 각 모드당 할당되어 있는 스택의 최상단을 지시하는 레지스터이다.

 

[ 스택이란 :http://blog.naver.com/doridori_33?Redirect=Log&logNo=50035553723 ]

 

+ 스택(Stack) 구조란?

 

스택 구조란 일반 컴퓨터들의 CPU가 갖고 있는 매우 활용도가 높은 기법으로, 메모리에 맨 나중에 저장된 것들을 가장 먼저 꺼내지도록 하는 저장 장치라 할 수 있다. 말 그대로 Stack, 쌓는다는 뜻이다. 스택을 이해할 때 쌓는다는 Stack 의 의미를 사용하기 때문에, 실제 ‘Stack 저장 장치에서도 위로 쌓고 맨 위에서부터 실행한다고 생각하지만, 실제 하드웨어 상으로는 아래방향으로 쌓는다. 메모리 안에 자료를 넣는 행위를 Push 라고 하며, 그것을 꺼내는 행위를 Pop 이라고 한다. 스택도 저장 장치이기 때문에 Data의 위치를 알려줄 주소가 필요하다. 하지만 앞에서 언급했듯이 PopPush연산만 존재하기 때문에, 주소를 알려줄 필드는 단 하나만 있어도 된다. , 스택이라는 통 속에 맨 위에 있는 것이 무엇이냐만 알면 되는 것이다. 그래서 스택 구조 컴퓨터에서는 0-주소 명령어 형식을 가진다.

 

여기서 주소 필드란 피연산자의 주소를 말한다. 맨 위를 가리키는 포인터도 반드시 필요하다. 이것의 이름은 SP(Stack Pointer)로 스택의 Top 값을 담고 있다. 어디에 위치하고 있는지 알려준다는 말이다. 스택에서는 Data를 한 번 꺼내면 사라져버리기 때문에 굳이 주소를 다룰 필요가 없기 때문이다.

 

 

 

-       LR (r14 : Load Register) : 함수 호출 또는 예외가 발생했을시에 복귀 주소를 저장하는 레지스터이다.

 

-       PC (r15 : Program Counter) : 일반적으로 현재 어디를 수행하고 있는 건지를 나타내는 것이라고 표현한다. 정확히 말하자면, 실제로는 실행하는 위치를 가리키는게 아니라 파이프라인에서 명령어를 Fetch 할 위치(주소)를 가리키는 것이다. , 순차적인 명령어 수행 시에 자동으로 증가되면 수행되어야 할명령어의 주소를 가지고 있는 레지스터이다 

 

 

 

 

ARM 은 위 레지스터 부분에서도 말했지만 Load/Store 아키텍처이다.

-       메모리간(memory-to-memory) 데이터 프로세싱 연산들은 지원하지않는다.

-       데이터 값은 사용되기 전에 이동되어져야한다. (레지스터로 이동시킨후 사용한다)

-       듣기에는 비효율적으로 들리지만, 실제로는 그렇지 않다,

 

 

'메모리, 레지스터'. 이렇게 System Data Structure 에 대해 기초적이면서도 ARM 만의 특성들을 알아 보았다. 다음 장에는 이 '시스템 데이터 구조'를 이용하여 (메모리와 레지스터) 여러 실행(Operation)들을 직접 작성해 보기위해 여러 명령어(Instructor)들에 대하여 알아 볼것이다. ARM은 Load/Store 아키텍처라는 것을 이번 장에서 개념적으로 이해하였다면, 다음 장부터는 여러 Instructor 코드들의 구성과 실제로 작동하는것을 통해 눈으로 직접 깨닳을 수 있을것이다.

 

 

 

Posted by 하늘_



컴퓨터 과학에서의 커널(kernel)은 운영 체제
의 핵심 부분으로서, 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다.


 

> 커널의 역할


커널은 운영 체제의 핵심 부분이므로, 커널의 역할 역시 운영 체제의 핵심 역할이라 할 수 있다.

   * 보안
- 커널은 컴퓨터 하드웨어와 프로세스의 보안을 책임진다.

   * 자원관리
- 한정된 시스템 자원을 효율적으로 관리하여 프로그램의 실행을 원활하게 한다. 특히 프로세스에 처리기를 할당하는 것을 스케줄링이라 한다.

   * 추상화

- 같은 종류의 부품에 대해 다양한 하드웨어를 설계할 수 있기 때문에 하드웨어에 직접 접근하는 것은 문제를 매우 복잡하게 만들 수 있다. 일반적으로 커널은 운영 체제의 복잡한 내부를 감추고 깔끔하고 일관성 있는 인터페이스를 하드웨어에 제공하기 위해 몇 가지 하드웨어 추상화(같은 종류의 장비에 대한 공통 명령어의 집합)들로 구현된다. 이 하드웨어 추상화는 프로그래머가 여러 장비에서 작동하는 프로그램을 개발하는 것을 돕는다. 하드웨어 추상화 계층(HAL)은 제조사의 장비 규격에 대한 특정한 명령어를 제공하는 소프트웨어 드라이버에 의지한다.


 

> 초기의 커널

 

초창기의 컴퓨터에서 운영 체제 커널은 필수적인 것이 아니었다. 초기의 프로그램은 하드웨어 추상화나 운영 체제의 지원을 받지 않고도 컴퓨터만으로 불러들인 다음 실행될 수 있었으며, 이것은 초창기 컴퓨터들의 일반적인 운영 방식이었다. 다른 프로그램을 실행하기 위해서는 컴퓨터의 전원을 껐다가 켬으로써 다시 입력자료를 읽어들여야 하는 방식이었다. 이러한 과정이 반복되면서 사람들은 로더와 디버거 같은 작은 프로그램들이 상주해 있는 것이, 다른 프로그램으로 교체하거나 새로운 프로그램을 개발하는 데 유리하다는 사실을 알게 되었다. 이와 같은 로더, 디버거들이 초기 운영 체제 커널의 기초가 되었다.



> 커널의 종류 

 

단일형 커널 (모노리딕 커널) 

단일형 커널은 하드웨어 위에 높은 수준의 가상 계층을 정의한다. 높은 수준의 가상 계층은 기본 연산 집합과 관리자 모드에 작동하는 모듈인 프로세스 관리, 동시성, 메모리 관리 등의 운영 체제 서비스를 구현하기 위한 시스템 콜으로 되어 있다.

이 연산들을 제공하는 모든 모듈이 전체로부터 분리되어 있더라도 모든 모듈이 같은 주소 공간에서 실행되기 때문에 코드의 집적도는 매우 조밀하며 수정하기 어렵고 한 모듈의 버그는 시스템 전반을 멈추게 할 수 있다. 그러나 구현이 신뢰할 수 있을 정도로 완성되면 구성 요소의 내부 집적이 내부의 시스템 이용을 효과적이게 하여 좋은 단일형 커널은 높은 효율을 보인다. 단일형 커널의 지지자들은 코드의 정확성 여부와 그런 코드(부정확한 코드)가 커널에 포함되었는지를 확인할 수 있고 그것은 마이크로커널에 비해 조금 더 우위에 있다고 주장한다.

리눅스, FreeBSD, 솔라리스와 같은 최신의 단일형 커널은 실행 모듈을 실시간으로 읽어들일 수 있다. 실시간으로 실행 모듈을 읽는 특징은 커널이 허용하는 범위 내에서 손쉽게 확장할 수 있게 커널 공간의 코드의 양을 최소한으로 유지시켜 준다.

마이크로소프트 윈도 NT 제품군(NT, 2000, XP, 2003, 비스타)은 처음에는 혼합형 커널이었으나 나중에 나온 것들은 단일형 커널로 바뀌었다. 윈도 NT 시리즈는 상위의 서비스들을 NT executive이라는 서버로 구현하였다. Win32 특성은 처음에는 사용자 모드의 서버 형태로 구현되었으나, 최근 버전에서는 관리자 주소 영역으로 이동하였다. 다양한 서버들이 로컬 프로시저 콜(LPC: Local Procedure Call)이라 불리는 주소 영역간 매커니즘을 통해 통신하며, 성능을 최적화하기 위해 공유 메모리를 이용한다.

주로 다음 운영 체제들의 커널이 단일형 커널인 것으로 알려져 있다.

유닉스
BSD
리눅스
솔라리스
윈도 NT
벨로나2
AIX
AGNIX



마이크로 커널 

마이크로커널은 하드웨어 위에 매우 간결한 추상화를 정의한다. 기본 연산 집합과 운영 체제 서비스를 구현한 스레드 관리, 주소 공간, 프로세스간 통신의 작은 시스템 콜으로 이루어져 있다. 일반적으로 커널이 제공하는 네트워킹과 같은 다른 서비스들은 사용자 공간 프로그램인 서버로 구현한다.

운영 체제는 서버를 다른 일반적인 프로그램처럼 간단히 시작하고 끌 수 있다. 이를테면 네트워킹 지원이 필요 없는 작은 시스템에서는 간단히 서버를 끄면 된다. 이 경우 전통적인 시스템에서는 재컴파일이 필요했고 일반 사용자의 능력 밖의 일이다. 이론적으로 마이크로커널에서 시스템은 더 안정적이다. 서버가 중단될 때 커널의 충돌이 아니기 때문에 단 하나의 프로그램만 내려버리면 된다.

그러나 서버가 실패한 후 시스템 상태도 잃어버릴 경우 응용 프로그램이 계속 수행되는 것은 그 응용 프로그램이 막 복사된 다른 서버를 이용하게 되더라도 보통은 매우 힘들다. 예를 들어 TCP/IP 연결을 요구하는 (이론적인) 서버가 다시 시작되면 응용 소프트웨어는 연결이 "끊어졌습니다."라고 말하고 서버의 새 인스턴스를 찾아서 다시 연결한다. 그러나 파일과 같은 다른 시스템 객체는 이렇게 편리한 의미론이 없다. 이러한 편리가 믿음직스럽지 못하고 마음대로 이용할 수 없다. 기록할 정보들은 모두 미리 보관해 두어야 한다. 서버 간의 하나의 서버를 다시 시작할 때 중요 상태를 보호하기 위해 트랜잭션, 복제, 대조점의 데이터베이스 기술이 요구된다.

일반적으로 마이크로커널은 전통적인 디자인의 수행을 잘못하고 때로는 극적이다. 이유는 응용과 서버 간의 자료 교환을 위해 커널을 출입하는 문맥 전환 때문이다. 주의 깊은 조율이 오버헤드를 극적으로 줄여줄 것으로 믿어져 왔으나 90년대 중반부터 대부분의 연구원들은 시도를 포기했다. 최근에 새 마이크로커널은 성능을 최우선으로 설계하며 이 문제를 넓은 부분에서 다루었다. 그러나 현재 운영 체제 시장은 자기 몸 사리며 마이크로커널 설계에 소극적이다.

마이크로커널과 마이크로커널에 기반한 운영 체제의 예

AmigaOS
Amoeba
ChorusOS
EROS
Haiku
K42
LSE/OS (a nanokernel)
KeyKOS (a nanokernel)
L4 마이크로커널
Mach - GNU 허드, 넥스트스텝, 오픈스텝,맥 오에스 텐에 사용 됨.
MERT
미닉스
MorphOS
NewOS
QNX
Phoenix-RTOS
RadiOS
Spring operating system
VSTa
Symbian OS



혼합형 커널 (하이브리드 or 모듈러 커널) 

혼합형 커널은 본질적으로 마이크로커널을 따르나, 일부 커널의 비(非)본질적 기능이더라도 사용자 레벨에서 수행될 때 성능상 느린 코드들을 커널 레벨에서 수행하도록 수정한 것을 말한다. 이는 다양한 운영 체제 개발자들이 마이크로커널 기반의 설계를 받아들이던 시점에 순수한 마이크로커널의 성능상의 한계를 인식하고 타협한 결과이다.

예를 들어, 맥 오에스 텐의 커널인 XNU는 Mach 커널 3.0 마이크로커널에 기반을 두고 있지만, 전통적인 마이크로커널 설계의 지연 현상을 줄이기 위해 BSD 커널의 일부 코드들을 들여와 동일한 주소 영역에서 실행하고 있다.

DragonFly BSD는 첫 번째 비 Mach 기반의 BSD OS로 혼합형 커널 구성을 적용한 예이다.

하이브리드 커널로는 다음과 같은 것들도 포함된다.

ReactOS
BeOS 커널
넷웨어 커널

혼합형 커널이라는 말을 부팅 후에 모듈을 읽어들일 수 있는 단일형 커널과 혼용하는 사람들이 있다. 이것은 사실이 아니다. 혼합형 커널은 단일형 커널과 마이크로커널 설계 양쪽의 구조적 개념과 작동방법에 대한 특히 메시지 전달과 어떤 중요하지 않은 코드는 사용자 공간에 들어가는 반면 어떤 코드는 성능의 이유로 커널 공간에 포함해야 하는지에 대한 문제의식을 가진다.



엑소커널 

엑소커널은 운영 체제 설계에 대한 급진적인 신개념으로 말단 이론을 따르는 수직 구조의 운영 체제이다.엑소커널의 구상은 개발자에게 강제적인 추상화를 줄여 하드웨어 추상화에 대해 선택지를 다양하게 하는 것이다. 엑소커널은 기능이 보호를 보장하는 것과 자원을 분배하는 것만 하기에 매우 작아 편익보다 단순함을 제공한다. 이런 특성은 오히려 모든 사용자가 각기 실제 호스트 컴퓨터의 자원을 모방한 컴퓨터를 받는VM/370 운영 체제와 비슷하다. 반면에 모노리딕커널이든 마이크로커널이든 전통적인 커널 설계는 하드웨어 추상화 계층(HAL)이나 장치 드라이버 아래 자원을 숨김으로써 하드웨어를 추상화한다. 한 예로 전통적인 시스템에서 물리 메모리가 할당할 때 실제 위치를 알려주지 않기 때문에 오프셋과 기억 관리 장치를 통해서만 문제를 해결 할 수 있다.


 

나노커널 

나노커널은 실질적으로 모든 서비스들을 '장치 드라이버'에게 넘긴다. - '서비스'들은 심지어 controllers 혹은 timer 에 대해 interrupt 하는것과 같은 아주 기초적인 것도 포함한다 - 나노커널이 이렇게 심지어 기초적인 서비스 조차 장치 드라이버(Device Driver)에게 위임하는 이유는, '커널 메모리 요구치'를 '전통적인 마이크로커널'보다 더 작게 만들기 위해서이다. (말 그대로, 커널의 역할을 nano 급으로 축소시키는 것을 뜻한다.)


 

> 모노리딕커널 대 마이크로커널 논쟁 


1990년대 초기 모노리딕커널은 진부한 것으로 여겨졌다. 리누스 토르발스와 앤드류 타넨바움간에 일어난 리눅스의 설계인 모노리딕커널과 마이크로커널에 대한 프레임 워는 유명했다.


타넨바움과 토르발스의 토론에 제시된 두 진영의 의견은 일장일단이 있다.


두 진영의 성공 사례가 있다. 모노리딕커널은 정확한 설계가 쉽고 마이크로커널 기반 시스템보다 빨리 성장할 수 있다. 반대로, 마이크로커널은 종종 임베디드 로봇 산업이나 의료 컴퓨터 등에 이용될 수 있다. 운영 체제의 컴포넌트를 개인적으로 가지고 있고 메모리 공간을 보호하기 때문이다. 근대의 모듈을 읽어오는 모노리딕 커널에서도 이런 것은 불가능하다.


Mach
는 일반적인 용도의 마이크로커널로 알려졌지만 특별한 용도로 설계된 마이크로커널도 있다. L3는 마이크로커널이 느리지 않다는 것을 보여주기 위해 만들어졌다. L4 L3의 후예로 Fiasco 구현으로 대중적인데 L4 프로세스들과 별도의 공간에서 리눅스 구동이 가능하다. 이런 특성의 스크린숏은 freshmeat.net에서 구할 수 있다. Pistachio라 불리는 새 버전도 역시 가능하다.


QNX
1980년 초에 나타난 운영 체제로 극 최소주의 마이크로커널 설계로 이루어졌다. 이 시스템은 Mach가 목표로 했던 마이크로커널 이념을 더 성공적으로 이루었다. QNX는 우주 왕복선의 로봇 팔과 (작은 실수가 수십억의 손실을 입히는 허블 우주망원경의 거울 등의) 오차에 민감한 유리를 닦는 기계에도 적용되었다.

 

Posted by 하늘_



이제 우리가 'ARM 공부'를 위해서는 'ARM 시스템을 개발하기위한 개발환경'을 갖추어야한다.
그 개발환경 속에서 여러 ARM 어셈블리 코드를 배우고, 그 코드가 의미하는 하드웨어적 의미들을 배워나갈것이다.


ARM
개발 환경은 무엇이 있을까? ARM Development Environment


우선 전반적인 개발 환경 구축에 앞서, 우리는 제일 첫번째로 가상화를 지원하는 '가상 머신'이란것이 필요하다.

ARM 개발 환경을 구축하기 위해 우리는 '가상화'를 이용해야하는가?

우리가 ARM을 배우기 위해서 ARM의 개발과정을 알아야하고, 그 과정속에서 코드를 익히는것이 목적인데, 기본적으로 앞서 말했듯이 ARM 아키텍쳐는 우리가 사용하는 PC regime과 전혀 다르다. ( CISC 가 아닌 RISC 라고 설명하였었다. ) 우리는 ARM 아키텍쳐의 개발을 위해서 PC를 이용해야하지만, ARM PC와 다르기 때문에 PC에서 ARM 과 유사한 환경을 '가상적'으로 구축해야지 작업을 할수있게 되는것이다


이것이 앞으로 우리가 하려는 '가상화'의 가장 큰 목적이다
.


[ 1. Virtual Machine : 가상 머신 ] : QEMU (ARM virtual machine)


'가상머신'이란 무엇인가
? VM(Virtual Machine)의 정확한 정의는 '컴퓨터 과학 분야에서 특정한 프로그램들을 실행하는 컴퓨터를 진짜 컴퓨터같이 만들어 주는 소프트웨어'이다. 아주 쉽게 설명을 하자면, A 기술로 만들어진 기기'내부'에서 가상적으로 B 기술로 만들어진 기기의 작동원리를 구성해주는 것을 뜻한다. 예전에 PC안에서 에뮬레이터를 다운받아 'GAMEBOY ADVANCE'의 기기처럼 작동시키거나, 실제로 없는 DVD롬을 'DAEMON TOOL'을 이용하여 가상의 DVD롬 기기가 있는것처럼 작동시켜주었던 기억이 있을것이다. 사실 VM(Virtual Machine : 가상머신)은 이렇게 단순하게 정의되는것이 아니다. 세세한 내용은 아래 분홍 박스를 참조하여라.

 

      + VM(Virtual Machine) 가상머신 이란?

가상 머신(VM)은 "일반 '호스트 운영 체제'속에서 완벽하게 고립된 '게스트 운영 체제'(guest operating system)"를 뜻한다. 현대의 가상 머신은 '소프트웨어 에뮬레이션' 혹은 '하드웨어 가상화' 둘 중 하나로 작동이 되기도 하지만, 거의 대부분의 가상머신은 이 두 가지를 한번에 이용한다.

가상 머신은 '물리적 머신'과 같은 프로그램들을 실행시켜주는 머신(예를 들어 컴퓨터와 같은)의 소프트웨어 실행기이다. 가상 머신은 두 가지의 주 카테고리로 나뉘어진다.

* 완전한 시스템 플랫폼을 제공하며, 다시 말해 완전한 운영 체제 (OS)의 실행을 지원하는 '시스템 가상 머신' (A system virtual machine).
* 반대로, 단일 프로그램을 실행하기 위해 고안되어진, 즉 싱글 프로세스를 지원해주는 것을 뜻하는 '프로세스 가상 머신' (a process virtual machine).


가상 머신의 '근본적 성질'(essential)은 제한된 리소스들과 가상 머신에 의해 제공되는 추상화들에 국한되어 소프트웨어를 구동한다는 점이다. (가상 world에서 벗어날 수 없다.)

> 일반적 분류
가상 머신은 실제 컴퓨터와 어느 정도의 통신과 사용을 기반으로 두 가지로 나뉜다.

   [ 시스템 가상 머신 ]

: 완전한 시스템 플랫폼을 제공하며, 다시 말해 완전한 운영 체제 (OS)의 실행을 지원한다.


시스템 가상 머신은 가끔 하드웨어 가상 머신이라고 하며 각 운영 체제를 실행하는 가상 머신 사이의 기초가 되는 물리 컴퓨터를 다중화(multiplex)한다. 가상화를 제공하는 소프트웨어 계층은 가상 머신 모니터 또는 하이퍼바이저라고 한다. 하이퍼바이저는 순 그대로의 하드웨어 또는 호스트 운영 체제 위에서 실행할 수 있다.


시스템 가상 머신의 주요 이점:


*
여러 운영 체제를 쓰는 환경은 운영 체제가 완벽히 고립된 채로 같은 컴퓨터에서 존재할 수 있다.
*
가상 머신은 실제의 컴퓨터가 제공하는 것과 다른 형태의 명령어 집합 구조 (ISA, Instruction Set Architechure)를 제공한다.

* application provisioning, maintenance, high availability 그리고 disaster recovery 들을 제공한다.

시스템 가상 머신의 주요 단점:

* 가상 머신이 하드웨어에 간접적으로 접근할때 가상 머신은 실제 머신보다 적은 효율을 지닌다.
* 복수의 VM들이 동시적으로 같은 물리적 호스트에서 작동할 경우, 각각의 VM 들은 다양하고, 불안정한 퍼포먼스들(실행 속도, 혹은 결과 자체가 없는 경우)을 보여줄 수 도 있다.


각자 게스트 운영 체제라 불리는 저만의 운영체제를 실행하는 복수의 VM들(Multiple VMs)은 '서버 통합(server consolidation)'에 사용된다. 서버 통합(server consolidation)은 '서로 방해되는 것을 막기위해 각자의 머신에서 가동되는 다른 서비스들'을 같은 물리적 머신 내에서 분산된 VM들을 이용함으로써 가동시키는 것을 뜻한다. 이러한 사용을 '제품 품질의 고립 (QoS 고립)'이라고 한다.


여러 개의 운영 체제를 사용하려는 열망은 가상 머신의 원래 취지였으며, 여러 개의 단일 작업 운영 체제들 사이에서 시분할 단일 컴퓨터를 허용함으로서 이를 실현하였다.

 In some respects, a system virtual machine can be considered a generalization of the concept of virtual memory that historically preceded it. IBM's CP/CMS, the first systems to allow full virtualization, implemented time sharing by providing each user with a single-user operating system, the CMS. Unlike virtual memory, a system virtual machine allowed the user to use privileged instructions in their code. This approach had certain advantages, for instance it allowed users to add input/output devices not allowed by the standard system.


'
게스트 운영 체제'들은 같은 컴퓨터 내에서 절대적으로 '각 다른 운영 체제들을 가동시키는 것을 가능하기위해 만들어진 하드웨어'에 순응할 필요는 없다. 다시 말해, 같은 컴퓨터에서 다른 운영체제를 돌릴 수 있게 해 준다. (: 마이크로소프트 윈도와 리눅스, 또는 최신 버전에서 지원하지 않는 소프트웨어를 지원하기 위해 옛날 버전의 운영체제를 설치) 다른 '게스트 운영체제'들을 지원하기 위해 가상 머신을 사용하는 것은 임베디드 시스템에서 인기를 끌고 있다 : 일반적으로 리눅스와 윈도와 같은 높은 수준의 운영 체제와 동시에 실시간 운영 체제를 지원하는 용도로 많이 사용한다.


다른 사용으로는 신뢰할 수 없는 운영체제를 sandbox하는 것이다. 왜냐하면 그 시스템이 개발 하의 시스템일 수도 있기 때문이다. 가상 머신들은 더 나은 오류 수정의 접근과 더 빠른 다시 시동과 더불어 운영 체제 개발에 다른 이점들을 가져다 준다.


'QoS
고립'을 위한 가상 머신의 인기는 대부분의 동시대 운영 체제가 제공하는 완전하지 못한 자원 고립을 이끈다. 솔라리스 존은 강력한 자원 고립을 제공하는 대체물이다. 존은 가상 머신이 아니지만 "운영 체제 가상화"의 예이다. 여기에는 Virtuozzo, FreeBSD Jail, Linux-VServer, chroot jail, 그리고 OpenVZ와 같은 가상 환경(가상 서버)을 포함한다. 이러한 환경은 운영 체제 안의 프로세스를 어떠한 형태로 둘러싼다.



 

   [ 프로세스 가상 머신

: 하나의 단일 프로그램을 실행하기 위해 만들어져 있는데, 다시 말해 단일 프로세스를 지원하는 것을 뜻한다.


종종 일반적인 '애플리케이션 가상 머신'이라고 불리우는 '프로세스 가상 머신'은 호스트 운영 체제 안에 있는 일반적인 애플리케이션을 실행하고, 단일 프로세스를 지원해준다.

이 프로세스 가상 머신은 프로세스가 시작될때 생성되고, 프로세스를 나갈때 파괴된다(destroyed). 
프로세스 가상 머신의 목적은 하드웨어나 운영 체제의 밑부분에 있는 매우 상세한 사항들을 추상화시켜주고, 어느 플랫폼에서든 같은 방식으로 하나의 프로그램을 실행시키는 것을 가능하게 해주는 platform-independent programming environment (플랫폼과 독립적인 프로그래밍 환경)를 제공하는 것에 있다. 


'프로세스 가상 머신'은 고급 프로그래밍 언어에서와 같은 높은 수준의 추상화를 제공한다. ('시스템 가상 머신'에서의 낮은 수준의 ISA 추상화에 비하면) — '프로세스 가상 머신'들은 interpreter를 사용하여 실행된다.(implement); interpreter 는 just-in-time compilation (JIT)를 이용함에 따라 compile 프로그래밍 언어와 견줄만한 퍼포먼스를 갖게 되었다.

이러한 종류의 가상 머신은 '자바 가상 머신(JVM : Java Virtual Machine)'을 사용하여 수행(implement)되는 '자바 프로그래밍 언어'와 더불어 유명해졌다. 또 다른 예로는, 몇몇의 interpreted 언어를 위해 추상화 계층을 제공하는 Parrot virtual machine 이 있고, '닷넷 프레임워크'가 있는데 '닷넷 프레임워크'는 공통 언어 런타임(Common Language Runtime)이라고 불리는 가상 머신을 실행한다.

http://en.wikipedia.org/wiki/Just-in-time_compilation          Just-In-Time Compilation


'프로세스 가상 머신'의 특수한 케이스는 잠재적으로 여러 다른 요소들로 구성된(potentially heterogeneous) 컴퓨터 클러스터의 통신 구조를 추상화하여 감추는(abstract over) 시스템들이다. 이러한 종류의 VM은 단일 프로세스로 구성되있지 않지만, 클러스터 내부에서 '물리적 머신 당 하나의 프로세스'(one process per physical machine)로 구성된다. 이것들은 프로그래머들에게 내부 연결(interconnect)과 OS 에 의한 통신 구조들은 복잡하게 생각하지 않게하고(이것이 'abstract over'의 의미), 단지 알고리즘에만 집중할 수 있도록 함으로써 병렬 응용 프로그램(parallel applications)들을 프로그래밍하는 작업을 쉽게 하기 위해 고안되었다.

다른 '프로세스 가상 머신'들과는 다르게, 이러한 시스템들은 특정한 프로그래밍 언어를 제공하지 않지만 기존의 언어에 통합(embedded)되어 있다. ; 보통 이러한 시스템들은 몇몇의 언어들을 합친 꾸러미(bindings)들을 제공한다(예를 들어, C와 FORTRAN). 병렬 가상 머신 (PVM : Parallel Virtual Machine)와 메시지 전달 인터페이스 (MPI : Message Passing Interface)가 그 예이다. 위에서 실행되는 응용 프로그램(애플리케이션)들이 여전히 모든 운영 체제 서비스에 대한 접근을 가지고 있기 때문에 가상 머신이라고 딱 잘라 말하진 않으므로 "가상 머신"이 제공하는 시스템 모델로도 정의하지 않는다.



> 기술

 

1. underlying raw hardware 에서의 에뮬레이션 (native execution)


이러한 접근은 하드웨어의 완전한 가상화를 말하며, 유형 1 또는 2의 하이퍼바이저(hypervisor)를 사용하여 수행(implement)된다.


* 유형 1 하이퍼바이저 : 직접적으로 '하드웨어' 위에서 실행한다.
* 유형 2 하이퍼바이저 : 리눅스와 같은 '다른 운영 체제' 위에서 실행한다.


각각의 가상 머신은 underlying hardware에 의해 지원을 받는 아무 운영 체제나 실행할 수 있다. 유저들은 당연히 별도의 '개인'(private) 가상 컴퓨터내에서 2개 혹은 그 이상의 다른 '게스트 운영 체제'들을 동시에 가동할 수도 있다.


The pioneer system using this concept was IBM's CP-40, the first (1967) version of IBM's CP/CMS (1967–1972) and the precursor to IBM's VM family (1972–present). With the VM architecture, most users run a relatively simple interactive computing single-user operating system, CMS, as a "guest" on top of the VM control program (VM-CP). This approach kept the CMS design simple, as if it were running alone; the control program quietly provides multitasking and resource management services "behind the scenes". In addition to CMS, VM users can run any of the other IBM operating systems, such as MVS or z/OS. z/VM is the current version of VM, and is used to support hundreds or thousands of virtual machines on a given mainframe. Some installations use Linux for zSeries to run Web servers, where Linux runs as the operating system within many virtual machines.

Full virtualization is particularly helpful in operating system development, when experimental new code can be run at the same time as older, more stable, versions, each in a separate virtual machine. The process can even be recursive: IBM debugged new versions of its virtual machine operating system, VM, in a virtual machine running under an older version of VM, and even used this technique to simulate new hardware.[6]

The standard x86 processor architecture as used in the modern PCs does not actually meet the Popek and Goldberg virtualization requirements. Notably, there is no execution mode where all sensitive machine instructions always trap, which would allow per-instruction virtualization.

Despite these limitations, several software packages have managed to provide virtualization on the x86 architecture, even though dynamic recompilation of privileged code, as first implemented by VMware, incurs some performance overhead as compared to a VM running on a natively virtualizable architecture such as the IBM System/370 or Motorola MC68020. By now, several other software packages such as Virtual PC, VirtualBox, Parallels Workstation and Virtual Iron manage to implement virtualization on x86 hardware.

Intel and AMD have introduced features to their x86 processors to enable virtualization in hardware.

As well as virtualization of the resources of a single machine, multiple independent nodes in a cluster can be combined and accessed as a single virtual NUMA machine.

 

2. non-native 시스템의 에뮬레이션


가상 머신은 또한 다른 컴퓨터 프로세서 아키텍쳐를 위해 쓰여진 소프트웨어 애플리케이션과 운영 체제가 동작할 수 있게 도와 줌으로써 에뮬레이터의 역할을 수행할 수도 있다.


몇몇의 가상 머신들은 자세한 규격으로 존재하는 하드웨어를 가상으로 구현(emulate)한다. 예를 들면:


* 가장 첫번째가 프로그래머들에게 '규격을 알맞게 수행하는 가상 머신 소프트웨어를 작동시키는 어느 컴퓨터에서든지 작동하는' Pascal 프로그램들을 작성할 수 있게끔 만들어주는 p-code machine specification이다.

* Java Virtual Machine의 규격(specification)

* 마이크로소프트 닷넷 계획(initiative)의 핵심(the heart)인 Common Language Infrastructure 가상 머신
* Open Firmware는 '플러그인 하드웨어'가 어떠한 종류의 CPU든 그 위에서 작동하는 부트시간 진단, 환경설정 코드, 디바이스 드라이버들을 포함하게끔 가능하게한다.


 

이 기술은 다양한 컴퓨터가 해당 규격에 맞춰 쓰인 아무 소프트웨어나 실행할 수 있게 해 준다.; 오직 가상 머신 소프트웨어 자체만이, 그 소프트웨어가 실행되는 각 컴퓨터 타입에 맞춰 독립적으로 쓰여질 수 있다.


3. 운영 체제 수준의 가상화


운영 체제 수준의 가상화는 서버들을 운영 체제 (커널) 계층 위에서 가상화하는 '서버의 가상화 기술'이다. 이 기술은 파티셔닝(partitioning)으로 간주될 수 도 있다 : 단일 물리 서버는 다수개의 작은 파티션들 (가상 환경 (VE), 가상 개인 서버 (VPS), guests, zones 등이라고도 한다.)로 쪼개진다. ; 이러한 각 파티션은 그것의 유저가 보는 관점에서 진짜 서버처럼 작동한다(looks and feels like). 

orts multiple guest OSes running under the same OS (such as Solaris 10). All guest OSes have to use the same kernel level and cannot run as different OS versions. Solaris native Zones also requires that the host OS be a version of Solaris; other OSes from other manufacturers are not supported.[citation needed],however you need to use Solaris Branded zones to use another OSes as zones.

Another example is System Workload Partitions (WPARs), introduced in the IBM AIX 6.1 operating system. System WPARs are software partitions running under one instance of the global AIX OS environment.

The operating system level architecture has low overhead that helps to maximize efficient use of server resources. The virtualization introduces only a negligible overhead and allows running hundreds of virtual private servers on a single physical server. In contrast, approaches such as full virtualization (like VMware) and paravirtualization (like Xen or UML) cannot achieve such level of density, due to overhead of running multiple kernels. From the other side, operating system-level virtualization does not allow running different operating systems (i.e. different kernels), although different libraries, distributions etc. are possible.

 


그래서 우리는 VM인 QEMU라고 불리는 x86 이외(쉽게말해 PC 이외)의 기기(ARM)를 위해 소프트웨어 스택 전체를 가상머신 위에서 실행가능하게 만들어주는 가상화 소프트웨어(에뮬레이터)를 이용할것이다. 그런데 QEMU 에뮬은 우분투, 데비안 등의 버젼은 있지만 (리눅스 계열에서) 마이크로소프트 윈도우 버젼은 없다. 그 이유는 QEMU가 ARM 에뮬레이터이고, 우분투와 데비안은 ARM 개발환경을 위한 OS 이기 때문, 자연히 Windows는 ARM 개발환경 OS가 아니라는 뜻이다. 이러한 이유때문에 우리는 우분투 OS를 설치해야하는 귀찮은 상황에 놓이게된다.
우분투를 사용해야하는 이러한 이유 말고도, 추가로 우분투를 이용하는 이유는, 우분투에 패키지 매니지먼트 기능이라고하는 Windows와 차별화된 매우 유용한 기능이 있기때문이다.


      + '우분투 패키지 매니지먼트'란? (Ubuntu Package Management)

1.
리눅스 환경 세팅의 핵심.

2.
대부분의 우분투 프로그램들과 라이브러리들은 '데비안 패키지 시스템'에 의해 관리된다.
( 우분투 OS는 데비안 OS (리눅스 커널을 탑재한 공개 OS)기반으로 제작된 OS이다. 이런 이유로 데비안의 패키지 시스템이 우분투에 그대로 내려와서 '우분투 패키지 매니지먼트'로 불리우는 것이다. )

3.
만약 인스톨 하려는 패키지 A가 전제조건적( A설치 이전에 필요한 ) 패키지 B, C, D...에 대한 의존성을 지니고 있다면, 매니저가 자동적으로 그 모든것들을 합쳐서 한번에 설치, 처리해준다.

4.
거의 대부분 사용되는 패키지관련 commands 
      + apt-get update :
모든 패키지를 최신으로 업데이트,
      + apt-get install <pkg-name> :
해당 패키지를 설치한다.

5. '4번' 에서의 명령어를 이용하여 터미널(Windows의 cmd와 같음)에서 컴퓨터에게 명령하면 sources.list 라고 하는 파일에 저장되어있는 '주소'리스트들에서 해당 패키지를 찾는다.

예를 들어 현재 나의 sources.list 에는 [ J-POP 파일들이 모아져있는 A 주소 ], [ K-POP 파일들이 모아져있는 B 주소 ] 이 두 개의 '주소'만 있다고 가정하자. 내가 US 노래를 설치하고싶어 터미널에 명령어 apt-get install US SONG 를 입력하면, US SONG 에 해당하는 파일을 A 주소B 주소에서 찾아 볼것이고, US SONG은 K-POP 과 J-POP 의 범주에 속하지 않은 파일이므로 어느 주소에서도 찾지 못하고, 설치 명령을 수행하지 못할 것이다.

※ '주소'는 PPA (Personal Package Achive) 라는 software repository (소프트웨어 저장소) 서버 '주소'이다.

6.
우분투 패키지들에 관련된 한국 프록시 DB(데이타베이스, 위에서 말한 '주소'개념)는 가끔 싱크가 맞지않아
   sources.list 에 있는 모든 주소들의 끝부분에 달린
 ko(한국)를 en(미국)으로 바꾸는것을 추천한다.


그래서 우선 ARM 개발환경 구축을 하는데에 있어 가장 먼저 해야할것이


1.
우툰투 가동을 위한 VMplayer (첫번째 가상머신) 설치


2. VMplayer가 돌릴 수 있는(run) '우분투 OS' VMplayer용 이미지를 구한다.

3.
우분투를 설치한 VMplayer로 돌리기.


4. 
우툰부 OS 안에서 Terminal (Windows의 cmd 하고 유사)를 켠 후에 거기서 우분투 버젼의 QEMU 를 설치.


      ※ 상세하게 설명하는 QEMU 설치방법 :
 

   1.
리나로 프로젝트의 PPA(Personal Package Archive)를 추가한다.

PPA는 위에서 말한 '우분투 패키지 매니지먼트'에서 특정 패키지를 다운로드 하기 위한 하나의 '패키지들의 저장소(Repository)'로써, 웹 하드처럼 각각의 용도별로 서버에 파일들을 깔끔하게 '필요에 맞추어' 저장, 정렬해 놓은것을 말한다. 복잡하게 A 사이트에서 '바퀴 부품'을 받고, B 사이트에서 '차체 부품'을 받고, C 사이트에서 '유리 부품'을 받아 자동차 조립을 시작하지 않고, S 사이트에서 '바퀴 부품', '차체 부품', '유리 부품'을 한꺼번에 구해서 조립을 시작할 수 있게끔. 필요한 파일들끼리 모아둔 '주소'인 것이다.

US SONG 예시에서 [ J-POP 파일들이 모아져있는 A 주소 ], [ K-POP 파일들이 모아져있는 B 주소 ] 밖에 없는 source.list sudo add-apt-repository ppa:'US-POP 파일들이 모아져있는 C 주소' 명령어를 입력하면, 최종적으로 sourst.list 에는 C 주소가 추가된 'A, B, C' 총 3개의 주소가 존재하게 된다.

이렇게 add-apt-repository 명령어와 함께 자신이 추가하고 싶은 PPA를 커맨드해주면, 그 '주소'가 'sources.list'에 주소리스트에 추가가 된다. 

리나로 프로젝트
 단순하게 말하자면, ARM의 개발 향상을 위해 ARM 개발 소프트웨어와 ARM 오픈 소스들을 제공하는 그룹으로, 데비안(우분투) 패키지 서버에 'linaro' 카테고리를 마련하여 이런 ARM 개발 소프트웨어들을 담아두고 있다. 우리는 linaro 의 개발 환경을 그대로 따라서 ARM을 공부할것이기 때문에, QEMU도 linaro에 맞추어 설치하여한다. 즉, linaro에 최적화된 QEMU를 이용하기 위해서는 리나로 프로젝트의 PPA에서 QEMU 관련 툴을 다운받아야한다.

그래서 우선 linaro-maintainers/tools 퍼스널 패키지 아카이브를 추가하는 것이다.
( linaro-maintainers/tools 디렉토리 서버에 QEMU 관련 패키지들이 포함되있다.)


 

sudo add-apt-repository ppa:linaro-maintainers/tools



   2. 리나로 프로젝트 PPA가 source.list 추가되었으니, 혹시나 있을 구버전을 신버전으로 교체해주기 위하여 
      패키지 데이터베이스를 업데이트한다음 QEMU 관련 패키지들을 설치한다.


추가한 서버 '리나로/tools' 에서 qemu 관련 패키지는 qemu-user-static 와 qemu-system 이다.
우선 이들을 받기 이전에 linaro-maintainers/tools 에 포함되있는 파일들 중에 각종 구버젼들을 모두 새로운 버젼으로 바꾸어주는 매우 간편한 명령어 sudo apt-get update 를 이용해 업데이트 먼저 해주자.

 

sudo apt-get update

sudo apt-get install qemu-user-static qemu-system


 

이렇게 ARM을 위한 가상화 소프트웨어 QEMU를 모두 마련하였다.



우리가 ARM을 개발하기 위해 최종적으로 사용할 리나로(Linaro : Open source software for ARM SoCs / SoC 개발을 위한 '소프트웨어 모음'으로 우리가 사용할 OS도 있고, Versatile Express 라는 '가상 환경'도 있다.)를 그 QEMU 위에서 작용시킬것이다.

QEMU 위에서 작동시킬 '가상 이미지'를 만든 다음, SoC 개발을 위해 필요한것들만 모아놓은 'Linaro-Developer (custom-built Dedian-Linux)' OS 를 그 위에 설치하고, 'Versatile Express ARM Development Board'라는 'ARM 가상 환경'을 구축하여 ARM을 공부할것이다. 아래는 이에 대한 과정들이다.


5. 가상화 소프트웨어 QEMU 가 읽을 수 있는 vexpress.img 이미지 파일(크기는 2G)을 제작한다.

(흔히 DVD 이미지를 읽기위한 가상화 소프트웨어 DAEMON TOOLs를 생각하면 쉽다.)


qemu-img create -f raw vexpress.img 2G


우리가 vexpress.img 를 생성한 이유는 간단하다. 위에서 살짝 언급했던 DAEMON TOOL 로 큰 용량의 게임을 돌릴때, 여러 파일들을 들고 다닐 필요가 없고, 단지 '하나'의 '이미지 파일'만을 들고다니면 되니까 굉장히 간편하다. vexpress.img 와 이 DVD 이미지 파일간의 차이점이라면 단지 DVD 이미지 파일은 읽기만 가능하지만, vexpress.img는 그 안의 내용 파일들을 언제든지 수정 가능하다는 점이다.

쉽게 'ARM 개발 환경'을 큰 컴퓨터들을 들고 힘들게 관리할 필요없이, 이동성이 있는 USB나 SD카드에 저장해서, 컴퓨터 한 대를 간편히 들고다니는 것이다.


6. 리나로 홈페이지 http://www.linaro.org/ 에서 '다운로드 - Developer'란에서 hwpack_linaro-lt-vexpress-a9_20120221-1_armel_supported.tar.gz (Vexpress-a9 가상 하드웨어 환경을 위한 '하드웨어 팩')linaro-o-developer-tar-20120221-0.tar.gz (Developer를 위한 linaro 소프트웨어 모음) 를 다운받는다.

이렇게 우리는 Linaro가 제공하는 ARM을 위한 모든 환경들을 QEMU를 통해 가상디스크 vexpress.img에다 세팅할 준비가 다 되었다.


7. 리나로 홈페이지 http://www.linaro.org/ 에서 '다운로드 - Developer - Instruction' 을 읽으면서 세팅을 마친다.

사실 이 과정이 제일 힘든 과정이다. 홈페이지는 모두 영문자로 되어있고, 각 자신의 상황에 맞추어 세팅을 진행해야 하기 때문이다. 그러나 내가 1번 부터 설명한대로 따라왔다면, 수많은 케이스들 중에 단 하나의 케이스의 상황에 우리는 놓아져있는것이다. 그럼 다음 설명만 잘 따라오면 된다. 그런데, 만약 1번 부터 6번 까지의 과정을 거치지 않은 사람들은, 밑에 설명이 맞지 않을것이다. 이런 분들은 리나로 홈페이지의 Instruction을 읽어보면서 자신의 상황에 맞게 설치하길 권장한다.

> INSTRUCTIONS 해설과, 각 과정에 대한 이해. // 영문 원본은 리나로 홈페이지를 참조하세요.


Linaro Developer Platform Team
에서 출시된 우분투용 이미지들을 설치하기 위해서는 당신은 아래 설명된 2개의 아티펙츠(인공체)를 다운받아야합니다. 그리고 그것을 바이너리 이미지 ( vexpress.img 의 파일 정보를 보면 01010.. 바이너리 파일 포맷인 것을 볼 수 있다. )로 합쳐야하며 그 이미지(vexpress.img)를 SD카드나, USB 저장소에 저장하셔야합니다.


      + 이미지(image)의 정의

A disk image is a single file or storage device containing the complete contents and structure representing a data storage medium or device. A disk image is usually created by creating a complete sector-by-sector copy of the source medium(매체, 도구/복수형:media) and thereby perfectly replicating the structure and contents of a storage device.


Some disk imaging utilities omit unused file space from source media, or compress the disk they represent to reduce storage requirements, though these are typically referred to as
archive files, as they are not literally disk images.


 

[ 2개의 아티펙츠, 설명 ]

1. UX (User eXperience) root filesystem tarball : 이것은 보드와 독립적입니다.

-
여기서 UX의 의미는 쉽게 말하자면 '유저가 사용하고 싶어하는 것에 최적화한' 을 뜻합니다. Linaro는 ARM 개발 환경에 알맞게 모든 프로그램들과 root filesystem들을 사용하기 편하게 정리를 깔끔하게 해놓았으므로, ARM 개발 환경을 원하는 유저들은 이 tarball (파일들의 집합) 만을 다운받아 설치하면, 기타 다른 환경 세팅이 필요없이 완벽하게 설치됩니다. 이것이 유저가 편하다는 UX 의 뜻과 부합합니다.


2. Board package (hardware pack)

- hardware pack 이라고 부르는 것은 커널, bootloader와 같은 보드 특유의 bits와 보드 특유의 미들웨어 등을 제공합니다. 우리는 Board package Versatile Express with A9x4 CoreTile을 이용할것입니다. 당신에게 필요한 (하드웨어팩)이 무엇인지 판단하기 위해서 이 링크를 따라주세요.



 

Root filesystems hardware packs 에 대한 링크들은, ‘매달 출시 안내’를 언급하는 ‘출시 페이지’로 링크되어있습니다. 또한 우리는 구버젼의 daily snapshots뿐만 아니라 milestone builds의 아카이브(achive)들을 가지고 있습니다. (링크에 들어가시면 받으실 수 있습니다.)

이 두 아티펙츠를 모두 다운로드 한 후에, 당신은 linaro-media-create 툴을 사용하여, SD 카드에 당신의 이미지를 플래시할 수 있게 됩니다.

Installing linaro-media-create


From package in Ubuntu : 우분투 OS에 패키지가 있을때

 

다음 명령들은 Linaro tools ppa를 당신의 시스템에 추가하고, linaro-media-create를 인스톨할것이다.


$ sudo add-apt-repository ppa:linaro-maintainers/tools

$ sudo apt-get update

$ sudo apt-get install linaro-image-tools

 + 위 명령어의 뜻 :
linaro-image-tools
에 있는 linaro-media-create 를 이용하여, vexpress.img 에다가 root filesystems hwpack을 바로 다음 과정에서 플래시할것이다.

 

 


 

Generating an image for QEMU : QEMU를 위한 이미지 만들기

 

아래 명령어에서 환경 변수들을 세팅하여라, 당신은 바로 아래에 있는 명령에 의해 이 명령이 제공되는 여러 변수 값들이 무엇인지 알 수 있고, 각각의 알맞은 변수값들을 결정할 수 있다.

$ linaro-media-create --help | grep dev

 + 위 명령어의 뜻 :
--help 를 이용하여 linaro-media-create 라는 명령어가 어떤 변수들을 지니고 있고, 각 변수에 어떠한 값들이 들어가야하는지 알려달라.

 

위 명령어로 변수들을 결정하였다면 당신이 이미지(vexpress.img)와 hardware pack을 다운로드 했던 디렉토리에서 linaro-media-create를 실행하여라.


$ sudo linaro-media-create --rootfs ext3 --image-file vexpress.img --binary linaro-o-developer-tar-_ _ _ .tar.gz --hwpack hwpack_linaro-lt-vexpress-a9_ _ _ .tar.gz --dev vexpress-a9

   + 위 명령어의 뜻 :
--image-file :
QEMU-이미지에 의해 만들어진 이미지 파일을 적어라.
        - vexpress.img

--binary : 다운로드받은 linaro OS 파일을 적어라.
        - linaro-o-developer-tar-_ _ _ .tar.gz

--hwpack : 다운로드받은 하드웨어 환경을 적어라.
        - hwpack_linaro-lt-vexpress-a9_ _ _ .tar.gz

--dev : hwpack 인자에서 보드(하드웨어 환경) 식별자를 읽어서 적어라.

        - vexpress-a9 ( hwpack_linaro-lt-vexpress-a9 이므로)

※ 추가로, linaro-media-create 명령어 실행중에 VERIFICATION 에 대한 이야기가 나온다면, NO 라고 대답하여라. Installations MUST be performed WITHOUT VERIFICATION when perform linaro-media-create

 

이제, 당신의 file.img 이미지 파일로 아까 다운받았던 linaro root filesystems hwpack을 플래시 완료하였다. (바이너리 이미지로 합쳤다.)


 

Versatile Express support in QEMU


이 페이지는 QEMU Versatile Express의 상태(정보)를 간단하게 요약해놓았고, 어떻게 그 위에 Linaro snapshot을 작동시킬지 설명한다.


 

Status of Versatile Express support


Implemented components:

  • Quad-core A9MP
  • Up to 1GB RAM
  • SD/MMC card
  • CLCD graphics, keyboard and mouse
  • Serial ports
  • Timers and RTC
  • LAN9118 ethernet

Missing components:

  • No USB (no model of the ISP1761 USB chip)
  • No modelling of the Flash memory
  • Components like the PL341 dynamic memory controller, PL354 static memory controller, PL310 L2 cache controller are not implemented (not even as dummy registers). This causes no problems for Linux booting but will probably be needed if we want to run u-boot or the VE boot ROM or other low level setup code
  • No Trustzone support (either in QEMU's A9 core model or in the Trustzone address space controller etc on the board)
  • We provide a PL110 CLCD controller, not a PL111
  • No Compact Flash
  • No audio (no PL041 model)
  • We don't implement remapping low memory; it is always RAM
  • No support for running the VE boot ROM -- you must provide the kernel and initrd directly to qemu

이중에서 몇 개의 구성요소들이 없더라도, Versatile Express 모델은 일반적으로 작동한다. Support (Support는 작동중인 키보드와 마우스 supprt를 포함한다.) Linaro 이미지들이 root prompt display graphics를 부팅하기 위해 완벽하다. 이 support들은 ‘versatilepb’ 또는 ‘realview-pbx’ 모델들을 위해 존재하는 QEMU support와 거의 같은 레벨이거나, 더 높은 레벨의 수준이다.




Creating Linaro Versatile Express images for qemu-linaro


 

이 과정을 수행하는 방법들 중에, 제일 간단한건 releases.linaro.org 에서 vexpress SD 카드 이미지 파일을 받는것이다. (예를 들어 images/12.01/oneiric/nano/ -- 다른 릴리즈 혹은 이미지 취향에 맞게 조정해서 다운받아라.) 아니면 만약에 당신이 snapshot 이미지들을 다 마련한 이후의 단계에 있다면, 당신은 linaro-media-create 를 이용하여 당신만의 이미지(QEMU-img)를 만들 수 있다. 만약에 snapshot 이미지가 gzipped 되있다면 이미지를 Umcompress하라.

 

이제 당신은 snapshot 이미지 파일로 부터 kernel initrd 를 추출해야한다.


 + initrd :
a scheme for loading a temporary file system into memory in the boot process of the Linux kernel. initrd and initramfs refer to slightly different methods of achieving this. Both are commonly used to make preparations before the real root file system can be mounted.

 

아래에 (IMG=vexpress.img...로 시작하는 커맨드는 마운트가 될 '파일(file)'과 이미지 파일에서 두번째 파티션의 offset(어떤 주소로부터 간격을 두고 떨어진 주소와의 거리)를 찾아 내기위한 'awk'를 이용한다. 그리고 나서 /mnt/mnt에 루프백 마운트를 이용하여 마운트 시킨다.


 + awk :
a data extraction and reporting tool that uses a data-driven scripting language consisting of a set of actions to be taken against textual data (either in files or data streams) for the purpose of producing formatted reports. : 자료 처리 및 리포트 생성에 사용하는 프로그래밍 언어


우선 리나로 가상 디스크를 마운트하기 위한 디렉토리(파일)를 준비한다


$ sudo mkdir /mnt/mnt


그리고 가상 디스크를 /mnt/mnt에 마운트한다. (virtual disk 마운트)


(IMG=vexpress.img ; if [ -e "$IMG" ] ; then sudo mount -o loop,offset="$(file "$IMG" | awk 'BEGIN { RS=";"; } /partition 2/ { print $7*512; }')" -t auto "$IMG" /mnt/mnt; else echo "$IMG not found"; fi )


위의 마운트 과정에 의하여 모든 파일 세팅이 /mnt/mnt 안에서 이루어진다. /mnt/mnt/boot 에는 마운트 과정에서 boot에 관련된 모든 파일들이 저장되는데, 이 boot 관련 파일들을 '현재 머물러있는 경로'라는 의미의 '로컬'의 boot 파일로( = local/boot )로 모든 kernel initrd 을 복사한다.
(kernel initrd 를 추출하는 과정이다.)


$ sudo cp -vr /mnt/mnt/boot .

$ sudo chown -R kauce:kauce boot

$ sudo umount /mnt/mnt

 

USB와 SD카드에 우리가 추출한 'boot 파일 전부'(kernel 과 initrd 를 포함하고 있다.)와 'vexpress.img 파일'만을 들고다니면 어느 우분투 컴퓨터에서든 아주 빠른 시간내에 ARM 개발환경을 구축할 수 있다.

   + 최종적으로 USB에 담아야 할 자료들

* kernel, initrd 를 포함한 'boot 파일'
* 'vexpress.img'

 



8. 이렇게 해서 추출된 kernel(커널)initial ramdisk(initrd), 그리고 virtual disk를 가지고 QEMU 가상 머신을 실행시키면, 우리의 최종 목적인 'ARM 개발 환경 구축'이 끝난다.

 

$ qemu-system-arm kernel boot/vmlinuz-3.2.0-1800-linaro-lt-vexpress-a9 -M vexpress-a9 -cpu cortex-a9 -serial stdio m 256 initrd boot/initrd.img-3.2.0-1800-linaro-lt-vexpress-a9 -append 'root=/dev/mmcblk0p2 rw mem=256M raid/noautodetect console=ttyAMA0,38400n8 rootwait vmalloc=256MB devtmpfs.mount=0' sd vexpress.img


   + 위 명령어의 뜻 :
-
메모리는 256M 으로 하향조정하였다.

- kernel : OS Kernel image

- initrd : Initial ramdisk image

 

위 qemu-system-arm 명령어는 우리가 'ARM 개발 환경 구축'을 하고싶을때 마다 작성해야할 명령어이다. 보다시피 명령어 길이가 길기때문에 매 시간마다 이 명령어를 치기에는 약간 귀찮을 수 있다. 그래서 이 statement를 shell(.sh) 쉘 파일로 저장해놓아 명령어를 치는 대신에 쉘 파일만 실행시키면 간단하게 환경 구축을 끝낼 수 있다. 


arm.sh 라는 이름의 쉘 파일을 작성한다. '
chmod 755 arm.sh'로 설정하고, 이 파일을 실행하고 싶을때는 이 arm.sh 이 있는 디렉토리로 가서 './arm.sh'만 명령어에 작성해주면 된다. QEMU VM을 끄고싶다면 'shutdown -h now' 명령어를 작성해주면 된다.
 

   + 최종적으로 USB에 담아야 할 자료들

* kernel, initrd 를 포함한 'boot 파일'  - QEMU VM에서 OS를 boot하는데에 필요한 파일
* 'vexpress.img'                           - QEMU VM에서 수정, 작성된 내용들이 저장될 가상 하드디스크

* 'arm.sh'                                   - QEMU VM을 실행하기 위한 명령어 모임


명령어를 실행하였을때 (arm.sh) 펭귄이 나온다면, 모든 환경 구축이 끝난것이다.

 


WELCOME!

 

 

 

 

 

 

Posted by 하늘_

 

시스템 프로그래밍이란? <-> ‘애플리케이션 프로그래밍과 반대되는 개념이다.

e.g. 리눅스 커널 프로그래밍 (linux kernel)

 

프로그래머들이 시스템을 공부하는 이유는 프로그래밍에 있어 더 나은 퍼포먼스를 이끌어 낼수있기 때문이다.

가령, 네트워크 공부 중 '직접 링크 네트워크'에서 워크스테이션의 하드웨어적 개념들과 여러 특성들을 이해한 후에 여러 애플리케이션 코드를 공부하게 되면, 그 하드웨어에 맞추어 코드 최적화가 가능하다. ‘더 나은 퍼포먼스라는 말은 이렇게 하드웨어와 코드 사이의 긴밀한 관계를 알고 그 사이간에 여러 최적화를 하는 것을 뜻한다.

 

그리고 여러 버그들 중 거의 프로그래밍 상에서 찾지 못하는 버그는 하드웨어적인 것이 많다.

여러 공동 작업자들과 최소한의 충돌로 좋은 프로젝트를 이끌어 낼수도있다.

(거의 시스템 지식은 필수적이다. 후에, 회사에서 중대한 임무를 맡느냐, 하위층을 맡느냐.)

 

왜 우리가 찾지 못하는 버그들은 하드웨어적인 문제들이 많을까?

마치 '를 이용하는 인간들이 그들의 상식 선에서 수들을 다루는 것 처럼 코드를 짜는 프로그래머들도 그들의 상식 선에서 코드들을 다루게된다. 기본적으로 그 코드들이 돌아가는 것은 하드웨어이기에 당연히 하드웨어적 접근을 해야하지만, 프로그래머들은 가끔 우리 인간의 상식대로만 작성하게되어 상식적으로 아무 문제가 없다라고 여기게된다. 하지만 하드웨어는 우리와 다르기 때문에 우리가 생각하지 못한 문제점들이 생겨나는 것이다.

 

이렇게 우리의 상식과 벗어나는 하드웨어적 문제들(Tricks)중 몇 가지를 살펴보자.


x^2 >= 0


수학적(일반적 상식)으로는 맞는 말이다. (물론 x 는 실수) 그러나 컴퓨터에선 어떨까?

Floats - 맞는 말이다.

Ints - 부분적으로 틀리게된다.

40000 * 40000 = 1600000000

50000 * 50000 = 오류

(Int형이 가진 크기를 넘어서서 Overflow가 일어나고, 결과는 음수 값이 나와 버릴것이다.)


(x + y) + z = x + (y + z)


Ints -
맞는 말이다.

Floats - 틀린 말이다.

(1e20 + -1e20) + 3.14 -> 3.14

1e20 + (-1e20 + 3.14) -> 0 (오류)

(Floats 형은 알다시피 전체 비트에서 지수 부분 + 소수점 표현부분들이 섞여있다. Float형이라고 하는 제한된 비트 내에서 또 각자 부분들의 제한된 영역(Finite memory)을 가진다는 것이다. 소수점 표현 부분은 이러한 제한 때문에 1.000000000000000000000314 같은 매우 큰 격차를 지닌 소수점 표현들이 공존할 수 없게 된다. 그래서 컴퓨터는 자동적으로 뒤에 작은 수들을 잘라버리는데, 이 때문에 작은 수치는 무시되게 된다.)

 

시스템 프로그래밍과 시스템의 전반적인 것을 다 배우고 나면 우리는 (일반 상식과는 다른) 하드웨어를 포함한 넓은 통찰력으로 프로그램을 짤 수 있게 되고, 시스템 프로그램, 시스템 분석 툴들도 작성할 수 있다.

 

수업에서 우리는 크게 ARM assembly Language 를 배울 것이다. 이런 언어들을 배우면서 언어가 가진 하드웨어적인 의미도 같이 공부해 본다.

 

 

왜 시스템 프로그래밍에서 ARM 을 배울까? ARM x86 에 비해 더 시스템적이며, 차후에 우리가 ARM 기반 시스템들에 대한 시스템 프로그램을 이용할 기회가 많을 것이다. PC 계를 제외한 여러 장치들에 거의 ARM 아키텍쳐를 사용하고있기 때문이다.

 

물론 Assembly Language는 이용할 날이 많진 않을것이다. 여러 exe 형태의 파일들의 원 소스를 파악하기 위해 디어셈블, 디컴파일을 하는데 이 과정에서 나오는 코드가 어셈블리 형태로 구성되어있어서, 이를 이해하는 것 외에는 크게 직접적으로 사용할 일이 없을것이다.

 

(ARM(Advanced RISC Machine) 아키텍처는 임베디드 기기에 많이 사용되는 32-bit RISC 프로세스이다. 저전력을 사용하도록 설계하여 ARM CPU는 모바일 시장에서 뚜렷한 강세를 보인다.)

      + RISC ( <-> CISC )

: RISC(reduced instruction set computer)
CPU 명령어의 개수를 줄여 하드웨어 구조를 좀 더 간단하게 만드는 방식으로, 마이크로프로세서를 설계하는 방법 가운데 하나이며, SPARC, MIPS 등의 아키텍처에서 사용된다.


전통적인 'CISC CPU'에는 프로그래밍을 돕기 위한 많은 수의 명령어과 주소 모드가 존재했다. 그러나 그중에서 실제로 쓰이는 명령어는 몇 개 되지 않는다는 사실을 바탕으로, 적은 수의 명령어만으로 명령어 집합을 구성한 것이 RISC이다. 그래서, RISC CISC보다 구조가 더 단순하다. 복잡한 연산도 적은 수의 명령어들을 조합하는 방식으로 수행이 가능하다.


그리고 CISC 형식의 CPU ROM에 소프트웨어적으로 적재된 내부 명령어들을 하드웨어적으로 구성하여 제어기(장치 드라이버 = 소프트웨어 드라이버 : 높은 수준의 컴퓨터 프로그램들이 컴퓨터 하드웨어 장치와 상호 작용하기 위해 만들어진 하나의 컴퓨터 프로그램)가 제거된 부분에 '프로세서 레지스터 뱅크' '캐시'를 둔다. 이렇게 함으로써 CPU, 상대적으로 느린 메인 메모리에 접근하는 횟수를 줄여주어 파이프라이닝 등 시스템 수행속도가 전체적으로 향상된다.)


> 특징


* 고정 길이의 명령어를 사용하여 더욱 빠르게 해석할 수 있다.

* 모든 연산은 하나의 클럭으로 실행되므로 파이프라인을 기다리게 하지 않는다.

­* 레지스터 사이의 연산만 실행하며, 메모리 접근은 세이브(save), 로드(load) 등 명령어 몇 개로 제한된다. 이렇게 함으로써 회로가 단순해지고, 불필요한 메모리 접근을 줄일 수 있다.

* 마이크로코드 논리를 사용하지 않아 높은 클럭을 유지할 수 있다.

* 많은 수의 레지스터를 사용하여 메모리 접근을 줄인다.

* 지연 실행 기법을 사용하여 파이프라인의 위험을 피한다.


CISC
에서는 하드웨어가 '스택'을 지원하지만, RISC에는 없다. 스택 제어(데이터의 PUSH, POP이 발생할 때 레지스터의 퇴피, 서브루틴에 점프했을 때의 리턴 주소의 보존, 복귀)의 처리는 단순한 명령을 조합하여 소프트웨어로 구현된다. 명령어의 순서로 인해 발생할 수 있는 파이프라인의 위험은 컴파일하는 동안 최적화되어 사라진다.


명령어의 길이를 고정하면 파이프라인 처리의 고속화를 꾀할 수 있지만, 컴파일러의 최적화 과정이 복잡해지기 쉽다.


RISC
는 대부분의 현대 프로세서 디자인에 채택되고 있고, 또 비교적 전력 소모가 적기 때문에 임베디드 프로세서에도 채택되고 있다.


요즘에는, 펜티엄과 같은 CISC CPU도 내부적으로는 복잡한 명령들을 단순한 명령들로 나누어 파이프라인에서 처리하기 때문에, 실제 작동 원리는 RISC와 같다.


-> ARM
계열 - 최신 팜 파일럿 PDA 시리즈. 게임보이 어드밴스, 닌텐도DS과 같은 닌텐도사의 소형 게임기 하드웨어. 한국 게임파크사의 GP32 하드웨어, 스마트폰, 태블릿pc.


      + 장치 드라이버 Device Driver
 

장치 드라이버(문화어: 장치구동기, 장치구동프로그람)디바이스 드라이버, 장치 제어기 또는 소프트웨어 드라이버라고 한다. 높은 수준의 컴퓨터 프로그램들이 컴퓨터 하드웨어 장치와 상호 작용하기 위해 만들어진 하나의 컴퓨터 프로그램이다.

드라이버는 흔히 컴퓨터 버스, 또는 하드웨어와 이어진 통신 하위 시스템을 통해(e.g. I/O버스 - 네트워크 어댑터) 장치와 통신한다. 요청하는 프로그램이 드라이버의 명령어들을 불러내면, 드라이버는 장치에 명령어들을 제공한다. 장치가 드라이버에게 데이터를 되돌려 주면, 드라이버는 원래 요청한 프로그램의 명령어들을 불러낸다.


드라이버는 하드웨어에 의존하며 특정한 운영 체제를 따른다.

이러한 드라이버는 비동기 시간에 의존하는 하드웨어 인터페이스에 필요한 인터럽트를 다룰 수 있다.

장치 드라이버는 흔히 장치 칩의 레지스터에 접근하여 하드웨어를 제어하며 하드웨어와 주변 기기를 사용하는 프로그램의 중간 다리 역할을 한다.

      + 레지스터 register

[
하드웨어 레지스터 ]

 

컴퓨팅에서, 하드웨어 레지스터는 다른 종류의 '하드웨어 입출력 (I/O)'를 위한 저장공간이다.

하드웨어 레지스터는 주요 주변장치의 내부에 포함되어 있고, '메모리맵 I/O' '포트맵 I/O'의 의미에 따라서 컴퓨터의 '중앙 처리 장치(CPU)'를 나타낸다. 특히 초기화 동안에, "환경설정"과 주기능의 시작을 포함하는 하드웨어 레지스터의 일반적인 사용은,


1. "
버퍼 저장공간" (예시로 그래픽 카드를 위한 비디오 메모리),

2. 하드웨어 장치에 발생되는 주요한 사건 같은 "상황 보고"가 있다.


읽어진 하드웨어 레지스터는 프로세서에 의한, "읽기" "저장" 명령과 접근한 그것의 메모리나 포트주소를 포함한다. 하드웨어 레지스터는 워드로 주소화되지만, 레지스터를 읽거나 쓰는데, 가끔씩 워드의 몇 비트만 사용한다.


[ 스트로브 레지스터 ]

 

스트로브 레지스터는 데이터를 저장하지않는 하드웨어 레지스터이지만 접근할 때 동작을 트리거링 수단처럼 사용된다. 신호의 수단이다.


전자 제품에서 각각의 주변 기기들을 제어하기 위해 설계된 펌웨어 또한 장치 드라이버라고 한다. 장치 드라이버의 실제 예는 소스가 공개된 '리눅스 커널 소스'에서 /driver 디렉터리 밑에 있는 것을 참조하여 볼 수 있다.


 

      + '리눅스 커널' Linux kernel 이란?

리눅스 커널(Linux kernel)은 유닉스 계열 운영 체제의 '커널'이다. 'GNU 일반 공중 사용 허가서' 버전 2 (GPLv2) 아래에서 공개되었으며 전 세계적으로 배포자들이 개발한 리눅스는 가장 두드러진 '자유 소프트웨어 / 오픈 소스'의 본보기들 가운데 하나이다.

 

리눅스 커널은 1991년에 리누스 토르발스에 의해 생긴 말이다. 일찍이 '미닉스' 커뮤니티가 리눅스 커널에 코드와 개념을 제공하였다. 그 당시 'GNU 프로젝트' '자유 소프트웨어' 운영 체제에 필요한 요소를 많이 만들어 냈지만 자체 커널 'GNU 허드'는 완전하지 않았고 이용성이 없었다. 'BSD' 운영 체제는 법적 문제로부터 헤어나오지 못했다. 이는 초기 버전의 제한된 기능에도 불구하고 리눅스가 새로운 운영체제를 사용하기 위한 프로젝트로부터 코드를 채용한 개발자들과 사용자들을 빠른 속도로 모았다는 것을 말해 준다. 오늘날 리눅스 커널은 수많은 프로그래머로부터 기여를 받고 있다.


 

      + '유닉스 계열' Unix-like 이란?

유닉스 계열(Unix-like) 운영 체제는 유닉스 시스템과 비슷한 구조를 가진 운영 체제를 말한다. *nix라고 부르기도 한다.


유닉스 계열이라고 해서 '단일 유닉스 규격'을 따르거나 관련 인증을 받을 필요는 없다.

이 용어는 벨 연구소의 유닉스가 고안하여 기능을 에뮬레이트하도록 설계된 자유 소프트웨어 / 오픈 소스 운영 체제와 그리고 라이선스된 유닉스 소스 코드를 기반으로 하는 버전들을 포함하기도 한다. 이 용어에 대한 표준이 공식적으로 정의된 바는 없으며, 어떠한 운영 체제가 유닉스 계통이냐 아니냐에 대해 일부 의견차가 있을 수 있다.


유닉스를 본래 제작한 사람들 가운데 한 명인 '데니스 리치' 'GNU/리눅스'와 같은 유닉스 계열 시스템이 de facto(in fact : 표준이나 법에 관련이 없고, 보편적이지 않은 단지 사실적인)유닉스 시스템이라고 의견을 냈다. 에릭 레이먼드와 랍 랭글리(Rob Langley)는 유닉스 계열 시스템에 세 가지 종류가 있다고 언급하였다.


*
일반 유닉스:
대부분의 상표 유닉스 시스템은 이 분류로 들어간다.
*
상표 유닉스: 오픈 그룹이 단일 유닉스 규격을 충족하기 위해 결정한 시스템이다.
*
기능 유닉스: 유닉스 규격에 거의 상응하는 방식으로 동작하는 유닉스 계열 시스템이다.


      + GNU

      + 리눅스

      + '단일 유닉스 규격' Single UNIX Specification : SUS ?

 

단일 유닉스 규격(Single UNIX Specification : SUS)은 컴퓨터의 운영체제가 유닉스란 이름을 사용하기 위해 지켜야 하는 표준 규격의 총칭이다. SUS IEEE와 오픈 그룹(The Open Group)의 표준화 작업 결과물에 바탕을 두고 있으며, 오스틴 그룹이 개발 및 유지 관리를 담당하고 있다. 단일 유닉스 규격 이전에 존재하였던 'POSIX' ISO/IEC JTC1에서의 작업은 종료되어, 오스틴 그룹이 유지 관리 작업에 관여하고 있다.



>역사


1980
년대 중반, 단일 유닉스 규격은 여러 유닉스 계열 운영 체제의 인터페이스를 표준화하기 위해 시작된 한 프로젝트에 그 바탕을 두고 있다. 업체마다 다른 운영체제 사이의 소프트웨어 이식에 들이는 비용을 되도록 줄여 달라는 여러 운영체제를 운영하던 기업들의 요청으로 인해 표준화 프로젝트가 시작되었다. 표준화의 바탕이 되는 운영 체제로 유닉스가 선택이 되었으며, 이는 유닉스는 특정 회사 제품에 종속되지 않는 중립형 운영 체제로 받아들여졌기 때문이다. 이 표준화 프로젝트의 결과로 만들어진 것이 IEEE 1003 (ISO/IEC 9945 로 등록되었다) 다른 말로 'POSIX'이다.


1990
년대 초에 POSIX와는 별도로, 이른바 UNIX 전쟁의 결과로 몇 군데의 회사들이 COSE(Common Open Source Environment) 협정을 결성하여, Common API Specification 또는 Spec 1170이라 불리는 사양을 내놓은 바 있다. 이 사양은 무료로 입수할 수 있었기에 IEEE에게 접근 비용을 부담해야 하는 POSIX보다 널리 일반화되었다.


1998
, Austin Group이라 불리는 공동의 워킹 그룹이 이 사양들의 통합을 시작하여, 그 결과로 Single UNIX Specification version 3(단일 유닉스 규격 제3)이 탄생하였다.



> 상세내용


단일 유닉스 규격에서 규정하는 운영체제와 사용자 및 소프트웨어 사이의 인터페이스는 다음의 4 가지로 분류된다.


* Base Definitions :
표준 규격을 기술하는 데 사용되고 있는 정의와 규약 등의 목록과, 이에 따르는 운영체제가 반드시 제공해야 할 C 언어의 헤더 파일 목록
* Shell and Utilities :
유틸리티(명령)의 목록 및 셸(sh)의 내역
* System Interfaces :
제공되어야 하는 시스템 호출 및 C 라이브러리의 목록
* Rationale :
이상의 표준에 대한 해설


이 표준에 의한 사용자 명령 줄 인터페이스와 스크립트 인터페이스는 초기 '콘 셸'에 바탕을 둔 '본 셸'의 확장판인 'POSIX '이다. 이 밖에 사용자 레벨의 프로그램 또는 서비스, 유틸리티로는 awk, echo, ed 등 수백여개의 목록이 포함되어 있다. 프로그램 레벨에서 필요로 하는 서비스로는 입출력(파일, 터미널, 네트워크) 등이 있다.


표준에는 테스트 프로그램 모음인 PCTS(Posix Certification Test Suite)가 포함되어 있다. PCTS NIST에서 오픈 소스로 공개되어 있다.


이 사양을 만족하기 위해 AT&T의 유닉스 소스 코드를 사용하지 않아도 된다는 점에 주의해야 한다. (실제의 예로, IBMz/OS (OS/390)은 소스코드는 완전히 독자적으로 만들어졌으나, 'UNIX'란 이름을 사용하도록 허용받고 있다.)



> 인증마크


이 표준을 만족하는 운영 체제에 사용할 수 있는 마크가 2가지가 존재한다.

UNIX 98 - SUS Version 2 를 만족하는 운영체제에 붙일 수 있는 마크
UNIX 03 - SUS Version 3
를 만족하는 운영체제에 붙일 수 있는 마크

이 밖에도 예전에 존재하였던 UNIX 93 UNIX 95가 있다.



      + '커널' kernel 이란?

컴퓨터 과학에서의 커널(kernel)은 운영 체제의 핵심 부분으로서, 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다.



> 커널의 역할


커널은 운영 체제의 핵심 부분이므로, 커널의 역할 역시 운영 체제의 핵심 역할이라 할 수 있다.


*
보안

커널은 컴퓨터 하드웨어와 프로세스의 보안을 책임진다.


*
자원 관리

한정된 시스템 자원을 효율적으로 관리하여 프로그램의 실행을 원활하게 한다.

특히 프로세스에 처리기를 할당하는 것을 스케줄링이라 한다.


*
추상화

같은 종류의 부품에 대해 다양한 하드웨어를 설계할 수 있기 때문에 하드웨어에 직접 접근하는 것은 문제를 매우 복잡하게 만들 수 있다. 일반적으로 커널은 운영 체제의 복잡한 내부를 감추고 깔끔하고 일관성 있는 인터페이스를 하드웨어에 제공하기 위해 몇 가지 하드웨어 추상화(같은 종류의 장비에 대한 공통 명령어의 집합)들로 구현된다. 이 하드웨어 추상화는 프로그래머가 여러 장비에서 작동하는 프로그램을 개발하는 것을 돕는다. 하드웨어 추상화 계층(HAL)은 제조사의 장비 규격에 대한 특정한 명령어를 제공하는 소프트웨어 드라이버에 의지한다.



> 초창기의 커널


초창기의 컴퓨터에서 운영 체제 커널은 필수적인 것이 아니었다. 초기의 프로그램은 하드웨어 추상화나 운영 체제의 지원을 받지 않고도 컴퓨터만으로 불러들인 다음 실행될 수 있었으며, 이것은 초창기 컴퓨터들의 일반적인 운영 방식이었다. 다른 프로그램을 실행하기 위해서는 컴퓨터의 전원을 껐다가 켬으로써 다시 입력자료를 읽어들여야 하는 방식이었다. 이러한 과정이 반복되면서 사람들은 '로더' '디버거' 같은 작은 프로그램들이 상주해 있는 것이, 다른 프로그램으로 교체하거나 새로운 프로그램을 개발하는 데 유리하다는 사실을 알게 되었다. 이와 같은 로더, 디버거들이 초기 운영 체제 커널의 기초가 되었다



> 커널의 종류


*
단일형 커널(monolithic kernel : 모노리딕 커널) -
커널의 다양한 서비스 및 높은 수준의 하드웨어 추상화를 하나의 덩어리(주소 공간)로 묶은 것이다. 운영 체제 개발자 입장에서 유지 보수가 일반적으로 더 어려우나 성능이 좋다.


*
마이크로커널(microkernel) - 하드웨어 추상화에 대한 간결한 작은 집합을 제공하고 더 많은 기능은 서버라고 불리는 응용 소프트웨어를 통해 제공한다.


*
혼합형 커널(hybrid kernel) -
성능 향상을 위해 추가적인 코드를 커널 공간에 넣은 점을 제외하면 많은 부분은 순수 마이크로커널과 비슷하다. 수정 마이크로커널이라고도 한다.


*
나노커널(nanokernel) - 실질적으로 모든 서비스를 책임진다.


*
엑소커널(exokernel) - 낮은 수준의 하드웨어 접근을 위한 최소한의 추상화를 제공한다. 전형적으로 엑소커널 시스템에서는 커널이 아닌 라이브러리가 단일형 커널 수준의 추상을 제공한다.

 

 



      + CISC ( <-> RISC )


: CISC (Complex Instruction Set Computer)는 복잡한 명령어 집합를 갖는 CPU 아키텍처이다.

명령어가 복잡하기 때문에 명령어를 해석하는 데 시간이 오래 걸리며, 명령어 해석에 필요한 회로도 복잡하다. 보통 풍부한 어드레싱 기능을 갖추고 있어 명령의 직교성이 좋으며, 어느 어드레싱 모드에서도 임의의 연산을 수행할 수 있다.


연산에 대해서는 레지스터와 레지스터 연산, 레지스터와 메모리 연산, 메모리와 메모리 연산을 모두 갖추고 있는 것이 보통이다. 피연산자(operand) 2개에서 3개까지 지정할 수 있는 경우가 많다. , 메모리 1의 내용과 메모리 2의 내용의 논리곱을 취해 메모리 3에 넣는 일을 하나의 명령어로 수행할 수 있다.


C
언어의 연산자는 CISC PDP-11이 갖추고 있던 명령에서 나온 것이다. 인덱스 어드레싱시의 오프셋도 명령의 데이터의 길이에 맞추어 바뀌는 것이 많다. , 길이가 다른 데이터 사이의 연산에서도 연산 전에 자동적으로 부호 확장 등이 수행되기 때문에, 데이터 길이를 가지런히 하는 명령어가 필요 없는 경우가 많다. 하나의 명령어를 수행하는 처리가 복잡하기 때문에, 마이크로 프로그램 방식을 채택하는 경우가 많다.


주로 메인프레임이나 X86 호환 프로세서, 모토로라사의 MC 680x0 (68K)계열 프로세서에서 이 방식을 사용하고 있다. 펜티엄 시리즈와 같은 CISC CPU도 내부적으로는 복잡한 명령들을 다시 단순한 명령들로 나누어 명령어 파이프라인에서 처리하기 때문에, 실제 내부 작동원리는 RISC와 같다고 할 수 있다.


-> x86



이렇게 우리가 시스템 프로그래밍 수업으로 무엇을 얻으려는지, 시스템 수업을 위해서 우리는 ARM을 공부할것이고, ARM의 특성, 각 용어들의 정확한 정의들을 알아보았다. 그럼 이제는 ARM 수업에 앞서 환경을 구축해 놓아야한다.

다음 강의에는 'ARM 수업'을 위한 환경, 정확히 말하자면 ARM (SoC) 개발을 위한 개발환경(Develop Environment)을 구축하는 법을 알아보도록 하자.

 

 

 

 

 

 

Posted by 하늘_