RTEMS 어플리케이션에서 태스크의 실행은 rtems_task_start 함수를 통해 진행된다. 해당 함수는 커널에서 아래와 같은 과정으로 진행된다.

- RTEMS 어플리케이션 레벨에서 태스크의 정보를 인자로 받음

- RTEMS 어플리케이션 레벨의 함수는 RTEMS 커널의 Core 함수중 Thread 관련 함수를 호출


좀 더 자세하게 함수 호출 과정을 살펴보면 아래와 같다.

rtems_task_start 함수는 _Thread_Start 함수를 호출하고, 해당 함수는 _Thread_Ready 함수를 호출한다. 

해당 부분은 dormant 한지 if문을 통해 확인하고 호출된다.


_Thread_Start 함수에서는 태스크의 entry_point를 성정하고, _Thread_Ready 함수는 _chain_append_unprotected 함수를 통해 해당 태스크 노드를 체인의 끝에 삽입한다. 체인에 삽입되었다는 것은 앞으로 태스크가 실행이 될 수 있다는것을 말한다.


다시 rtems_task_start로 돌아오면 _Thread_Enable_dispatch 함수를 호출한다. 만약 _Thread_start에서 thread가 dormant 상태면 바로 _Thread_Enable_Dispatch함수를 호출하게 된다.




RTEMS 커널에 파일을 추가 혹은삭제를 하면 기본적으로 존재하는 Makefile을 수정하고 이를 반영시켜서 커널을 bootstrap 해주어야합니다.


만약 rtems-4.10/cpukit/score/inline에 test.h라는 파일을 추가하였다면 rtems-4.10/cpukit/score/Makefile.am 파일을 수정해야합니다.

해당 파일 외의 Makefile.in이나 preinstall.am은 bootstrap 과정에서 툴에의해 자동적으로 생성되는 파일이므로 수정할 수 없습니다.


RTEMS 커널 내부의 Makefile.am들은 대게 동일한 모습으로 작성되어있습니다.


Makefile.am의 내용은 아래와 같습니다.


Makefile.am에는 헤더부분과 *.c 코드등이 세부적으로 나누어 작성되어있으므로 자신이 수정해야할 부분을 찾기 쉽습니다.

위에서 추가한 test.h을 include_rtems_score_HEADERS에 아래와 같이 추가해주도록 합니다.



이후 파일을 저장하고 닫은 뒤 rtems 커널 최상단으로 이동하여 bootstrap 과정을 다시 진행합니다. 

우선 기존의 preinstall과 같은 파일들을 삭제한 뒤 다시 생성해주는 과정이 필요합니다.


  $ ./bootstrap -c

  $ ./bootstrap -p

  $ ./bootstrap 


bootstrap 과정을 마치면 자신이 생성한 파일이 커널을 make할 때 포함되게 됩니다.





RTEMS 커널을 빌드하기 위해서는 Sparc RTEMS Cross Compiler(RCC)와 RTEMS 커널 소스가 필요합니다.


