2010년 2월 19일 금요일

개발환경 구축

<Host>

  • # cd /XHYPER320
  • #mkdir -p /PROJECT/WENDERS
  • #cd ... ../XHYPER320
  • #chmod 755 installer-xhyper320-tku.sh
  • ./installer-xhyper320-tku.sh /PROJECT/WENDERS/
  • yum -y install dialog
  • vi /etc/pam.d/gdm ==> line 2 주석
  • vi /etc/pam.d/gdm-password ==> line 2 주석
  • vi .bash_profile
PATH > :/usr/local/arm-linux-4.1.1/bin:
  • source .bash_profile
  • yum -y install tftp
  • yum -y install tftp-server
  • export LANG=C
  • setup

>Sysem service

>>(x) blootheth

>>(x) iptables 2개

>>(o) nfs

>>(x) sendmail

>>(o) tftp

  • vi board.sh

#!/bin/sh

ifconfig eth0 192.168.1.100 up

iptables -F

service iptables stop

service xinetd restart

service nfs restart

* iptables : IPv4 패킷 필터링 툴

* selinux : 내가 root일지라도 허가를 받아야하는 불편함때문에 해제시킴.

  • #vi /etc/selinux/config

SELINUX=enforcing

==> SELINUX=disabled

  • #vi /etc/hosts.deny 에서 All 이면 주석처리.
  • #mkdir /tftpboot
  • #vi /etc/xinetd.d/tftp

disable = yes

=> disable = no

 

=> server_args = -s /tftpboot 로 수정

  • #cd ... ./XHYPER320/IMAGE
  • #cp ./gtk.img /tftpboot
  • #cp ./zImage /tftpboot
  • nfs 설정
    • vi /etc/exports

