RaspberryPi 커널컴파일및커널모듈 1 제 13 강 커널컴파일및커널모듈 커널컴파일가상주소 (mmap() 함수 ) 에의한디바이스제어커널모듈및커널모듈테스트커널모듈에의한입출력디바이스제어 (LED, BTN) 커널모듈을커널에포함하기

Similar documents
untitled

PowerPoint 프레젠테이션

Microsoft PowerPoint - lab14.pptx

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

ECE30076 Embedded System Programming - LED Device Driver

교육지원 IT시스템 선진화

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Chapter #01 Subject

PowerPoint 프레젠테이션

KEY 디바이스 드라이버

슬라이드 1

PowerPoint 프레젠테이션

슬라이드 1

임베디드시스템설계강의자료 6 system call 2/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

Adding a New Dev file

망고100 보드로 놀아보자 -13

Microsoft PowerPoint - lab15.pptx

<4D F736F F F696E74202D FB8DEB8F0B8AE20B8C5C7CE205BC8A3C8AF20B8F0B5E55D>

2009년 상반기 사업계획

Microsoft PowerPoint - IOControl [호환 모드]

Microsoft PowerPoint - 10-EmbedSW-11-모듈

Microsoft Word doc

교육지원 IT시스템 선진화

RaspberryPi U-Boot & GPIO 제어 1 제 12 강 U-Boot + GPIO 제어 부트로더 U-Boot 부트로더 raw GPIO 제어 (LED, BTN) LED, BTN 제어

<4D F736F F F696E74202D205BBAB0C3B75D20B8AEB4AABDBA20B5F0B9D9C0CCBDBA20B5E5B6F3C0CCB9F620B8F0B5A82E >

PowerPoint 프레젠테이션

지난시간에... 우리는 kernel compile을위하여 cross compile 환경을구축했음. UBUNTU 12.04에서 arm-2009q3를사용하여 간단한 c source를빌드함. 한번은 intel CPU를위한 gcc로, 한번은 ARM CPU를위한 gcc로. AR

Chap 7

Microsoft Word doc

임베디드시스템설계강의자료 6 system call 1/2 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

제1장 Unix란 무엇인가?

제1장 Unix란 무엇인가?

/chroot/lib/ /chroot/etc/

PowerPoint 프레젠테이션

제12장 파일 입출력

PowerPoint 프레젠테이션

고급 프로그래밍 설계

PowerPoint 프레젠테이션

디바이스드라이버 (Device Driver) Driver is literally a subject which drive a object. 응용프로그램에서하드웨어장치를이용해서데이터를직접읽고쓰거나제어해야하는경우에디바이스드라이버를이용 하드웨어를제어하는프로그램과애플리케이션에서

PowerPoint 프레젠테이션

6주차.key

로봇SW교육원 강의자료

ABC 11장

PowerPoint 프레젠테이션

Microsoft PowerPoint - ch09_파이프 [호환 모드]

2009년 상반기 사업계획

Microsoft PowerPoint - 03-Development-Environment-2.ppt

(Microsoft PowerPoint - Device Driver [\310\243\310\257 \270\360\265\345])

chap7.key

vi 사용법

(Microsoft PowerPoint - Device Driver [\310\243\310\257 \270\360\265\345])

슬라이드 1

Microsoft PowerPoint - e9.pptx

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

11장 포인터

Microsoft PowerPoint - chap13-입출력라이브러리.pptx


Embeddedsystem(8).PDF

Mango220 Android How to compile and Transfer image to Target

Microsoft PowerPoint - chap12 [호환 모드]

Microsoft Word - MPC850 SPI Driver.doc

리눅스 취약점대응방안권고 / KISA 취약점점검팀 영향받는플랫폼 OS, FAQ 추가 개요 미국보안회사 에의해 시스템의 라이브러리 의특정함수에서임의코드를실행할수있는취약점이공개 해당취약점은 CVE 지정, 도메인네임을

BMP 파일 처리

슬라이드 제목 없음

Raspbian 설치 라즈비안 OS (Raspbian OS) 라즈베리파이 3 Model B USB 마우스 USB 키보드 마이크로 SD 카드 마이크로 SD 카드리더기 HDM I 케이블모니터

10.

좀비프로세스 2

°ø°³¼ÒÇÁÆ®-8È£

untitled

Microsoft PowerPoint - 09-Pipe

K&R2 Reference Manual 번역본

< E20C6DFBFFEBEEE20C0DBBCBAC0BB20C0A7C7D12043BEF0BEEE20492E707074>

교육지원 IT시스템 선진화

Microsoft PowerPoint - chap10-함수의활용.pptx

이번장에서학습할내용 동적메모리란? malloc() 와 calloc() 연결리스트 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2

2009년 상반기 사업계획

API 매뉴얼

Microsoft PowerPoint APUE(Intro).ppt

휠세미나3 ver0.4

임베디드시스템설계강의자료 4 (2014 년도 1 학기 ) 김영진 아주대학교전자공학과

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

[ 컴퓨터시스템 ] 3 주차 1 차시. 디렉토리사이의이동 3 주차 1 차시디렉토리사이의이동 학습목표 1. pwd 명령을사용하여현재디렉토리를확인할수있다. 2. cd 명령을사용하여다른디렉토리로이동할수있다. 3. ls 명령을사용하여디렉토리내의파일목록을옵션에따라다양하게확인할수

DE1-SoC Board

C++-¿Ïº®Çؼ³10Àå

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap12-고급기능.pptx

Abstract View of System Components

PowerPoint 프레젠테이션

Microsoft Word - KPMC-400,401 SW 사용 설명서

Microsoft PowerPoint - [2009] 02.pptx

한백전자교육사업부 AndroX Studio 로배우는임베디드프로그래밍 - 한백전자 - 본문서의저작권은 한백전자에있으며, 허락없이무단복제및전제를불허합니다.

Microsoft PowerPoint - Lecture_Note_7.ppt [Compatibility Mode]

RaspberryPi 시리얼통신 1 제 08 강 시리얼통신제어 시리얼통신시리얼모니터링루프백시리얼통신 Win. PC와의시리얼통신가상머신과의시리얼통신아두이노보드와의시리얼통신 KUT51보드와의시리얼통신

1217 WebTrafMon II

The Pocket Guide to TCP/IP Sockets: C Version

본 강의에 들어가기 전

Sena Technologies, Inc. HelloDevice Super 1.1.0

Transcription:

RaspberryPi 커널컴파일및커널모듈 1 제 13 강 커널컴파일및커널모듈 커널컴파일가상주소 (mmap() 함수 ) 에의한디바이스제어커널모듈및커널모듈테스트커널모듈에의한입출력디바이스제어 (LED, BTN) 커널모듈을커널에포함하기