Sparc RCC와 커널 소스는 Gaisler의 홈페이지(http://gaisler.com/index.php/downloads/compilers)에서 받을 수 있습니다.

이외의 버전은 RTEMS github(https://github.com/RTEMS/rtems)에서 받을 수 있습니다.


RCC의 설치 및 설정은 이전글인 "Ubuntu에서 LEON 용 RTEMS Corss Compiler (RCC) 설치하기" 를 참고하시면 됩니다.


현재 안정화 버전은 4.10이므로 4.10을 기반으로 진행합니다. 

(4.11 이상의 버전에서는 source-builder 라는 툴을 사용해서 커널을 컴파일할 수 있어서 좀 더 편리해진 것 같습니다.)


RTEMS에서의 커널 컴파일은 크게 2가지로 나누어집니다.

1. 커널 bootstrap

2. 커널 configure 및 make


1. 커널 bootstrap

커널 bootstrap 과정은 커널에서 파일을 추가, 삭제하거나 변경된 경우에만 진행하면 됩니다. 이외의 경우는 configure 과정을 바로 진행하면 됩니다.

bootstrap 과정은 아래의 3가지 명령어를 통해 클린-생성-bootstrap 과정을 진행하게 됩니다. 

생성 과정에서는 *.am 파일들과 같이 bootstrap에 필요한 파일을 생성합니다.


아래의 과정은 RTEMS 커널 디렉터리로 이동한 후 진행하면됩니다.

  $ ./bootstrap -c

  $ ./bootstrap -p

  $ ./bootstrap 


 bootstrap 과정은 아래의 스크린샷과 같이 진행되며 약 5~10분 정도 소요됩니다. 만약, bootstrap 과정 중에 문제가 발생해도 끝까지 진행되므로 마지막에 정상적으로 진행되었는지 확인할 필요가 있습니다.

./bootstrap -c


./bootstrap -p


./bootstrap



2. 커널 configure 및 make

1에서 진행한 bootstrap 과정이 정상적으로 끝나면 커널 소스 디렉터리에서 나와 새로운 디렉터리를 만들도록 합니다.

저는 leon3를 타겟으로 하기때문에 leon3라는 디렉터리로 만들었습니다. 


우선 bootstrap 과정에서 생성된 configure 파일을 통해 커널을 설정해주어야 합니다. 

여기서 중요한 부분은 자신의 RCC가 bashrc에 잘 적용되어있는가입니다. 


configure 과정은 자신이 원하는 부분에 따라 다를 수 있으므로 configure 내용을 확인하고 진행하는 것이 좋을듯합니다.

저는 아래와 같이 configure을 하였습니다.


   $../rtems-4.10/configure --target=sparc-rtems --enable-rtemsbsp=leon3 --enable-posix --disable-samples --disable-tests


configure 과정에서 필요한 부분은 target 부분으로 자신의 RCC에 맞추어 설정해야합니다. 만약 RCC가 sparc-rtems4.10-xxx 라면 타겟에 sparc-rtems4.10 과 같이 적어주어야합니다. 

그리고 rtemsbsp 를 지정하지 않으면 leon3, erc32등의 다수의 bsp를 컴파일할 수 있고 특정 bsp들로만 구성하고 싶으면 --enable-rtemsbsp="erc32 leon3"와 같이 작성하면됩니다.

나머지의 옵션들은 작성하지 않으면 기본설정으로 설정 및 컴파일 되게됩니다.


configure 과정은 약 30초 내외로 진행되고 정상적으로 마치면 아래와 같이 출력됩니다.



configure 과정을 거치면 아래와 같은 파일이 생성됩니다.



이후 make 명령어를 입력하여줍니다. make 과정은 약 5~10분 정도 소요됩니다.


   $make


make 과정중에서 오류가 발생하지 않으면 아래와 같이 종료됩니다.



이제 make install을 입력합니다.


   $make install


make install 과정이 정상적으로 끝나면 아래와 같이 종료됩니다.



모든 단계를 마치면 아래와 같은 파일들이 생성된것을 볼 수 있습니다. 여기서 kernel 내용이 들어있는 부분은 sparc-rtems 디렉터리 입니다.



해당 디렉터리를  cp 혹은 mv  명령어를 통해 RCC가 설치된 폴더의 sparc-rtems에 덮어씌워주면 모든 과정이 끝납니다.


   $cp -r sparc-rtems /opt/rtems-4.10


만약 cp 과정을 없애고 싶으면 configure 단계에서 make install 경로를 설정해주면됩니다.



RTEMS C언어 어플리케이션은 아래의 소스코드 형태와 같이 가장 기본적인 설정(#define)이 포함되어야 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <bsp.h>
 
#include <stdio.h>
#include <stdlib.h>
 
#include <rtems.h>
 
rtems_task task1(rtems_task_argument unused);
 
rtems_task Init(rtems_task_argument ignored) {
    rtems_id tid;
    rtems_status_code status;
    rtems_name name;
 
    name = rtems_build_name('T''A''S''K');
 
    status = rtems_task_create(name, 1, RTEMS_MINIMUM_STACK_SIZE,
            RTEMS_NO_PREEMPT, RTEMS_FLOATING_POINT, &tid);
    if (status != RTEMS_SUCCESSFUL) {
        printf("rtems_task_create failed with status of %d.\n", status);
        exit(1);
    }
 
    status = rtems_task_start(tid, task1, 0);
    if (status != RTEMS_SUCCESSFUL) {
        printf("rtems_task_start failed with status of %d.\n", status);
        exit(1);
    }
 
    status = rtems_task_delete(RTEMS_SELF);
    printf("rtems_task_delete returned with status of %d.\n", status);
    exit(1);
}
rtems_task task1(rtems_task_argument unused) {
    for( ;; )
}
 
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
 
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_MAXIMUM_TASKS 3
 
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
cs


가장 기본적인 형태로 Init 함수에서 rtems_task_create 함수를 통해 새로운 RTEMS 태스크를 생성한다.


인자로는 RTEMS 태스크의 이름, 우선순위, 스택 크기, 모드, 특성, id 값이 필요하다.


- 이름          : rtems_build_name 함수를 사용하여 형식에 맞도록 생성해준다.

- 우선순위    : 1~255의 값을 가지며 낮을수록 높은 우선순위를 뜻한다.

- 스택 크기   : 최소한의 스택크기로 설정하는 것이 좋다. 

  이를 위해 RTEMS_MINIMUM_STACK_SIZE 를 사용하는데 해당 값은 시스템 마다 상이하다.

- 모드          : 선점형(RTEMS_PREEMPT), 비선점형(RTEMS_NO_PREEMPT), 

  타임슬라이싱(RTEMS_TIMESLICE), ASR(RTEMS_ASR/RTEMS_NO_ASR) 등

   '|' 를 사용해 여러가지를 복합적으로 사용할 수 있다.

   가장 기본적인 모드의 사용은 RTEMS_DEFAULT_MODES를 사용한다.

- 특성          : 부동 소수점(RTEMS_NO_FLOATING_POINT/RTEMS_FLOATIONG_POINT), 글로벌/로컬(RTEMS_GLOBAL/RTEMS_LOCAL)


RTEMS를 Linux에서 Cross Compile 하기 위해서는 해당 Cross Compiler가 필요합니다.

(RTEMS: https://www.rtems.org/ ,https://en.wikipedia.org/wiki/RTEMS)


특히 지금 사용하고 있는 Sparc 프로세스에 맞추어 만들어진 Cross Compiler가 필요합니다.

Cross Compiler에 대한 설명은 https://en.wikipedia.org/wiki/Cross_compiler를 참고하시면 됩니다.


크로스 컴파일러를 사용할 수 있는 환경을 일일이 설치하려면 각 프로그램 사이의 버전에 대한 의존성을 확인해야 하므로 번거로울 수 있습니다.


따라서 저는 Gaisler 에서 제공하는 Sparc RTEMS Cross Compiler(RCC)를 다운받아서 설치를 하였는데, 해당 크로스 컴파일러는 Sparc(LEON, ERC32) 용 RTEMS를 Linux에서도 컴파일할 수 있도록 해줍니다.


하지만 이러한 컴파일러를 위해서는 리눅스 유틸리티 중에서 autoconf 와 automake를 요구합니다.

- autoconfhttps://en.wikipedia.org/wiki/Autoconf

- automakehttps://en.wikipedia.org/wiki/Automake


제가 RCC를 사용하는 시스템의 사양은 아래와 같습니다.

- OS: Ubuntu 14.04.1 LTS x86

- Compiler: sparc-rtems-4.10(gcc-4.4.6-1.2.14)

- Tools: autoconf-2.69, automake-1.9.6


툴의 설치 순서는 다음과 같습니다.

autoconf 설치 - automake 설치 - RCC 압축해제 및 폴더 이동 - 실행 경로 변수 추가(bash)


주의하실 점은 automake를 autoconf 전에 설치하면 에러가 발생할 수 있습니다.


1. autoconf 설치

1) 파일 압축해제

# tar -jxf autoconf-2.69.tar.bz2


2) 설정 준비 및 설정

(1) configure를 위해 디렉터리 생성

# mkdir autoconf-2.69/build

# cd autoconf-2.69/build


(2) 설정

../configure --prefix=/usr


3) 설치

# sudo make 

# sudo make install


2. automake 설치

1) 파일을 압축해제 한다.