/root/work/bsp/fs   (tab)   *(rw,no_root_squash)

    • exportfs
    • cd /root/work/bsp/fs/etc
    • find . | xargs grep "192.168.1.*"
    • service nfs restart
  • mkdir -p /root/work/bsp/fs/ldd
  • mkdir -p /root/work/bsp/kernel
  • mkdir -p /root/work/bsp/ldd
  • cp ... ./XHYPER320/Kernel/linux.tar.gz /root/work/bsp
  • cp ... ./XHYPER320/Filesystem/rootfs.tar.gz /root/work/bsp
  • cd /root/work/bsp
  • tar xvzf linux.tar.gz
  • mv ./linux/* ./kernel
  • rmdir linux
  • tar xvzf rootfs.tar.gz
  • mv ./rootfs/* ./fs
  • rmdir rootfs
  • cd /root/work/bsp/fs
  • cd ./etc
  • find . | xargs grep "192.168.1.*"
  • cd ../kernel
  • make menuconfig
    • Device Driver
      • N/W device support
        • Ethernet(10 or 100Mbit)
          • <*> DM9000 support
    • File system
      • N/W File system
        • <*> NFS server support
        • [*] root file system on NFS
        • esc esc esc ok <= save
  • cp .config .config_nfs
  • make WENDERS_NFS_defconfig
  • make   <= 커널 컴파일
  • cp ./arch/arm/boot/zImage /tftpboot/zImage_nfs
  • #yum -y install minicom
  • /root/board.sh <= 모두 ok 될때까지
  • minicom -s

<configuration>

>Serial port setup

>>A

>>>/dev/ttyS0

>>>enter

>>E    <== Bps/Par/Bits

>>>D  <== 38400

>>F     <== Hardware Flow Control No

>>enter

>Save setup as dfl

>Exit

 

 

<Target Board>

* power on

 

<minicom>

* enter를 쳐서 blob 명령창으로 이동

blob> setip (192.168.1.100 192.168.1.50 확인)

blob> tftp zImage_nfs

blob> nandwrite -z 0x80800000 0x00040000 0x00200000

 

<Host PC>

# cd /root/work/bsp/fs

# touch test

 

<Target Board>

# cd /

# ls <= test 파일이 있으면 nfs 성공!

  • Target Board에서 실행할 파일을 위해 Makefile 수정
    • #vi Makefile
...

KDIR := /root/work/bsp/kernel

...

GNU make & autotools

(1) make
  • make
    • 파일 관리 유틸리티
    • 파일 간의 종속 관계를 파악하여 기술
    • 파일(makefile)에 기술된 대로 컴파일 혹은 쉘 명령을 순차적으로 수행.
  • make 장점
    • 컴파일 시간 절약
    • 프로그램 종속 구조를 빠르게 파악 가능
    • 프로그램 관리 용이
    • 단순 반복 작업과 재 작성을 최소화 ==> 개발자의 시간 절약
  • make 기본동작
all : diary
diary : memo.o calendar.o main.o
gcc -W -Wall -o diary memo.o calendar.o main.o
memo.o : memo.c
gcc -W -Wall -o memo.o memo.c
calendar.o : calendar.c
gcc -W -Wall -o calendar.o calendar.c
main.o : main.c
gcc -W -Wall -o main.o main.c


(2) 기술파일 작성방법
  • 기술파일 작성
CC = gcc <== 매크로 정의
target1 : dependency1 dependency2
(tab) command1 # 주석처리
command2 \ <== 개행 같은 라인으로 인식
command3
  • 매크로 사용
    • 매크로 : 사용자 정의 변수에 특정한 문자열을 정의
    • 일관된 기술 파일 작성 가능 => 이식성과 융통성 높은 기술 파일 작성 가능
CC = arm-linux-gcc # 매크로 정의
...
$(CC) ... # 매크로 사용( or ${CC} )

NAME1 = stringA # 재귀적 확장 매크로
NAME2 := stringB # 단순 확장 매크로
NAME3 += stringC
NAME4 ?= stringD

A = $(B) BB # A = D CC BB
B = $(C) CC # B = D CC
C = D

a := $(b) bb # a = bb
b := $(c) cc # b = cc
c := d # c = d

NAME := string1 # NAME ==> string1 string2
NAME += string2

NAME1 := string1 # NAME1 ==> string1
NAME1 ?= string2
NAME2 ?= string3 # NAME2 ==> string3

CC = gcc
CFLAGS = -W -Wall
TARGET = diary

all : $(TARGET)
$(TARGET) : memo.o calendar.o main.o
$(CC) $(CFLAGS) -o $(TARGET) memo.o calendar.o main.o
...
clean :
rm -f *.o
rm -f $(TARGET)
    • 내부적으로 정의되어 있는 매크로가 있음(ex) CC = cc)
    • 내부적 정의 매크로 확인 :
      • #make -p |grep ^[[:alpha:]]*[[:space:]]*=[[:space:]]
    • 자동 macro
      • $^ : 현재 타겟의 종속 항목 리스트(확장자 규칙에서 사용 불가)
      • $@ : 현재 타겟의 이름
      • $< : 현재 타겟보다 최근에 변경된 종목 항목 리스트
  • 확장자 규칙 사용
    • 확장자 규칙 : 확장자(.c, .o, .S ...)에 따라 정의되어 있는 기술파일 항목
    • 기술 파일을 단순, 명료하게 할 수 있음
    • 내부적으로 정의되어 있는 확장자 규칙( %.o : %.c ... )
    • .SUFFIXES : .o .c ...
    • SRCS = $(wildcard *.c); OBJECT = $(SRCS:.c=.o)
    • OBJECT = $(patsubst %.c, %.o, $(wildcard *.c)) <= 3중에서 1을 2로 바꿔
  • 명령어 사용 규칙
    • cd ./tmp; rm -rf * ==> 문제 있음
    • cd ./tmp && rm -rf * ==> 다른 의미에서, 왼쪽이 참이면 오른쪽 수행
    • 에코기능 끄기 : .SILENT: or @cat file.txt
    • Error와 상관없이 수행 : .IGNORE: or -cat file.txt
    • Shell 변수 사용 : $$(HOME)
  • 재귀적 make 사용
    • 소스가 하위 디렉토리에 존재할 경우, 각 디렉토리를 순회하며 make 수행.
    • tree 명령어로 디렉토리를 tree 구조로 보여줌.
  • 조건부 수행
  • 함수의 사용
(3) Autotools 소개
(4) Autoconf 사용법
(5) Automake 사용법

end

2010년 2월 18일 목요일

Compile on Linux

(1) Quiz 1
* page fault : virtual memory에는 있는데, physical memory에는 없는 경우 발생.
* segmentation fault : virtual memory에도 없는 경우 발생.

< 그림 1 - 안그림 >

* PGD : 항상 연결됨.
* PTE : 항상 연결되는 것이 아님. 없으면 page fault가 발생해서 PTE에 연결시켜줌.


(2) GCC 특징
  • 전처리기, C 컴파일러, 어셈블러, 링커
  • gcc -v --save-temps -o hello hello.c
  • Using built-in specs : 컴파일시 꼭 필요한 옵션을 저장한 파일

    * hello.c --(cc1)--> hello.i --(cc1)--> hello.s --(as)--> hello.o --(collect2)--> hello
    1. 전처리 과정 : cpp0 or cc1
    2. 컴파일 과정
  • 어셈블리 소스로 컴파일 : cc1
  • 최적화 과정 : O0 ~ O3
  • 기계어 코드 생성 : as, ELF 포멧
    5. 링킹 과정 : collect2

* 심볼 : 메모리상의 주소를 가지는 모든 것
* 심볼 테이블 : .c 파일 내부에 사용된 심볼들의 정보가 들어있는 테이블

(3) 코드 최적화
    * 실행 파일이 수행될 때 속도와 메모리 사용측면에서 효율적으로 동작하는 코드를 생성하는  
      소프트웨어 기법
  • 컴파일 후 명령어 수행 횟수를 최소화 함으로써 성능을 높임.
  • 일반적으로 길이가 짧은 코드가 적은 명령어를 수행함.
  • 의도상 delay를 주는 경우가 아니라면 -O3 옵션이 최적화에 큰 역할 할 수 있음.

    * 고려 사항
  1. 속도
  2. 메모리 요구량
  3. 레지스터 사용량 - 아키텍처 의존적
  4. 파이프 라이닝 - 아키텍처 의존적
    * 코드 최적화 기법
  1. Loop Fusion : 루프 갯수 줄임
    • 반복문은 다른 연산에 비하여 상대적으로 많은 cycle을 요구
    • fusion이 가능한 반복문은 루프를 하나로 결함.
    • 효과적인 cache 사용으로 인한 성능상의 이득을 얻을 수 있음.
  2. Loop Unrolling : 루프 수행 횟수 줄임
    • 배열의 크기가 unrolling의 양의 배수가 되도록 작성.
    • for(i=0; i<ARRAY_SIZE;i++)    array_v[i];
    • => for(i=0; i<ARRAY_SIZE;i++) array_v[i] = i; array_v[i+1] = i + 1;
    • unrolling 갯수에 비례하지 않음.
    • register 이용 개수를 고려하여 작성해야 함.
    • unrolling의 깊이가 증가할수록 메모리 사용량 증가
  3. Loop Invariant Code Motion : 불변 계산은 상수로 만듬.
    • loop 내에 불변하는 계산들은 오버헤드를 유발함.
    • loop 내에서 불변하는 계산 값이나 함수를 코드 바깥쪽으로 분리
      • strlen()이 비교문에 들어가는 경우
      • 변하지 않는 사칙 연산 값
    • loop 내에 불변의 값을 상수 값으로 대체
    • 수식이 간단하다면 loop 안에서 계산하는 것이 더 효율적일 수 있음.
    • O3 옵션을 이용하면 최적화를 해줌(함수호출의 경우 O0에 대배하여 O3옵션으로 컴파일 하더라도 이득이 별로 없음.)
  4. Strength Reduction
    • 고비용의 연산자를 저비용의 연산자를 이용하여 연산되도록 코드 최적화
      • 나머지 연산을 비트 연산으로 대체
      • sin, cos, pow 등 수학함수를 호출하는 루틴 중 연산자로 계산시 간단하게 구현 가능한 부분에 대하여 연산자로 대체
      • 간단한 연산의 경우 산술연산을 하는 것이 효과적
      • 코드의 복잡도, 가독성, 속도 향상 등을 고려하여 최적화
  5. Count up to Zero
    • 루프의 종료조건을 0과 비교하는 것이 효율적
    • 대부분의 아키텍처에서는 0에 도달할 때 ZERO 플래그를 재설정하게 됨.
    • 변수를 0과 비교하게 되면 명시적인 비교문이 생략됨.
  6. Register Allocation
    • C 컴파일러가 변수를 위해 사용할 수 있는 레지스터 : r0 ~ r3, r4~r11 사용이 바람직.
    • 사용가능한 변수보다 많은 변수를 사용하면 stack에 저장
      • 변수들이 메모리에 저장됨(spilled)=>사실 대부분 cache에 저장될 것임.
    • 자주 접근되는 변수는 레지스터에 저장
    • 서브루틴 호출 시 매개변수 처리
      • 4개 이하 인자를 매개변수로 받는 함수가 효율적임(그 이상 stack에 쌓임)
      • 5개 이상의 매개변수를 받아야 하는 경우는 구조체를 이용하여 전달.
    • 일반적으로 전역변수를 사용하여 연산을 수행하는 것은 부가적인 오버헤드를 유발
    • 전역변수의 사용은 메모리 참조연산을 수반하기 때문에 전역변수를 사용하여 복잡한 연산을 하는 것은 비효율적임
    • 지역변수를 이용해 연산을 수행하고 그 결과값을 전역변수에 저장하는 게 효율적
    • 컴파일러에 의한 최적화 이유로 구조체를 이용한 매개변수 전달의 최적화가 상쇄될 수 있음
  7. Software Pipelining
    • 명령어마다 각기 다른 사이클 소요
      • 아키텍처마다 다름
      • ARM9TDMI
        • 덧셈, 뺄셈, 논리연산과 같은 ALU연산은 한 사이클 소요
        • 곱셈, 나눗셈은 오퍼랜드 값에 따라 다양한 사이클 소요
        • 분기 명령은 3사이클 소요
        • N개를 저장하거나 로드하는 경우 N 사이클 소요
        • 1개인 경우 2사이클 소요
        • PC를 로드한다면 2사이클 추가 소요
    • 배열에 값을 저장한 후 그 값을 바로 다음에 연산에 이용하면 stall 발생하면서 파이프 라인이 깨져서 더 많은 사이클 소요됨. 그러므로 loop 내에서 다음 명령라인이 바로 이전 연산에 종속되지 않도록 작성하는 게 중요함.
      • for(i... ... ...) ary1[i] = v1 + 1; ary12[i] = ary1[i] & 0xff00;
      • => for(i... ... ...) ary1[i] = v1 + 1; ary2[i] = v2 + 1; ... ary12[i] = ary1[i] & 0xff00; ...

* GCC 옵션
  • -S : .s 파일 생성, 전처리된 파일을 어셈블리 파일로 컴파일
  • -c : .o 파일 생성, as에 대한 어셈블까지만 수행하고 링크는 않함.
  • --save-temps : 컴파일시 중간과정 생성 파일을 현재 디렉토리에 저장
  • -I : 전처리과정에서의 탐색 디렉토리 추가
  • -D : 매크로를 외부에서 define할 때
  • -W : 부가적인 정보 제공
  • -Wall : 모든 경고 메시지 출력
  • -O0 : 최적화 하지 않음
  • -O2 : 최적화 기본 단위
  • -O3 : 가장 높은 레벨의 최적화
  • -Os : 사이즈 최적화 수행
  • -g : gdb에게 제공하는 정보를 바이너리에 삽입(g0 ~ g3)
  • -pg : 프로파일을 위한 코드 삽입(함수 호출 횟수나 수행 시간 분석 수행시)

2. QT 설치

(1) QT 개발환경(설치 목록)
  • QT/X11
    • x86 qt library
    • uic(User Interface Compiler for the Qt GUI toolkit) - UI 디자이너로 만든것 변환.
    • qvfb(qt virtual frame buffer) - 일종의 에뮬레이터
  • tslib
    • touch screen library
  • QT/E for x86
    • qt embedded library for x86
  • QT/E for arm
    • qt embedded library for arm


(2) QT 설치과정
  1. 임베디드 보드 툴체인 설치(크로스 컴파일 환경 구축)
  2. Xlib 개발 패키지 설치
  3. QT/X11 설치
  4. tslib 설치
  5. QT/Embedded for x86 설치
  6. QT/Embedded for arm 설치
  7. QT 동작 확인


(3) QT 설치
    1. 임베디드 보드 툴체인 설치(크로스 컴파일 환경 구축)
  • (이전에 이미 환경 구축함.)

    2. Xlib 개발 패키지 설치
  • 헤더파일 존재 여부 파악 : #ls /usr/include/X11
    
    3. QT/X11 설치
  • 다운로드 주소 : ftp://ftp.trolltech.com/qt/source/qt-x11-opensource-src-4.3.3.tar.gz
  • .bash_profile 파일 수정(path 추가)
  • qvfb 빌드

    4. tslib 설치
  • 다운로드 주소 : http://tslib.berlios.de/ , tslib-1[1].0.tar.bz2
  • config.h 파일 수정
  • input-raw.c 파일 수정
  • tslib 환경 파일 작성
  • ts.conf 파일 수정
  • tslib.env 파일 작성
  • ts device 설정
  • ts device 동작 확인
  • tslib 동작 확인

    5. QT/Embedded for x86 설치
  • 다운로드 주소 : ftp://ftp.trolltech.com/qt/source/ , qtopia-core-opensource-src-4.3.3.tar.gz
  • qte_x86_env 설정 파일 작성
  • qvfb 동작 확인으로 설치 확인

    6. QT/Embedded for arm 설치
  • 다운로드 주소 : ftp://ftp.trolltech.com/qt/source , qtopia-core-opensource-src-4.3.3.tar.gz
  • qte_arm_env 설정 파일 작성
  • tslib와 QT/E for arm 동작 확인
  • NFS를 이용한 라이브러리 설정
  • NFS를 이용한 tslib 환경 설정
  • NFS를 이용한 qt4 환경 설정 및 동작 확인
  • qt4_env 설정 파일 작성

    7. QT 동작 확인
  • tslib와 QT/E for arm 동작 확인
  • NFS를 이용한 qt4 환경 설정 및 동작 확인
  • qt4_env 설정 파일 작성

* 주의 사항
  • QT 응용 프로그램 작성 후 컴파일 시, 프로그램의 타겟 플랫폼에 따라 환경 설정을 바꿔줘야 함.
    • X11 : X11 용으로 컴파일한 qt library 패스 설정
    • x86 / qvfb : qvfb 용으로 컴파일한 qt embedded library 패스 설정
    • arm / FB : arm 용으로 컴파일한 qt embedded library 패스 설정

2010년 2월 17일 수요일

1.QT 소개

(1) QT의 특징
  • 멀티 플랫폼 C++ GUI Toolkit
  • C++ 기반의 객체지향 클래스 라이브러리(캡슐화, 상속, 다형성-오버로딩, 오버라이딩)
  • Signal / Slot 매커니즘(이벤트와 핸들러라고 생각하자.)

* 오버로딩 : 함수 이름은 같고, 함수 인자의 갯수를 다르게 정의.함
* 오버라이딩 : 함수를 상속받아 구현부만 다르게 정의함.
* Signal/Slot : 객체(Object)의 신호(Signal)를 다른 객체(Object) 슬롯(Slot)에 연결.

(2) QT 관련 사이트 : www.trolltech.com

* widget : 다이얼로그 or 클래스 같은 것.

* QT 라이센스 있음( 교육용은 무상 )

(3) QT 종류
  • QT/X11 : X11 환경
  • QT/Embedded : 임베디드 리눅스 환경
  • QT/Windows : MS-Windows 환경(여기선 Visual Studio가 강력함)

* Qtopia : QT/E에서 어플리케이션의 모음 같은 것.


2010년 2월 16일 화요일

Blob 분석

BLOB : Boot Loader OBject

 

(1) 소개

  • 네덜란드에서 개발한 Open Source의 Boot Loader 프로그램으로 Intel SA-1100 Micro-Processor를 사용한 LART(Linux Advanced Radio Terminal)라는 내장형 컴퓨터에 처음 사용됨.
  • blob-2.0.5-pre3 버전 소스 분석
  • ARM 기반에서 사용하는 대표적인 Boot Loader

    1.BLOB 기능

  • 하드웨어 초기화
  • 레지스터 설정을 통한 시스템의 활성화
  • 저장 매체로부터 Kernel을 읽어서 메모리의 적절한 위치로 적재
  • 압축을 풀고 Kernel로 제어를 옮김
  • 그 외 serial이나 ethernet 장치를 통해 Kernel이나 Ramdisk 등의 image를 다운로드

    2.BLOB 흐름도

 

     (1) Start stage : 하드웨어의 기본적인 초기화 및 레지스터 설정을 담당

     (2) Rest stage : Boot Loader의 부가적인 기능을 제공

 

 

 

    3. 단계별 분석

      3.1 Start Stage

      3.1.1 Boot Loader 시작

      3.1.2 start.S

      3.1.3 rest

      3.1.3.1 Disable All Interrupt

      3.1.3.2 CPU Speed Setup

      3.1.3.3 Memory Setup

      3.1.3.3.1 DRAM Configuration Register

      3.1.3.3.2 DRAM CAS Waveform Shift Register

      3.1.3.3.3 DRAM refresh Controller Register

      3.1.3.3.4 Enable SDRAM BANKS

      3.1.3.3.5 Static Memory Register Configuration

      3.1.3.3.6 SMROM Register Configuration

 

      3.1.3.4 LED Conguration( GPIO )

 

kkkkk

kkkk

 

2010년 2월 9일 화요일

하드웨어 통신 제어 및 인터럽트 처리

(1) 예외처리
  • 외부의 정상적인 요청이나 비정상적인 오류의 발생에 의해서 프로그램을 중지하고 발생된 요청이나 오류를 처리하는 것
  • 예외처리가 발생하면 처리해야 할 프로그램의 위치가 메모리의 특정한 위치에 지정
  • 예외 벡터 테이블


(2) 인터럽트
  • 디바이스는 프로세서와는 다른 시간 간격, 정확하게는 훨씬 느린 시간으로 수행됨.
    • 프로세서가 무작정 외부 이벤트를 기다리는 것은 바람직하지 못하므로 프로세서에게 뭔가 발생했다고 알릴 방법의 필요


(3) 인터럽트 처리
  • 인터럽트 핸들러(인터럽트 서비스 루티 - ISR)
    • 인터럽트를 처리하는 커널 함수
    • 디바이스 드라이버의 일부분
    • 인터럽트 컨텍스트에서 실행
  • 인터럽트 처리를 두 단계로 분리
    • Top half
      • 인터럽트 핸들러
      • 인터럽트가 발생하는 즉시 실행되는 타임 크리티컬한 작업들
    • Bottom half
      • 나중에 해도 무관한 작업들
      • 모든 인터럽트를 활성화시킨 상태에서 실행
        • (보통 인터럽트 핸들러가 리턴되면 실행)

(4) IRQ 인터럽트 서비스 처리 흐름
  • 처리 흐름
    • 프로세서마다 인터럽트 처리 방식이 다름
      • 발생된 IRQ 번호를 획득하여 do_IRQ() 함수 호출
    • 리눅스 커널에서는 동일한 처리를 위해 IRQ 인터럽트는 모두 do_IRQ() 함수를 호출하여 처리
  • request_irq() 함수를 이용하여 처리하고자 하는 IRQ 번호와 서비스 함수 주소를 등록
    • Ex) linux/include/asm-arm/arch-pxa/irqs.h
  • 인터럽트 발생 후
    • 아키텍처마다 고유의 IRQ 검출 루틴을 이용
    • do_IRQ() 함수는 irq_desc 전역변수에서 IRQ 번호에 맞게 등록된 인터럽트 서비스 함수를 찾고, 있으면 호출
    • 참조된 데이터의 주소나 값들은 인터럽트 서비스 함수의 매개변수인 dev_id에 전달
    • 인터럽트 처리가 필요없는 경우에는 free_irq() 함수 호출
      • irq_desc 전역변수에 등록된 인터럽트 서비스 함수를 제거


(5) 인터럽트 서비스 함수의 형식
  • irqreturn_t int_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  • 커널 2.4 - 반환 값은 void
  • 커널 2.6 - 반환 값은 IRQ_HANDLED
  • 매개변수
    • int irq - 인터럽트 번호(irqs.h에 정의)
    • void *dev_id - 인터럽트 서비스 함수를 수행할 때 필요한 정보가 저장된 메모리 주소
    • struct pt_regs *regs - 인터럽트가 발생했을 당시의 레지스터 값(디버깅용)

(6) 인터럽트 서비스 함수 내의 메모리 할당
  • 주로 사용하는 메모리 할당 및 해제
    • kmalloc()
      • GFP_ATOMIC 인자를 사용한 방식만을 사용
      • vmalloc() 함수로 인터럽트가 발생하기 전에 미리 할당한 메모리는 아무런 제약 사항이 없음.
      • kmalloc 할당 후 리턴값 확인 필수

irqreturn_t int_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
char *data;
...
data = kmalloc(128, GFP_ATOMIC);
if( data != NULL ){
...
kfree(data);
}
...
return IRQ_HANDLED;
}


(7)  인터럽트 서비스 함수 등록
  • #include <linux/interrupt.h>를 포함
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long flags, const char *device, void *dev_id);

  • 매개변수
    • irq - 인터럽트 번호
    • (*handler) - 해당 인터럽트 번호를 위한 인터럽트 서비스 함수 포인터
    • flags - 인터럽트 공유나 빠른 인터럽트 처리 등의 속성 지정
      • SA_INTERRUPT - 다른 인터럽트를 허용하지 않음
      • SA_SHIRQ - 동일한 인터럽트 번호를 공유
      • SA_SAMPLE_RANDOM - 랜덤 값 처리에 영향을 줌
    • device - 디바이스 이름(/proc/interrupt 에 쓰임)
    • dev_id - 인터럽트 공유시 구분인자, handler 함수가 참조하는 데이터의 주소 지정
  • request_irq() 함수
    • 정상적 수행시 0 리턴
    • 비정상적 수행시 음수 값 리턴
    • 인터럽트 함수를 등록하는 예
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
return IRQ_HANDLED;
}

int xxx_interrupt(struct inode *inode, struct file *filp)
{
if( ! request_irq(XXX_IRQ, xxx_ineterrupt, SA_INETRRUPT, "xxx", NULL) )
{
// 정상 등록 후 처리
}

return 0;
}


(8) 인터럽트 서비스 함수 해제
  • free_irq() 함수
    • 커널 2.4와 2.6 사용 동일
    • 등록되어 있던 인터럽트 서비스 함수를 제거
void free_irq(unsigned int irq, void *dev_id);

    • 인터럽트 서비스 함수를 제거하는 예
int xxx_release(struct inode *inode, struct file *filp)
{
// 하드웨어 인터럽트 금지 처리 루틴
...
free_irq(XXX_IRQ, NULL);
return 0;
}



(7) 인터럽트 서비스 등록과 해제 시점
  • 하나의 응용 프로그램만이 디바이스 파일을 사용하는 경우
    • 모듈 초기화, open() 함수 모두 ISR 등록 가능
  • 두 개 이상의 응용 프로그램이 디바이스 파일을 사용하는 경우
    • 모듈 초기화에서 ISR 등록을 주로 함
    • 이유
      • open()에서 등록할 경우 동일한 인터럽트 서비스 루틴이 두 번 등록 -> 구현이 복잡해지며, 에러 처리 고려
      • open()에서 등록할 경우 먼저 해제를 시도한 쪽에서 인터럽트 서비스 함수를 제거하는 경우 다른 쪽 응용 프로그램에서 사용하는 디바이스 드라이버는 인터럽트 서비스 함수가 동작하지 않음.
  • 결론
    • PC 같은 범용 시스템에 사용되는 디바이스 드라이버
      • open()과 close()에서 처리하는 것이 효율적
    • Embedded System에 사용되는 디바이스 드라이버
      • 모듈 초기화 및 모듈 해제 시점에서 처리하는 것이 효율적


(8) 인터럽트 함수와 디바이스 드라이버 간 데이터 공유
  • 인터럽트 서비스 함수는 프로세스 문맥과 별개로 동작하므로 인터럽트 서비스 함수와 디바이스 드라이버 함수 간에 데이터를 공유하는 방법이 필요함.
  • 공유 방법
    • 전역 변수
      • 인터럽트 하나에 인터럽트 서비스 함수 하나가 동작하는 경우
      • 동일한 인터럽트 서비스 함수로 여러 디바이스를 제어할 경우엔 사용 못함.
    • devi_id 매개 변수
      • 여러 디바이스를 하나의 인터럽트 서비스 함수에서 사용 가능
      • 다중 프로세스 환경에 매우 적합함.
/* dev_id를 이용한 데이터 공유 */
typedef struct {
unsigned long ioaddress;
unsigned long count;
} __attribute__((packed)) R_INT_INFO;