RaspberryPi 커널컴파일및커널모듈 2 커널컴파일 * 커널소스컴파일 : 가상머신에서 10여분소요 : 라즈베리파이보드에서 90여분소요 따라서, 가상머신에서커널컴파일진행 * 이후진행은, 가상머신에서슈퍼유저로전환하여진행 ifc415@ubuntu $ sudo su root@ubuntu #

커널컴파일 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 3 * 커널소스다운로드 (./kernelsrc ) : 커널소스다운로드사이트 https://github.com/raspberrypi/linux/archive/rpi-4.9.y.tar.gz : Windows 환경에다운로드하여가상머신으로이동 :./kernelsrc 학습자료 - rpi-4.9.y.tar.gz (4.9.79 버전, 2018.2 현재 ) - rpi-4.13.34.tar.gz

커널컴파일 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 4 * 커널소스다운로드 ( 기타의방법 ) : git 툴을사용하여다운로드 # apt-get install git // git 패키지설치 # git clone --depth=1 https://github.com/raspberrypi/linux.git : 현재작업디렉터리에./linux/ 로커널소스다운로드 ( 최신버전 ) : wget 툴을사용하여다운로드 # apt-get install wget // wget 패키지설치 # wget https://github.com/raspberrypi/linux/archive/rpi-4.9.y.tar.gz : 현작업디렉터리에 rpi-4.9.y.tar.gz 파일다운로드

커널컴파일 ( 계속 ) * 커널소스설치 RaspberryPi 커널컴파일및커널모듈 5 : tar 파일푼후, 커널소스디렉터리 (/usr/src/) 로이동 : 커널소스디렉터리를소프트링크 # tar xvfz rpi-4.9.y.tar.gz // tar파일풀기 // 현작업디렉터리에./linux-rpi-4.9.y/ 디렉터리생성 # mv linux-rpi-4.9.y /usr/src // /usr/src 로이동 # cd /usr/src # ls linux-rpi-4.9.y sense-hat # ln -s linux-rpi-4.9.y linux // 소프트링크 # ls -l linux ->./linux-rpi-4.9.y/ ==> 커널소스의절대경로 /usr/src/linux

커널컴파일 ( 계속 ) * 커널소스버전확인 RaspberryPi 커널컴파일및커널모듈 6 : 커널소스홈디렉터리의 Makefile 앞부분참조 # cd /usr/src/linux # head Makefile // 선두 10라인보기 VERSION = 4 PATCHLEVEL = 9 SUBLEVEL = 79 EXTRAVERSION = NAME = Roaring Lionus... : 4.9.79 버전으로확인됨!

커널컴파일 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 7 * 커널환경설정 : 커널환경설정파일 (./arch/arm/configs ) # ls -l./arch/arm/configs/bcm* bcm2709_defconfig... 라즈베리파이 2, 3 보드 bcm2835_defconfig... 라즈베리파이 zero 보드 bcmrpi_defconfig... 라즈베리파이 1 보드 # make bcm2709_defconfig //.config 히든파일로설정정보가저장됨 // 커널컴파일할때이히든파일을참조함 # ls -a.con*.config.config.old

커널컴파일 ( 계속 ) * 디폴트커널환경설정정보확인 RaspberryPi 커널컴파일및커널모듈 8 :.config 내용이반영된메뉴방식환경에서 # apt-get install libncurses5-dev // 다음명령으로내용을살펴보려면이패키지를설치해야함 # make menuconfig // 내용확인및필요에따라수정가능, 저장시.config 파일로저장

커널컴파일 ( 계속 ) * 커널컴파일 : 사전작업 RaspberryPi 커널컴파일및커널모듈 9 # KERNEL=kernel7 // 커널이름설정 // 라즈베리파이1 kernel, 라즈베리파이2,3 kernel7 # apt-get install bc // bc 패키지설치 : 컴파일 -j4 옵션... CPU 의코어수지정 // 라즈베리파이보드, 가상머신은 quad core임 # make -j4 zimage modules dtbs //./arch/arm/boot/zimage 커널이미지파일생성 //./arch/arm/boot/dts/ 관련 //./arch/arm/boot/overlays/ 관련

커널컴파일 ( 계속 ) * 커널컴파일 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 10 : 동일버젼의커널모듈설치 ( /lib/modules/ 디렉터리하부에 ) # make modules_install // /lib/modules/4.9.79-v7/ 를생성하여커널모듈을복사 // build, source 소프트링크파일포함, 커널모듈컴파일시

커널컴파일 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 11 * 새커널이미지및커널모듈라이브러리복사 : 커널이미지파일과커널모듈라이브러리를타깃보드로전송 : NFS 서비스사용 # cd./arch/arm/boot # cp zimage /nfs // 커널이미지파일복사 # cp -rf /lib/modules/4.9.79-v7 /nfs // 커널모듈라이브러리복사 : 참고 ) 관련파일들복사 ( 복사위치는타깃보드기준임 ) // 새커널로부팅시문제가있을경우에한해 # cp./arch/arm/boot/dts/*.dtb /boot/ # cp./arch/arm/boot/dts/overlays/*.dtbo /boot/overlays/ # cp./arch/arm/boot/dts/overlays/readme /boot/overlays/

커널컴파일 ( 계속 ) * 라즈베리파이보드에서 RaspberryPi 커널컴파일및커널모듈 12 : NFS 를위한마운트후, 관련파일들복사 $ cd /boot $ sudo mv kernel7.img kernel7_org.img // 기존커널퇴피 $ sudo mount -t nfs 192.168.0.20:/nfs /share // NFS 마운트 사 $ sudo cp /share/zimage kernel7.img // 새커널이미지복 $ sudo cp -rf /share/4.9.79-v7 /lib/modules // 라이브러리복사 : 재부팅후커널버전확인 $ sudo reboot // 재부팅 $ uname -r // 커널버전확인 4.9.79-v7

RaspberryPi 커널컴파일및커널모듈 13 가상주소에의한디바이스제어 * 입출력디바이스 (GPIO) 제어방법 1) 물리주소에의한제어 ( 부트로더실행방식 ) : 앞장에서이미살펴봄 2) 가상주소에의한제어 ( mmap() 함수활용 ) : OS가실행중인상태에서, 메모리디바이스파일통해 3) 커널모듈 ( 디바이스드라이버 ) 에의한제어 : 가상주소활용한디바이스드라이버통해 : 커널에동적 ( 비포함 ), 혹은정적 ( 포함 ) 링크가능