# tar -jxf automake-1.9.6.tar.bz2


2) 설정 준비 및 설정

(1) configure를 위해 디렉터리 생성

# mkdir automake-1.9.6/build

# cd automake-1.9.6/build


(2) 설정

# ../configure --prefix=/usr


3) 설치

# sudo make 

# sudo make install


3. RCC 설치

1) RCC 압축해제

# tar -jxf sparc-rtems-4.10-gcc-4.4.6-1.2.14-linux.tar.bz2


2) 디렉터리 이동 (/opt/)

# mv -f rtems-4.10 /opt/


3) 환경변수 설정

# sudo vi ~/.bashrc

bashrc 파일에 다음을 입력한다.

# export PATH=/opt/rtems-4.10/bin:$PATH


위의 과정을 수행한 후, 환경 변수 설정이 잘 되었는지 확인하기 위해 명령 프롬프트에서 "sparc-rtems-" 명령을 입력한 후 tab을 눌러 자동완성이 되는지 확인합니다.

그리고 컴파일러가 잘 동작하는지 확인하기 위해 RTEMS 샘플 코드를 작성하여 컴파일이 정상적으로 동작하는지 확인합니다.


샘플 코드:

#include <stdio.h>
 
void main(){
  printf("Hello World\n");
}


컴파일: 

 $ sparc-rtems-gcc -o main main.c