irqreturn_t count_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
R_INT_INFO *ptrInfo;
ptrInfo = (R_INT_INFO *)dev_id;
printk("INT READ I/O %02X\n", inb(ptrInfo->ioaddress));
ptrInfo->count++;

return IRQ_HANDLED;
}

int int_open(struct inode *inode, struct file *filp)
{
R_INT_INFO *ptrInfo;

ptrInfo = kmalloc(sizeof(R_INT_INFO), GFP_KERENL);
filp->private_data = ptrInfo;
switch( MINOR(inode->i_rdev) ){
case 0 : ptrInfo->ioaddress = 0x378; break;
case 1 : ptrInfo->ioaddress = 0x278; break;
}

if( ! request_irq(XXX_IRQ, count_interrupt, SA_INTERRUPT, "test", ptrInfo) ){
// 커널 함수가 아니고 임의의 인터럽트 제어 함수
enable_hardware_init(ptrInfo);
}

return 0;
}

int int_release(struct inode *inode, struct file *filp){
R_INT_INFO *ptrInfo = (R_INT_INFO)filp->private_data;

disable_hardware_int(ptrInfo);
free_irq(XXX_IRQ, ptrInfo);
kfree(ptrInfo);
return 0;
}


(9) 인터럽트 공유
  • 같은 인터럽트 번호에 다른 인터럽트 서비스 함수 등록 가능
    • request_irq() 함수의 매개변수에서 flags를 SA_SHIRQ 포함
    • dev_id : 0이 아닌 값 사용
  • 같은 인터럽트 번호에 대해 여러 인터럽트 서비스 함수가 동작할 경우
    • 인터럽트 서비스 함수는 자신이 관리하는 디바이스에서 인터럽트가 발생했는지를 확인하는 과정이 필요
    • 커널 2.6에서는 위의 오류 해결을 위해 인터럽트 서비스 함수의 반환 값을 확인하는 과정을 거침
      • 오류가 발생하면 해당 인터럽트를 금지, IRQ_NONE을 리턴