RaspberryPi 커널컴파일및커널모듈 14 가상주소에의한디바이스제어 ( 계속 ) : 커널이부팅된후 mmap() 통한가상주소로접근 : 메모리디바이스 "/dev/mem" 파일접근 * mmap() 함수에의한제어흐름 단계1) open() 함수를사용하여 /dev/mem 파일개방단계2) mmap() 함수를사용하여제어할디바이스의포인터획득단계3) 포인터에서값을읽거나기록 ( 입출력 ) 단계4) munmap() 함수를사용하여메모리공간을해제단계5) close() 함수를사용하여파일닫기 * LED 제어예 fd = open("/dev/mem", O_RDWR); addr=mmap(null, 1, PROT_WRITE, MAP_SHARED, fd, ADDRESSOFLED); *addr = 0xFF; munmap(addr, 1); close(fd);

RaspberryPi 커널컴파일및커널모듈 15 가상주소에의한디바이스제어 ( 계속 ) * mmap() 함수 ( 가상주소확보 ) void * mmap(void *start, size_t length, int prot, int flags, start length prot flags fd offset int fd, off_t offset);.. 특정메모리주소를요청하기위해사용, 통상 NULL로설정.. 메모리세그먼트의길이.. 메모리세그먼트의접근허용권한설정 PROT_READ PROT_WRITE PROT_EXEC PROT_NONE 각각, 읽기허용, 쓰기허용, 실행허용, 접근불허.. 페이지에대한변경이다른곳에반영되는방법설정 MAP_PRIVATE MAP_SHARED MAP_FIXED 다른프로세스와대응영역을비공유, 공유, 지정된주소로고정.. 메모리디바이스파일기술자.. 디바이스의물리주소, GPIO의베이스주소 * munmap() 함수 : mmap() 함수로매핑된메모리를반환하는기능 int munmap(void *start, size_t length);

RaspberryPi 커널컴파일및커널모듈 16 가상주소에의한디바이스제어 ( 계속 ) [ 실습 1] GPIO LED 제어 (./mmapgpio ) : LED ON/OFF를반복하는프로그램 : BCM_GPIO #18에 LED 회로연결 $ nano ledgpio_01.c //======================================= // ledgpio_01.c // BCM_GPIO #18, LED // using mmap() //======================================= #include <stdio.h> #include <unistd.h> // sleep(), close() #include <fcntl.h> #include <sys/mman.h> #define GPIO_BASE 0x3F200000 // for BCM2836, BCM2837 // address offset of registers for BCM_GPIO #18 #define GPFSEL1 0x04 #define GPSET0 0x1C

RaspberryPi 커널컴파일및커널모듈 17 #define GPCLR0 0x28 int main(void) { int fd; char * gpio_mmap; volatile unsigned int * gpio; int i; printf("[mmapgpio testing...led]\n"); if((fd = open("/dev/mem", O_RDWR O_SYNC)) < 0) { printf("/dev/mem open error!!\n" ); return 1; gpio_mmap = (char *)mmap(null, 4096, PROT_READ PROT_WRITE, MAP_SHARED, fd, GPIO_BASE); if(gpio_mmap == MAP_FAILED) { printf("mmap() error!!\n"); return 1; gpio = (volatile unsigned int *)gpio_mmap; // 19 18 11 10 // GPFSEL1 = 0bxx xxx 001 xxx xxx xxx xxx xxx xxx xxx xxx; gpio[gpfsel1 / 4] &= ~(6 << 24); // #18, output, ~(001)=110(6)

RaspberryPi 커널컴파일및커널모듈 18 while(1) { // 29 20 19 10 9 0 // GPSET0 = 0b00 0000000000 0100000000 0000000000; gpio[gpset0 / 4] = (1 << 18); // LED ON printf("led ON...\n"); sleep(1); // 29 20 19 10 9 0 // GPCLR0 = 0b00 0000000000 0100000000 0000000000; gpio[gpclr0 / 4] = (1 << 18); // LED OFF printf("led OFF...\n"); sleep(1); munmap(gpio_mmap, 4096); close(fd); return 0; $ gcc o ledgpio_01 ledgpio_01.c 혹은, $ make ledgpio_01 $ sudo./ledgpio_01 ( /dev/mem 파일열려면슈퍼유저로실행해야함 )

RaspberryPi 커널컴파일및커널모듈 19 가상주소에의한디바이스제어 ( 계속 ) [ 실습 2] GPIO LED 및 BTN 제어 : BTN 눌린동안 LED ON하는프로그램 : BCM_GPIO #17에 BTN 연결 : BCM_GPIO #18에 LED 연결 $ nano ledgpio_02.c //======================================= // ledgpio_02.c // BCM_GPIO #18, LED // BCM_GPIO #17, BTN // using mmap() //======================================= #include <stdio.h> #include <unistd.h> // sleep(), close() #include <fcntl.h> #include <sys/mman.h> #define GPIO_BASE 0x3F200000 // for BCM2836, BCM2837

// address offset of registers for GPIO #define GPFSEL1 0x04 #define GPSET0 0x1C #define GPCLR0 0x28 #define GPLEV0 0x34 int main(void) { int fd; char * gpio_mmap; volatile unsigned int * gpio; int i, ret; RaspberryPi 커널컴파일및커널모듈 20 printf("[mmapgpio testing...led/btn]\n"); if((fd = open("/dev/mem", O_RDWR O_SYNC)) < 0) { printf("/dev/mem open error!!\n" ); return 1; gpio_mmap = (char *)mmap(null, 4096, PROT_READ PROT_WRITE, MAP_SHARED, fd, GPIO_BASE); if(gpio_mmap == MAP_FAILED) { printf("mmap() error!!\n"); return 1; gpio = (volatile unsigned int *)gpio_mmap;

RaspberryPi 커널컴파일및커널모듈 21 gpio[gpfsel1 / 4] &= ~(7 << 21); gpio[gpfsel1 / 4] &= ~(6 << 24); // #17, input // #18, output while(1) { ret = (gpio[gplev0 /4] & (1 << 17)); if(ret) { else { munmap(gpio_mmap, 4096); close(fd); // press? printf("pressed, then LED ON...\n"); gpio[gpset0 / 4] = (1 << 18); // LED ON printf("released, then LED OFF...\n"); gpio[gpclr0 / 4] = (1 << 18); // LED OFF return 0; $ gcc o ledgpio_02 ledgpio_02.c 혹은, $ make ledgpio_02 $ sudo./ledgpio_02

커널모듈 * Linux 커널구조 RaspberryPi 커널컴파일및커널모듈 22

커널모듈 ( 계속 ) * Character 디바이스 RaspberryPi 커널컴파일및커널모듈 23 : 자료의순차성을지닌장치로서버퍼캐쉬비사용즉, 버퍼를통하지않고순차적으로데이터를읽고쓸수있는장치를의미 : Terminal, Console, Keyboard, Sound card, Scanner, Printer, Serial/Parallel, Mouse, Joystick 등 # ls -al /dev

커널모듈 ( 계속 ) * Block 디바이스 RaspberryPi 커널컴파일및커널모듈 24 : 버퍼캐쉬를통해랜덤접근이가능한장치 : 데이터를블록단위 (512B, 혹은 1024B) 로입출력 : 파일시스템을구축가능 : Hard Disk, Floppy Disk, RAMDisk, CD-ROM * Network 디바이스 : 네트워크통신을통해네트워크패킷을송수신할수있는장치 : Ethernet, PPP, Slip, ATM, ISDN NIC 등

커널모듈 ( 계속 ) * 커널모듈이란 RaspberryPi 커널컴파일및커널모듈 25 : 디바이스를구동하기위한구동프로그램 ( 디바이스드라이버 ) : 디바이스와가상파일시스템간데이터전송인터페이스제공 : 커널에정적혹은동적으로링크되어사용 ( 모듈화 ) * 구성 : 함수와데이터의집합체 : 디바이스의입출력특성에따른특정함수구현필요

커널모듈 ( 계속 ) * 기본구성 ( xxx 디바이스 ) #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h>... RaspberryPi 커널컴파일및커널모듈 26 //1. Header Files int xxx_open( ) { int xxx_release( ) { ssize_t xxx_write( ) { ssize_t xxx_read( ) { //2. Functions static struct file_operations xxx_fops = { //3. File Operations.open = xxx_open,.release = xxx_release, // 멤버및초기화병행.write = xxx_write,.read = xxx_read, ;.llsek = NULL static int xxx_init() {... static void xxx_exit() {... module_init(xxx_init); module_exit(xxx_exit); //4. 모듈링크시초기화수행 //5. 모듈제거시수행 // 매크로, insmod시수행 // 매크로, rmmod시수행

커널모듈 ( 계속 ) * file_operations 구조체 RaspberryPi 커널컴파일및커널모듈 27 : 함수포인터들의구조체 : 커널소스의./include/linux/fs.h 참조 : 라즈베리파이에서는 6개필드제공 static struct file_operations xxx_fops = {.owner = THIS_MODULE,.open = xxx_open,.release = xxx_release,.write = xxx_write,.read = xxx_read,.llsek = NULL // 비정의시 ;

모듈링크개념도 * RaspberryPi 커널컴파일및커널모듈 28

커널모듈관련명령 * insmod RaspberryPi 커널컴파일및커널모듈 29 : 모듈의 module_init() 호출 : 커널모듈을적재하기위한메모리할당 : 드라이버이름, 메이저번호, file_operations 구조체등록예 ) $ sudo insmod hello.ko // 모듈명을풀네임으로

커널모듈관련명령 ( 계속 ) * rmmod RaspberryPi 커널컴파일및커널모듈 30 : 모듈의 module_exit() 호출, 디바이스드라이버를커널에서제거 예 ) $ sudo rmmod hello // 모듈명만 혹은 $ sudo rmmod hello.ko // 혹은, 풀네임으로 * lsmod : 등록된디바이스드라이버목록출력예 ) $ sudo lsmod 혹은 $ sudo lsmod grep hello* * modinfo : 커널모듈의버전확인명령 $ sudo modinfo hello.ko