만약 컴파일 과정에서 libgmp.so.3 혹은 libmpfr.so.1 에러가 발생하면 다음과 같이 해결할 수 있습니다.

/opt/rtems-4.10/libexec/gcc/sparc-rtems/4.4.6/cc1: error while loading shared libraries: libgmp.so.3: cannot open shared object file: No such file or directory


해당 에러는 /usr/lib 디렉터리에 libgmp.so.3 파일이 존재하지 않아 발생하는 문제이기 때문에 아래와 같이 gmp를 설치해서 해결할 수 있습니다. 

(gmp의 다운은 http://ftp.gnu.org/gnu/gmp/에서 받을 수 있습니다. 저는 5.1.3 버전을 사용하였습니다)

1) 압축해제

# tar xfz gmp-5.1.3.tar.gz


2) 설치

# ./configure

# sudo make

# sudo make install


3) 파일 복사

현재 gmp 라이브러리가 설치된 경로는 /usr/local/lib/ 로 해당 디렉터리에 있는 libgmp.so.x 파일을 /usr/lib/ 로 복사해 주어야 합니다. 

5.1.3의 설치 결과로 libgmp.so.10 파일이 생성되었습니다.

# sudo cp /usr/local/lib/libgmp.so.10 /usr/lib/libgmp.so.3


/opt/rtems-4.10/libexec/gcc/sparc-rtems/4.4.6/cc1: error while loading shared libraries: libmpfr.so.1: cannot open shared object file: No such file or directory


해당 에러도 위의 에러와 마찬가지로 /usr/lib/ 에 해당 파일이 존재하지 않아서 발생하는 문제입니다. 

그러므로 mpfr을 설치해서 해결할 수 있습니다. 

(mpfr의 다운은 http://www.mpfr.org/mpfr-current/#download 에서 받을 수 있습니다. 저는 3.1.2 버전을 사용하였습니다)


1) 압축해제

# tar xfz mpfr-3.1.2.tar.gz


2) 설치

# ./configure

# sudo make

# sudo make install


3) 파일 복사

/usr/local/lib/ 에 있는 libmpfr.so.x를 /usr/lib/ 에 복사해 주어야 합니다. 3.1.2 버전에서는 libmpfr.so.4 파일이 생성되었습니다.

# sudo cp /usr/local/lib/libmpfr.so.4 /usr/lib/libmpfr.so.1


이후 다시 컴파일해서 정상적으로 동작하는지 확인합니다.