irqreturn_t xxx_inerrupt(int irq, void *dev_id, struct pt_regs *regs)
{
인터럽트_관리_구조체 * ptrMng = (인터럽트_관리_구조체 *)dev_id;
if( 자신의 인터럽트 처리 함수(ptrMng) )
{
// 인터럽트 처리
...
return IRQ_HANDLED;
}

return IRQ_NONE;
}


(10) 인터럽트 금지와 해제
  • 인터럽트 서비스 함수가 동작 중에 다른 인터럽트가 발생하지 못하게 막는 경우
    • request_irq() 함수의 flags를 SA_INTERRUPT를 사용함.
      • 커널이 프로세서의 인터럽트를 금지 시킨 후 호출
      • 인터럽트 두 개가 동시에 발생하면 SA_INTERRUPT가 설정된 함수 먼저 수행
  • 일반적인 함수 수행 중에 데이터 처리를 보호하기 위해 인터럽트를 강제로 막는 경우
    • #include <asm/irq.h> 포함
    • void disable_irq(int irq) : 인터럽트l 금지
    • void enable-irq(int irq) : 인터럽트 허가
    • void disable_irq_nosync(int irq) : 현재 핸들러가 종료할 때까지 기다리지 않음.
    • synchronize_irq(unsigned int irq) : 특정 인터럽트 핸들러가 실행 중일 경우 기다렸다가 실행이 끝나면 리턴
  • 프로세서 전체의 인터럽트를 금지하고 해제할 경우
    • #include <asm/system.h> 포함
    • local_irq_disable(void) : 프로세서의 인터럽트 처리를 금지
    • local_irq_enable(void) : 프로세서의 인터럽트 처리를 허가
    • local_save_flags(unsigned long flags) : 현재의 프로세스 상태 저장
    • local_restore_flags(unsigned long flags) : 저장된 프로세스 상태 복구
  • 보편적인 인터럽트 방지법