커널모듈관련명령 ( 계속 ) * mknod : 새로운디바이스파일생성명령 : 디바이스파일의위치 /dev/ RaspberryPi 커널컴파일및커널모듈 31 : mknod 장치파일명장치유형 major minor < 장치파일 > : /dev 디렉토리에장치파일로생성 < 장치유형 > : c( 문자디바이스 ), b( 블록디바이스 ) <major> <minor> : 유형별장치식별번호, 0 이면자동할당 : 다수의동일장치간의구별번호 예 ) $ sudo mknod /dev/hello c 230 0 * 기타관련명령 $ sudo more /proc/devices // 주 (major) 번호확인 $ dmesg // 커널에서출력한메시지확인, printk()

커널모듈 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 32 [ 실습 1] 커널모듈테스트 (./hellomodule/hello/ ) : hello 모듈 : 최소한의모듈구성요소를갖춘모듈 : 모듈컴파일및모듈등록및제거를확인 * Makefile : 타깃보드에서커널모듈컴파일시사용하는 Makefile $ nano Makefile #======================================= # Makefile for device module #======================================= CC := /usr/bin/gcc KDIR := /lib/modules/4.9.79-v7/build obj-m := hello.o

RaspberryPi 커널컴파일및커널모듈 33 build: clean: make -C $(KDIR) SUBDIRS=`pwd` modules rm -rf *.o *.ko *.mod.c.*.cmd *.order *.symvers.tmp* 참고 ) 밑줄부분은자신의커널소스버전과일치시킴 (/lib/modules/4.9.79-v7/build 는커널소스가설치된 /usr/src/linux/ 임 ) * Hello 모듈소스 : 최소한의요소로구성 $ nano hello.c //======================================= // hello.c // Hello MODULE test //======================================= #include <linux/module.h> #include <linux/kernel.h>

RaspberryPi 커널컴파일및커널모듈 34 #include <linux/init.h> MODULE_LICENSE("GPL"); int hello_init(void) { printk("hello MODULE is loaded.\n"); return 0; void hello_exit(void) { printk("hello MODULE is unloaded.\n"); module_init(hello_init); module_exit(hello_exit); * 모듈컴파일 ( 슈퍼유저권한으로실행 ) $ sudo make $ ls Makefile hello.c hello.mod.c hello.o modules.order Module.symvers hello.ko hello.mod.o // 생성된 hello.ko 파일이 hello 디바이스드라이버모듈임

* 커널모듈정보확인 RaspberryPi 커널컴파일및커널모듈 35 $ modinfo hello.ko // 커널모듈정보확인 filename: license: srcversion: depends: vermagic: /home/pi/ifc415/13_kernel/moduletest/hello/hello.ko GPL 502289B12C7BD57EC69249A 4.9.79-v7 SMP mod_unload modversions ARMv7 p2v8 // 4.9.79-v7 버전의커널에서동작됨 ( 커널버전과일치시킬것 ) // 블일치시 Invalid module format Error 발생 * 커널모듈동적링크및해제 $ sudo insmod hello.ko // 모듈삽입명령 $ dmesg // 커널출력메시지확인 $ lsmod grep hello // 등록모듈확인 hello 1084 0 $ sudo rmmod hello // 모듈제거, 모듈명만, 혹은전체이름가능 $ dmesg // 커널출력메시지확인 $ lsmod grep hello // 등록모듈확인

RaspberryPi 커널컴파일및커널모듈 36 커널모듈 ( 계속 ) * 커널모듈에서의디바이스접근 : 디바이스의물리주소로커널의가상메모리주소확보 : linux/io.h, 혹은 asm/io.h 라이브러리 : ioremap() 함수 // 물리주소 (offset) 에대한가상메모리주소획득 void *ioremap(unsigned long offset, unsigned long size); void *ioremap_nocache(unsign long offset, unsigned long size); : iounmap() 함수 // 가상메모리주소를위한공간해제 void *iounmap(void *addr);