unsigned long flags;

local_save_flags(flags);
local_irq_disable();

// 인터럽트 호출에서 보호하고자 하는 루틴

local_restore_flags(flags);
  • local_save_flags() 함수에 의해 저장된 flags 변수에 이미 인터럽트 허가 상태가 포함되어 있기 때문에 local_resstore_flags() 함수에 의해 local_irq_enable() 호출 효과 발생.


(11) 인터럽트 시스템의 현재 상태 체크
  • irqs_disabled()
    • 로컬 프로세서의 인터럽트가 비활성화된 경우 0이 아닌 값을, 활성화된 경우 0을 리턴.
    • #include <asm/system.h> 포함
  • in_interrupt()
    • 커널이 현재 인터럽트 컨텍스트에 있는 경우 0이 아닌 값을 리턴
    • 커널이 인터럽트 핸들러 혹은 Bottom half 핸들러를 실행중인 상태를 포함
    • #include <asm/hardirq.h> 포함
  • in_irq()
    • 커널이 인터럽트 핸들러를 실행 중일 때만 0이 아닌 값을 리턴
  • 프로세스 컨텍스트인가를 체크해야 할 경우
    • 휴면과 같은 프로세스 컨텍스트에서만 가능한 작업을 수행하기 위해
    • #include <asm/hardirq.h> 포함

디바이스 드라이버의 소개

(1) 장치 파일

 

  • 디바이스 드라이버를 접근하는 통로
  • 장치 파일의 inode는 장치 유형(type), 주번호, 부번호로 구성됨.
  • 장치 파일 생성

    • # mknod /dev/mydev [b|c] 240 0

 

 

(2) 디바이스 드라이버의 구성

  1. 초기화 인터페이스 - init_module() 함수
    • register_chrdev()
    • register_blkdev()
    • request_irq()
    • ...
  2. 시스템 인터페이스 - 문자/블록의 경우 file_operations 이용
    • 문자 드라이버 - open, release, read, write, ioctl
    • 블록 드라이버 - open, release, request, ioctl
    • 네트워크 드라이버 - open, close, transmit, receive, ioctl
  3. 하드웨어 인터페이스
    • in(), out()

 

 

(3) 새로운 디바이스 드라이버 작성 단계

 

  1. 디바이스 드라이버 커널 인터페이스 구현
    • file_operations
  2. 디바이스 드라이버 초기화 인터페이스 구현
    • 주 번호 할당 및 디바이스 드라이버 루틴 등록
  3. 디바이스 하드웨어 인터페이스 구현
    • 레지스터 접근
  4. 장치 파일 생성
    • #mknod /dev/mydev [b|c] major_number minor_number
  5. 응용 프로그램 작성
  6. 커널 컴파일 및 리부팅

 

 