커널모듈 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 37 [ 실습 2] ioremap() 에 LED 제어 (./helloled/ ) : 앞의 hello 모듈소스기반 + 링크시 LED 제어 : GPIO #18에연결된 LED를 5회점멸하는모듈구현 $ nano Makefile #======================================= # Makefile for device module #======================================= KERVER := $(shell uname -r) PWD := $(shell pwd) CC KDIR obj-m build: := /usr/bin/gcc := /lib/modules/$(kerver)/build := helloled.o make -C $(KDIR) SUBDIRS=$(PWD) modules clean:

RaspberryPi 커널컴파일및커널모듈 38 rm -rf *.o *.ko *.mod.c.*.cmd *.order *.symvers.tmp* $ nano helloled.c //======================================= // helloled.c // hello + LED module //======================================= #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/io.h> // ioremap(), iounmap() #define GPIO_BASE 0x3F200000 // for BCM2836, BCM2837 #define BLOCK_SIZE 4096 // address offset of registers for BCM_GPIO #18 #define GPIO_LED #define GPFSEL1 18 (0x04/4) // BCD_GPIO #18 // int * #define GPSET0 (0x1C/4) #define GPCLR0 (0x28/4) volatile unsigned int * gpio_addr; // LED blinking

static void blinking(void) { int i; RaspberryPi 커널컴파일및커널모듈 39 for(i=0; i<5 ; i++){ // 1C h : 28 dec = 4 * 7 *(gpio_addr+gpset0) = 1 <<(GPIO_LED); mdelay(1000); // 28 h : 40 dec = 4 * 10 *(gpio_addr+gpclr0) = 1 <<(GPIO_LED); mdelay(1000); static int hello_init(void) { printk("insmod : Hello, GPIO LED Module Test...\n"); gpio_addr = ioremap(gpio_base, BLOCK_SIZE); // GPFSEL1 = gpio_addr + 1 *(gpio_addr+gpfsel1) &= ~(6 << (((GPIO_LED)%10)*3)); blinking(); // LED ON/OFF return 0; static void hello_exit(void) {

RaspberryPi 커널컴파일및커널모듈 40 iounmap(gpio_addr); printk("rmmod : Hello, GPIO LED Module Test...\n"); module_init(hello_init); module_exit(hello_exit); $ sudo make // 모듈컴파일 $ sudo insmod helloled.ko // 모듈등록시 LED 가 5 회점멸하는것을확인 $ sudo rmmod helloled.ko // 결과확인이종료된후이후에모듈제거

RaspberryPi 커널컴파일및커널모듈 41 커널모듈에의한디바이스제어 * 커널모듈에의한디바이스제어응용의흐름 : 모듈명 sk, 응용프로그램 test 인경우

RaspberryPi 커널컴파일및커널모듈 42 커널모듈에의한디바이스제어 ( 계속 ) * 커널모듈내함수 xxx_init() // insmod 명령시호출되는함수 // register_chardev(), register_blkdev() 호출하여커널과링크 // 기타모듈등록시처리할사항들 ( 인터럽트처리관련초기화등등 ) xxx_exit() // rmmod 명령시호출되는함수 // unregister_chardev(), unregister_blkdev() 호출하여링크해제 // 기타모듈등록시처리한사항들의해제 ( 인터럽트등등 ) xxx_open() // 디바이스파일 open시 ( open() 호출 ) xxx_release() // 디바이스파일 close시 ( close() 호출 ) xxx_read() // 입력디바이스로부터데이터입력 ( read() 호출 ) xxx_write() // 출력디바이스로데이터출력 ( write() 호출 )

RaspberryPi 커널컴파일및커널모듈 43 커널모듈에의한디바이스제어 ( 계속 ) * 커널모듈과응용프로그램간함수호출 커널모듈 (xxx) 응용프로그램 응용프로그램에서함수호출예 xxx_open() open() fd=open( /dev/xxx, O_WRONLY); xxx_release() close() close(fd); xxx_read() read() read(fd, buf, len); xxx_write() write() write(fd, &buf, len);

RaspberryPi 커널컴파일및커널모듈 44 커널모듈에의한디바이스제어 ( 계속 ) * 가상메모리보호정책 : 커널영역과사용자영역간교차접근불허 : PAGE_OFFSET (0xC000_0000, BCM2835 데이터시트 ) : 영역간데이터전달은커널관점의시스템함수를호출하여

RaspberryPi 커널컴파일및커널모듈 45 커널모듈에의한디바이스제어 ( 계속 ) * 사용자및커널영역간데이터전송함수 : 함수명의명명은커널중심의관점 ( asm/uaccess.h ) : xxx_write() 함수에서 get_user(void *x, const void *addr) // 사용자영역 *addr의값을커널영역인 x로 sizeof(addr) 만큼복사 copy_from_user(void *to, void *from, unsigned long size) // 사용자영역의주소 from으로부터 size만큼커널영역 to로복사 : xxx_read() 함수에서 put_user(void *x, const void *addr) // *x의값을 user 영역인 addr로 sizeof(addr) 만큼복사 copy_to_user(void *to, void *from, unsigned long size) // 커널영역의주소 from으로부터 size만큼사용자영역 to로복사

RaspberryPi 커널컴파일및커널모듈 46 커널모듈에의한디바이스제어 ( 계속 ) [ 실습 3] rawgpio 에의한 LED 제어 (./gpioled/ ) : 모듈의메이저번호는 201, 모듈이름은 gpioled : LED 회로는 BCM_GPIO #18에연결 : 커널모듈소스 $ nano gpioled.c //======================================= // gpioled.c // LED Device Driver : Direct Access //======================================= #include <asm/uaccess.h> // copy_to_user(), copy_from_user() #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> // open(), close(), read(), write() #include <linux/cdev.h> #include <linux/io.h> // ioremap(), iounmap() #define GPIO_BASE 0x3F200000 // for BCM2836, BCM2837 #define GPIO_RANGE 1024

RaspberryPi 커널컴파일및커널모듈 47 // address offset of registers for BCM_GPIO #18 #define GPFSEL0 (0x00/4) // int * #define GPSET0 (0x1C/4) #define GPCLR0 (0x28/4) //#define MOD_MAJOR 0 // automatic allocation #define MOD_MAJOR 201 #define MOD_NAME "gpioled" #define GPIO_LED 18 // BCM_GPIO #18 volatile unsigned int * gpio_addr; int gpioled_open(struct inode *minode, struct file *mfile) { printk("kernel Module Open(): %s\n", MOD_NAME); return 0; int gpioled_release(struct inode *minode, struct file *mfile) { printk("kernel Module close(): %s\n", MOD_NAME); return 0; ssize_t gpioled_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) { unsigned char c; get_user(c, gdata); // if c==1 then ON, else OFF

RaspberryPi 커널컴파일및커널모듈 48 if (c == 1) *(gpio_addr+gpset0) = 1 << (GPIO_LED); else *(gpio_addr+gpclr0) = 1 << (GPIO_LED); // ON // OFF return length; static struct file_operations gpioled_fops = {.write = gpioled_write,.open = gpioled_open,.release = gpioled_release, ; int gpioled_init(void) { int result; result = register_chrdev(mod_major, MOD_NAME, &gpioled_fops); if(result < 0) { printk("can't get any major\n"); return result; printk("init Module: Major number %d\n", MOD_MAJOR); printk("init Module: Major number %d\n", result); gpio_addr = ioremap(gpio_base, GPIO_RANGE);

RaspberryPi 커널컴파일및커널모듈 49 // GPFSELn, #18, out *(gpio_addr + (GPIO_LED/10)) &= ~(6 << (((GPIO_LED)%10)*3)); return 0; void gpioled_exit(void) { unregister_chrdev(mod_major, MOD_NAME); printk("%s DRIVER CLEANUP\n", MOD_NAME); module_init(gpioled_init); module_exit(gpioled_exit); : LED 응용프로그램소스 - 명령행에서 on 혹은 off 문자열을인자로전달받아 LED 제어 $ nano gpioled_test.c //======================================= // gpioled_test.c // //=======================================

RaspberryPi 커널컴파일및커널모듈 50 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char **argv) { int fd; char buf; if(argc <= 1) { printf("usage :./gpioled_test on or off\n"); return -1; fd = open("/dev/gpioled", O_WRONLY); if(fd == -1) { printf("device Open ERROR!\n"); exit(-1); if(argv[1][0] == 'o' && argv[1][1] == 'n') buf = 1; else if(argv[1][0]=='o' && argv[1][1]=='f' && argv[1][2]=='f') buf = 0; write(fd, &buf, 1); // LED control

RaspberryPi 커널컴파일및커널모듈 51 close(fd); return 0; : Makefile 수정 - 커널모듈과응용프로그램을함께컴파일할수있게작성 $ nano Makefile #======================================= # Makefile for device module #======================================= KERVER := $(shell uname -r) PWD := $(shell pwd) CC KDIR obj-m := /usr/bin/gcc := /lib/modules/$(kerver)/build := gpioled.o TEST_TARGET = gpioled_test TEST_OBJS = gpioled_test.o TEST_SRCS = gpioled_test.c

RaspberryPi 커널컴파일및커널모듈 52 build: $(TEST_TARGET) make -C $(KDIR) SUBDIRS=$(PWD) modules $(TEST_TARGET) : $(TEST_OBJS) $(CC) -o $@ $(TEST_OBJS) clean: rm -rf *.o *.ko *.mod.c.*.cmd *.order *.symvers.tmp* rm -f $(TEST_TARGET) : 컴파일 - 디바이스드라이버모듈 gpioled.ko 와응용프로그램 gpioled_test 생성 $ sudo make $ ls Makefile gpioled.ko gpioled.o gpioled_test.c Module.symvers gpioled.mod.c gpioled_test.o gpioled.c gpioled.mod.o gpioled_test modules.order 참고 ) 재컴파일시목적코드들제거위해 $ sudo make clean

RaspberryPi 커널컴파일및커널모듈 53 : 디바이스파일생성하고, 접근속성을변경 $ sudo mknod /dev/gpioled c 201 0 $ sudo chmod 777 /dev/gpioled $ ls /dev/gpio* -al crw-rw---- 1 root gpio 254, 0 Aug 6 14:10 /dev/gpiochip0 crwxrwxrwx 1 root root 201, 0 Aug 7 12:38 /dev/gpioled crw-rw---- 1 root gpio 246, 0 Aug 6 14:10 /dev/gpiomem : 드라이버모듈을등록하고, 응용프로그램을실행하여그결과를관찰 $ sudo insmod gpioled.ko $ lsmod grep gpioled gpioled 2052 0 $./gpioled_test on 혹은, $./gpioled_test off

RaspberryPi 커널컴파일및커널모듈 54 : 다음의명령을통하여모듈제거, 노드삭제등의역과정을진행 $ sudo rmmod gpioled $ lsmod grep gpioled $ sudo rm /dev/gpioled $ ls /dev/gpio*

RaspberryPi 커널컴파일및커널모듈 55 커널모듈에의한디바이스제어 ( 계속 ) * linux/gpio.h 함수를사용한제어 : GPIO 핀의사용요청및해제 int gpio_reqeust(unsigned int gpio, const char *label); void gpio_free(unsigned int gpio); : GPIO 핀의입출력방향지정 int gpio_direction_input(unsigned int gpio); int gpio_direction_output(unsigned int gpio, int value); // value는해당핀으로의초기출력값 : GPIO 핀과의데이터입출력함수 int gpio_get_value(unsigned int gpio); void gpio_set_value(unsigned int gpio, int value);

RaspberryPi 커널컴파일및커널모듈 56 커널모듈에의한디바이스제어 ( 계속 ) * linux/gpio.h 함수를사용한제어 ( 계속 ) 참고 ) 인터럽트처리를위해 GPIO 핀의 IRQ 번호를반환하는함수 : 반환된 irq 번호는 request_irq() 함수를사용하여인터럽트핸들러함수를등록할때사용 int gpio_to_irq(unsigned int gpio);

RaspberryPi 커널컴파일및커널모듈 57 커널모듈에의한디바이스제어 ( 계속 ) [ 실습 4] gpio.h 함수를활용한 LED 제어 (./gpioled2/) : gpio.h 함수를이용한커널모듈로 LED 제어 : 응용프로그램은앞의 [ 실습3] 과동일한소스사용 $ nano gpioled.c //======================================= // gpioled.c // LED Device Driver // using /linux/gpio.h //======================================= #include <asm/uaccess.h> // copy_to_user(), copy_from_user() #include <linux/ioport.h> #include <linux/module.h> #include <linux/fs.h> // open(),close(), read(), write() #include <linux/cdev.h> #include <linux/io.h> // ioremap(), iounmap() #include <linux/gpio.h> // *)!!!!

RaspberryPi 커널컴파일및커널모듈 58 //#define MOD_MAJOR 0 // automatic allocation #define MOD_MAJOR 201 #define MOD_NAME "gpioled" #define GPIO_LED 18 // BCM_GPIO #18 int gpioled_open(struct inode *minode, struct file *mfile) { printk("kernel Module Open(): %s\n", MOD_NAME); return 0; int gpioled_release(struct inode *minode, struct file *mfile) { printk("kernel Module close(): %s\n", MOD_NAME); return 0; ssize_t gpioled_write(struct file *inode, const char *gdata, size_t length, loff_t *off_what) { unsigned char c; get_user(c, gdata); gpio_set_value(gpio_led, ((c == 0)? 0 : 1)); return length; static struct file_operations gpioled_fops = {.write = gpioled_write,

;.open.release RaspberryPi 커널컴파일및커널모듈 59 = gpioled_open, = gpioled_release, int gpioled_init(void) { int result; result = register_chrdev(mod_major, MOD_NAME, &gpioled_fops); if(result < 0) { printk("can't get any major\n"); return result; printk("init Module: Major number %d\n", MOD_MAJOR); gpio_request(gpio_led, "LED"); gpio_direction_output(gpio_led, 0); return 0; void gpioled_exit(void) { unregister_chrdev(mod_major, MOD_NAME); printk("%s DRIVER CLEANUP\n", MOD_NAME); gpio_free(gpio_led);

module_init(gpioled_init); module_exit(gpioled_exit); RaspberryPi 커널컴파일및커널모듈 60 MODULE_LICENSE("GPL"); MODULE_AUTHOR("melee"); MODULE_DESCRIPTION("Raspberry Pi 3 GPIO LED Device Driver Module"); : 실행을위한응용프로그램은 [ 실습 3] 의것을사용

RaspberryPi 커널컴파일및커널모듈 61 커널모듈에의한디바이스제어 ( 계속 ) * Interrupt 처리 ( linux/interrupt.h 라이브러리 ) : 인터럽트핸들러함수원형 static irqreturn_t btn_interrupt(int irq, void *dev_id) {... : 인터럽트핸들러함수의등록및해제 : GPIO 핀에대한인터럽트번호는 gpio_to_irq() 함수호출로확보 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev); // 인터럽트핸들러함수를등록하는함수 void free_irq(unsigned int, void *); // 인터럽트핸들러함수의등록을해제하는함수

RaspberryPi 커널컴파일및커널모듈 62 커널모듈에의한디바이스제어 ( 계속 ) * 인터럽트처리시주요코드 static int btn_irq; // interrupt handler static irqreturn_t btn_interrupt(int irq, void *dev_id) {... // service return 0; int gpiobtn_init(void) { int result, irq;... gpio_request(gpio_btn, "SWITCH"); gpio_direction_input(gpio_btn); btn_irq = gpio_to_irq(gpio_btn); irq = request_irq(btn_irq, &btn_interrupt, IRQF_TRIGGER_FALLING, "SWITCH", NULL);... void gpiobtn_exit(void) {... free_irq(btn_irq, NULL);

RaspberryPi 커널컴파일및커널모듈 63 커널모듈에의한디바이스제어 ( 계속 ) [ 실습 5] 인터럽트에의한 BTN 제어 (./gpiobtnint/ ) : BTN 디바이스의제어를위해디바이스드라이버를구현 : BTN 디바이스로부터의입력에대해인터럽트방식으로처리 : interrupt.h와 gpio.h 함수사용 : major 202, gpiobtn $ nano gpiobtn.c //======================================= // gpiobtn.c // GPIO Input Device Driver // using Interrupt method & gpio.h //======================================= #include <linux/interrupt.h> // *)!! #include <linux/cdev.h> #include <linux/module.h> #include <linux/io.h>

#include <linux/gpio.h> // *)!! #include <asm/uaccess.h> #define MOD_MAJOR 202 #define MOD_NAME "gpiobtn" RaspberryPi 커널컴파일및커널모듈 64 #define GPIO_BTN 17 // BCM_GPIO #17 static int btn_irq; static char msg[40] = {0; // interrupt handler static irqreturn_t btn_interrupt(int irq, void *dev_id) { char temp[40] = "GPIO Switch was Pushed!"; strcpy(msg, temp); return 0; static ssize_t gpiobtn_read(struct file *filp, char *buf, size_t count, loff_t *l) { int result; result = copy_to_user(buf, &msg, sizeof(msg)); memset(msg, 0, 40);

RaspberryPi 커널컴파일및커널모듈 65 return result; static int gpiobtn_open(struct inode *inode, struct file *filp) { printk("kernel Module Open(): %s\n", MOD_NAME); return 0; static int gpiobtn_release(struct inode *inode, struct file *filp) { printk("kernel Module close(): %s\n", MOD_NAME); disable_irq(gpio_btn); return 0; static struct file_operations gpiobtn_fops = {.read = gpiobtn_read,.open = gpiobtn_open,.release = gpiobtn_release, ; int gpiobtn_init(void) { int result, irq; result = register_chrdev(mod_major, "GPIO INTERRUPT", &gpiobtn_fops); if(result < 0) {

RaspberryPi 커널컴파일및커널모듈 66 printk(kern_warning"can't get major %d\n", MOD_MAJOR); gpio_request(gpio_btn, "SWITCH"); gpio_direction_input(gpio_btn); btn_irq = gpio_to_irq(gpio_btn); irq = request_irq(btn_irq, &btn_interrupt, IRQF_TRIGGER_FALLING, "SWITCH", NULL); if(irq < 0) printk(kern_err "%s: Request for IRQ %d failed\n", FUNCTION, GPIO_BTN); printk("init module, GPIO major number : %d\n", MOD_MAJOR); return 0; void gpiobtn_exit(void){ unregister_chrdev(mod_major, "GPIO INTERRUPT"); free_irq(btn_irq, NULL); gpio_free(gpio_btn); printk("%s DRIVER CLEANUP\n", MOD_NAME); return;

RaspberryPi 커널컴파일및커널모듈 67 module_init(gpiobtn_init); module_exit(gpiobtn_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("melee"); MODULE_DESCRIPTION("Raspberry Pi 3 GPIO Switch Device Driver Module"); $ nano gpiobtn_test.c //======================================= // gpiobtn_test.c // //======================================= #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> int main(void) { int fd;

RaspberryPi 커널컴파일및커널모듈 68 char buf[40]; fd = open("/dev/gpiobtn", O_RDWR); if(fd < 0) { printf( "Device Open ERROR!\n"); exit(1); printf("please push the GPIO button!\n"); read(fd, buf, 40); printf("%s\n", buf); // read close(fd); return 0;

응용과제 [ 응용 1] 커널컴파일및테스트 RaspberryPi 커널컴파일및커널모듈 69 : 다음버전의커널소스를다운도드받아적용 # wget https://github.com/raspberrypi/linux/archive/rpi-4.9.y.tar.gz : 위커널소스는 4.9.80 버전임 (2019.07.31. 현재 ) +) LED/BTN 제어소스적용 (mmap() 이용 ) +) LED/BTN 제어소스적용 ( 디바이스드라이버이용 )

응용과제 ( 계속 ) RaspberryPi 커널컴파일및커널모듈 70 [ 응용 2] BTN 제어 (./gpiobtnpoll/ ) : BTN 디바이스의제어를위해디바이스드라이버를구현 : Polling 방식 : 하지말것!!

RaspberryPi 커널컴파일및커널모듈 71 아래는자율학습할것!!

커널모듈을커널에포함하기 * 커널이미지에모듈포함 RaspberryPi 커널컴파일및커널모듈 72 : 커널소스의일부로커널모듈소스를포함 // [ 실습3] gpioled 관련소스활용 : 커널모듈을포함한커널이미지로부팅 : bool 메뉴유형, tristate 메뉴유형 : Kconfig ( 커널환경설정파일 )

RaspberryPi 커널컴파일및커널모듈 73 커널모듈을커널에포함하기 ( 계속 ) * Kconfig 메뉴항목포맷 : config DEVMEM bool "/dev/mem virtual device support" default y help Say Y here if you want to support the /dev/mem device. The /dev/mem device is used to access areas of physical memory. When in doubt, say "Y". bool "/dev/mem virtual device support // y( 커널이미지에포함 ), n( 비포함 ) tristate "/dev/mem virtual device support // y( 커널이미지에포함 ), m(module 형태로 ), n( 비포함 ) string, hex, int : 해당유형별입력박스항목 default : 디폴트설정값, help : 메뉴사용도움말

RaspberryPi 커널컴파일및커널모듈 74 커널모듈을커널에포함하기 ( 계속 ) * 드라이버모듈소스를커널소스내로복사 # cd /usr/src/linux/ // 커널소스홈디렉터리 # cp???/gpioled.c./drivers/char/ //./drivers/char/ 커널의문자디바이스관련모듈소스위치 //./drivers/block/ 커널의블록디바이스관련모듈소스위치 * Kconfig 편집하여항목추가 : 커널환경설정에서드라이버모듈항목이나타나도록등록 (make menuconfig 명령사용할때 ) # nano./drivers/char/kconfig config GPIO_LED_TEST bool GPIO LED Module Test Program ( 혹은, tristate GPIO LED Module Test Program ) // 항목의심볼명은 CONFIG_GPIO_LED_TEST임, default/help항비명시

RaspberryPi 커널컴파일및커널모듈 75 커널모듈을커널에포함하기 ( 계속 ) * Makefile 수정 : 커널컴파일시드라이버모듈이컴파일될수있도록 : 현디렉터리의 Makefile에심볼명을활용하여다음과같은라인을추가 ( Kconfig에서등록한모듈항목에대한심볼명유의 ) : 목적코드파일명지정 # nano./drivers/char/makefile... obj-$(config_brcm_char_drivers) += broadcom/ obj-$(config_gpio_led_test) += gpioled.o // Kconfig 등록심볼명과일치

RaspberryPi 커널컴파일및커널모듈 76 커널모듈을커널에포함하기 ( 계속 ) * 커널환경설정 # KERNEL=kernel7 # make bcm2709_defconfig // 기본커널환경설정정보 # make menuconfig : Device Drivers-Character devices-gpio LED Module.. 이동 : bool 메뉴유형의경우, [ ] GPIO LED M...

RaspberryPi 커널컴파일및커널모듈 77 커널모듈을커널에포함하기 ( 계속 ) : tristate 메뉴유형의경우, < > GPIO LED M... // 메뉴유형에따라적절히선택하여설정하고저장 (.config 로저장 ) # cat.config grep CONFIG_GPIO_LED* // 커널모듈에대한심볼명이포함여부및설정상태확인 CONFIG_GPIO_LED_TEST=y // bool, y CONFIG_GPIO_LED_TEST=m // tristate, m(module)

RaspberryPi 커널컴파일및커널모듈 78 bool 메뉴유형 * bool 메뉴유형이며, y 설정의경우 : 커널모듈을커널이미지로파일로포함 (built-in) : 커널컴파일및타깃보드로전달 # cd /usr/src/linux // 커널소스의홈디렉터리로이동 # make j4 zimage // 커널컴파일 # cp./arch/arm/boot/zimage /nfs/ // NFS 서비스위해 $ sudo mount -t nfs 192.168.0.20:/nfs /share $ cd /boot/ // 필요시이전커널이미지퇴피권고 $ cp /share/zimage./kernel7.img $ sudo reboot // 새로운커널이미지로재부팅

bool 메뉴유형 ( 계속 ) : 커널모듈적재확인 RaspberryPi 커널컴파일및커널모듈 79 $ dmesg grep Init* [ 0.308241] Init Module: Major number 201 [ 0.775732] Init: Port Power? op_state=1 $ cat /proc/devices grep gpio* 201 gpioled // 주번호및모듈명 246 bcm2835-gpiomem : 디바이스파일생성및응용프로그램실생 $ sudo mknod /dev/gpioled c 201 0 $ sudo chmod 777 /dev/gpioled $./gpioled_test on 혹은, $./gpioled_test off

tristate 메뉴유형 RaspberryPi 커널컴파일및커널모듈 80 * tristate 메뉴유형, m(modules) 설정의경우 : : 커널컴파일및모듈라이브러리설치 # cd /usr/src/linux # sudo make -j4 zimage modules dtbs scripts/kconfig/conf --silentoldconfig Kconfig... CC [M] drivers/char/gpioled.o... LD [M] drivers/char/gpioled.ko # sudo make modules_install // 커널모듈라이브러리설치 # cd /lib/modules/4.9.79-v7/ # ls kernel/drivers/char/ broadcom gpioled.ko // 커널모듈

tristate 메뉴유형 ( 계속 ) : NFS 서비스로타깃보드로전달 # cp./arch/arm/boot/zimage /nfs # cp -rf /lib/modules/4.9.79-v7/ /nfs RaspberryPi 커널컴파일및커널모듈 81 $ sudo mount t nfs 192.168.0.20:/nfs /share $ sudo cd /boot/ $ sudo cp /share/zimage./kernel7.img $ sudo cp rf /share/4.9.79-v7/ /lib/modules/ : 부팅시커널모듈을적재토록하려면 ( 선택사항임 ) $ sudo nano /etc/modules gpioled // 모듈이름을추가 $ sudo reboot // 새로운커널이미지로재부팅 참고 ) /etc/modules 파일에미등록시 insmod, rmmod 명령으로동적링크함

tristate 메뉴유형 ( 계속 ) : 커널모듈적재확인 RaspberryPi 커널컴파일및커널모듈 82 $ lsmod grep gpio* // 확인가능 $ dmesg grep Init* [ 0.308241] Init Module: Major number 201 [ 0.775732] Init: Port Power? op_state=1 $ cat /proc/devices grep gpio* 201 gpioled // 주번호및모듈명 246 bcm2835-gpiomem : 디바이스파일생성및응용프로그램실생 $ sudo mknod /dev/gpioled c 201 0 $ sudo chmod 777 /dev/gpioled $./gpioled_test on 혹은, $./gpioled_test off