(4) 자원 처리 요청 방법

  • 커널에 자원 처리를 요청하는 방법
    • 응용 프로그램이 커널에게 자원 처리를 요청하는 방법
      • 시스템 호출
      • 파일 입출력 형식을 이용한 디바이스 드라이버 사용

 

  • 시스템 호출 방법
    • Software Interrupt를 이용, 응용 프로그램에서 요청하는 처리를 커널이 수행

 

  •  파일 형식의 디바이스 드라이버
    • 일반 파일을 제어하듯이 디바이스 파일을 통해 하드웨어 입출력 시도
    • 커널 내의 해당 디바이스 파일에 연결된 디바이스 드라이버의 서비스 루틴이 호출되어 디바이스에 대한 처리
    • 모든 처리가 끝나면 커널이 제어 흐름을 다시 응용 프로그램에 넘기는 구조

 

 

(5) 모듈

  • 모듈은 커널이 부팅되어 동작 중인 상태에서 디바이스 드라이버를 동적으로 추가하거나 제거할 수 있게 하는 개념
    • 개발 기간 단축
    • PCI, USB, PCMICIA에 연계된 디바이스의 PNP 기능을 지원하기 위해 모듈 방식이 필수
      • 모듈 방식은 MMU가 있는 CPU에서만 지원
      • 동일한 커널 버전 사용 요구

 

 

(6) 디바이스 파일

  • 리눅스는 모든 하드웨어를 파일로 추상화
    • /dev/ : 디렉토리에 있는 파일들로 실제 하드웨어를 표현
  • 시스템 또는 하드웨어 정보 제공
    • 디바이스 타입정보(문자, 블록), 주번호, 부번호

(7) 디바이스 드라이버의 종류
  1. 문자 디바이스 드라이버 - 버퍼 없음
  2. 블록 디바이스 드라이버 - 버퍼 있음
  3. 네트워크 디바이스 드라이버
    • 커널 내부에 있는 네트워크 프로토콜 스택과 연동


(8) 디바이스 드라이버 계층
  • 시리얼, tty
  • 사운드
  • USB
  • Frame Buffer
  • IDE
  • SCSI
  • PCI


* 원하는 디바이스 드라이버 소스 검색 방법
  • 디바이스 모델명을 찾는다.
    • PCI : lspci
    • USb : lsusb
  • drivers 디렉토리 검색
    • ex) # grep cmd680 * -r
  • Documentation/Configure.help 탐색
    • CONFIG_XXX 변수가 무엇인지 확인
    • 해당 옵션을 사용하는 Makefile 검색

리눅스 디바이스 드라이버 개요

(1) 리눅스 특징

 

  • 모놀리틱 커널 구조(monolithic) - 다양한 컴포넌트로 구성된 거대하고 복잡한 프로그램
  • 모듈 지원 - 동적 로딩 및 제거 가능(디바이스 드라이버)
  • 커널 스레드 제공
  • 다중 프로세서 지원  - SMP(Symmetric Multiprocessing) 지원

 

 

(2) 리눅스의 장점

 

  • 목적에 맞게 컴포넌트 커스터마이징 가능
  • 저가의 하드웨어 플랫폼에서 수행
  • 다른 운영체제와 호환성이 뛰어남 - POSIX 준수

 

 

(3) 리눅스의 단점

 

  • 책임자가 없음 - 개발 및 사후 관리가 어려움

 

 

(4) 임베디드 리눅스를 선택하는 이유

 

  • 코드 품질과 신뢰성
  • 모듈성과 구조, 수정 편의성, 확장성
  • 코드 가용성
  • 하드웨어 지원
  • 통신 프로토콜과 소프트웨어 표준
  • 사용할 수 있는 툴
  • 커뮤니티 지원
  • 가격

 

 

(5) 임베디드 리눅스 시스템 구성

 

  1. 부트 소프트웨어를 포팅하고 설정
  2. 시스템 컴포넌트를 결정
  3. 커널을 설정하고 빌드
  4. 루트 파일시스템을 빌드

 

 

(6) 임베디드 리눅스 시스템 구축 시 고려사항

 

  • 부트로더의 선택은 어떤 것으로 할 것인가?
  • 최신 커널을 사용할 것인가? 충분히 검증된 커널 사용
  • 루트 파일 시스템에 포함할 것은 무엇인가?
    • 파일 시스템의 크기 고려
    • 전체 시스템 가동에 필요한 최소한의 파일만 포함

 

RTOS 소개

(1) Real Time System

  • 불시에 발생하는 이벤트에 대하여 정해진 시간 내에 정확한 결과를 제공
  • (응답시간이 예측가능하고 일정해야 한다.)
  • 시간에 적시성(timeliness)을 가지며 예측 가능한(predictable) 시스템
  • Deadline 이내에 결과값 산출
  • Deadline 넘으면 심각한 결과 발생

 

(2)

 

(3)