커널은 memory protection을 하고 있기 때문에. 바로 건들지 않고, copy 해와야 한다. 
관련함수는 copy_from_user(). copy_to_user() 이다. 
 

#include <asm/uaccess.h>
 copy_to_user(buf, &k_data, count);
 copy_from_user(&k_data, buf, count);



kmalloc시 
메모리 해제될 때까지 block 되었다가 기다리게 하는 것을 GFP_KERNEL 옵션
무조건 할당하고 없으면 즉시 NULL을 반환하는 것은 GFP_ATOMIC 옵션
연속된 물리 메모리를 할당받을 때 사용하는 것은 GFP_DMA 옵션

OS와 드라이버에 대한 깊은 이해가 필요한데. 과부하와 버그에 대해서 대처 방법을 모를 수 있다. 
내가 구현하고 싶은 디바이스 드라이버가 있으면, 가장 비슷한 디바이스 드라이버를 참조해서 도움이 된다.
함수로 쓰지 않는 것이 좋다고 한다. . (하지만, 천재는 제외겠지. ㅋ)




ssize_t sk_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos) {
void * k_data;
k_data = kmalloc(count, GFP_KERNEL);
if (k_data == NULL) {

}


ret = copy_from_user(k_data, buf, count);
if(ret < 0) return -1;
....





Posted by '김용환'
,

<소스>

static int my_age;
static char *my_name;


// 리눅스 커널 2.6.20 이전
MODULE_PARM(my_age, "i");
MODULE_PARM(my_name, "string");

// 리눅스 커널 2.6.20 이후
module_param(my_age, int, 0);
module_param(my_name, charp, 0);

 int my_parm_start(void)

{
    printk(KERN_INFO " Parameter Module is Loaded!! ....\n");

    if((my_age == 0) || (my_name == NULL))
    {
        printk(KERN_ERR "Please Input Youre Parameters!!\n");
        printk(KERN_ERR "Usage : insmod my_parm_module.o my_age=15 my_name=kim\n");
    } else {
        printk(KERN_INFO "Your Parameter is ....\n");
        printk(KERN_INFO "\tname : %s\n", my_name);
        printk(KERN_INFO "\tage : %d\n", my_age);
    }

    return 0;
}

...... 




[root@linux2 my_parm]# insmod my_parm_module.ko  my_name=\"kk aa mm \" my_age=17


MY Parameter Module is Loaded!! ....
Your Parameter is ....
        name : kk aa mm 
        age : 17

Posted by '김용환'
,

mkfifo 명령어

c or linux 2011. 4. 19. 14:08

mkfifo 명령어는 named pipe를 생성한다. 


mkfifo myfifo

ls -al myfifo
prw-r--r--  1 root root     0  4월 19 09:29 myfifo




http://forum.falinux.com/zbxe/?document_srl=420145
http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/3/mkfifo

Posted by '김용환'
,


0xf100000 번지에 0x0606 이라는 값을 넣고 싶다고 할 때..
c 언어로 어떻게 해야 하는지 적은 것이다..

단순하게 표현해서 c언어가 이해할 수 있는 수준까지 ~

1단계 단순하게 처리.. 
* (0xf100000) = 0x0606 
-> 이는 C 컴파일러 에러를 나게 한다. 

2단계 주소라는 것을 알려주자
* ((*) 0xf100000) = 0x0606 

3단계, 2byte를 저장할 꺼니. 주소 크기를 추가하자
* ((unsigned short *) 0xf100000) = 0x0606 

4단계, compiler 최적화를 피하자. gcc 옵션에는 Optimization 기능때문에 문제가 될 수 있다.
* ((volatile unsigned short*) 0xf100000) = 0x0606 

5단계. 이것을 변수화 시키자.. 매번 할당하는 것이 오버로드니.. macro를 이용한다.
그리고 다른 연산자나 변수와 문제될 수 있으니 ()를 더 넣자.

#define FND1  (* ((volatile unsigned short *) 0xf1000000))
#define FND2  (* ((volatile unsigned short *) 0xf1100000))

int mina_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
printk(KERN_WARNING "[DD]ioctl..\n");
switch(cmd) {
case 1 :
FND1 = 0x0606;
break;
case 2 :
FND2 = 0x0808;
break;
}
return 0;
}




cmd 값이 1이면, 0xf1000000 번지에 0x0606이 저장되고,
cmd 값이 2이면 0xf1000000번지에 0x0808이 저장된다.

만약. 임베디드 보드라고 한다면, 이 위치가 가르키는 것이 LED라면, 바로 내용 저장이 가능하게 한다. 


 

Posted by '김용환'
,



insmod해서 나온 major number  나온 값을 가지고 device파일을 생성되고.
그걸 가지고. app에서 그 device를 가지고 처리하는 것이 핵심이다.

device 프로그래밍할 때의 큰 개념은
insmod에서 register하고,
rmmod에서 unregister되게 하고,
모듈 등록하면 ok~

 
보드가 2.4 커널 기반이라서 2.4로 해야했다.
module_init, module_exit 을 이용하고.. 실제 file_operation할 때 어떤 메소드가 호출될지를 지정한다. 


struct file_operations mina_fops = {
    read:       mina_read,
    write:      mina_write,
    open:       main_open,
    ioctl: mina_ioctl,
    release:    mina_release
};

int mina_init(void)
{
int error;

printk("<1> Mina Module id Up....\n");

/** important **/
error = register_chrdev(mina_major, "mina", &mina_fops);
if(error < 0) {
printk(KERN_WARNING "mina:register_chrdev() error!!\n");
return error;
} else if(sk_major==0) mina_major = error;
printk("<1> mina:register_chrdev() ok! => major_num:%d\n", mina_major);

printk(KERN_WARNING "Mina Module Insert Done!!\n");
return 0;
}

void mina_exit(void)
{
printk("<1> Mina Module id Down....\n");

unregister_chrdev(mina_major, "mina");

printk(KERN_WARNING "Mina Module Delete Done!!\n");
}

module_init(mina_init);
module_exit(mina_exit);

MODULE_LICENSE("Dual BSD/GPL");



register 함수가 참 중요하다.

함수의 원형은 다음과 같다. 
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

커널 모듈시 등록시  register_chrdev() 함수의 세번째 파라미터인 fops 를 파라미터로 넣는다.
독특해 보이는데, 그 이유는 함수형 포인터때문이다. 이것을 이용해서 write 시스템 콜이 호출되면, VFS에서 그것을 커널에 등록된 write로 매핑된 함수를 호출하도록 되어 있는 것이다.

linux/fs.h 파일에 정의되어 있는 구조체는 다음과 같다. 


struct file_operations {
  struct module *owner;
  loff_t (*llseek) (struct file *, loff_t, int);
  ssize_t (*read) (struct file *, char *, size_t, loff_t *);
  ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
  int (*readdir) (struct file *, void *, filldir_t);
  unsigned int (*poll) (struct file *, struct poll_table_struct *);
  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
  int (*mmap) (struct file *, struct vm_area_struct *);
  int (*open) (struct inode *, struct file *);
  int (*flush) (struct file *);
  int (*release) (struct inode *, struct file *);
  int (*fsync) (struct file *, struct dentry *, int datasync);
  int (*fasync) (int, struct file *, int);
  int (*lock) (struct file *, int, struct file_lock *);
  ssize_t (*readv)  (struct file *, const struct iovec *, unsigned long, loff_t *);
  ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
};




register_chrdev() 함수의 두번째 major number 파라미터이다. major number는 unique해야 하는데,  사실 모든 major 번호를 찾기가 어렵다.  major number를 0을 주면 알아서 major 번호를 준다.
리턴값으로 major 정보를 전달한다.  그게 0 이하면 에러를 의미한다.

이렇게 만들어진 커널모듈을 리눅스에 올려보자..
 



[root@linux2 01.sk_basic]# insmod miua_drv.ko
[root@linux2 01.sk_basic]# lsmod | grep sk
mina_drv                  2692  0
[root@linux2 01.sk_basic]# dmesg |
Enabling unmasked SIMD FPU exception support... done.
VFS: Disk quotas dquot_6.5.1
RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
Attached scsi disk sda at scsi0, channel 0, id 0, lun 0
 mina:register_chrdev() ok! => major_num:254




254 major 넘버로 사용하고, char device로 하고, minor는 아무거나 한다.

[root@linux2 mina]# mknod /dev/mina c 254 0

[root@linux2 mina]# ls -al /dev/mina
crw-r--r--  1 root root 254, 0  4월 19 11:39 /dev/mina

[root@linux2 mina]# ./mina_test_app
/dev/mina file open ok!!
app => write request(tx_data:33)!!
app => write done(ret:4)!!
app => read request!!
app => read done(rx_data:1, ret:4)!!
app => ioctl request(cmd:1)!!
app => ioctl done(ret:0)!!



dmesg로 커널단에서 어떻게 호출되었는지 확인가능하다.

[DD]open..
[DD]write..
[DD]read..
[DD]ioctl..
[DD]release..



참고로.. .  ioctl 함수에 재미있는 것이 있다. 

int mina_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)

마지막 파라미터는 unsigned long 은 포인터로 오는 경우를 의미할 수도 있다. 단순한 숫자뿐 아니라 포인터도 보낼 수 있다는 의미이다.











Posted by '김용환'
,


1. 가장먼저 boot loader를 보드에 전달한다. 

boot loader를 fusing한다. (이미지를 굽는다.)
보드사에서 제공하는 boot loader를 굽는다. 

[root@linux2 src]# ./Jflash-XHYPER255  x-boot255
JFLASH Version 2003.06.03 - HyBus - XHYPER255B
COPYRIGHT (C) 2000, 2001 Intel Corporation
JTAG Test Passed

ACT: 0110 1001001001100100 00000001001 1
EXP: **** 1001001001100100 00000001001 1

PXA255 revision ?? + 6

There are two 16-bit Flash devices in parallel

Characteristics for one device:
 Number of blocks in device = 128
 Block size = 65536 0x10000 word(16-bit)
 Device size = 8388608 0x800000 word(16-bit)

Sample block to address list:

 Block 0 = hex address: 00000000
 Block 40 = hex address: 00A00000
 Block 80 = hex address: 01400000
 Block 120 = hex address: 01E00000

Starting erase
Erasing done
Starting programming
Writing flash at hex address     2dc0, 56.43% done

Verification successful!



잘 되었다. 

보드에 맞는  커널 소스 압축풀고,  corss tool chain 설치한다.
설치 후 path등록하여 편하게 사용하도록 한다.

이걸 가지고, 나중에 커널 모듈 컴파일시 KERNEL_DIR에 넣어서 타겟 보드에서 정상적으로 동작되게 한다.


2. minicom을 실행한다.
 
minicom은 auto loading 모드과 명령어 모드가 있다.
명령어 모드를 사용하려면, 3초안으로 키보드 입력을 한다.

명령어도 모드를 사용한다.

Welcome to minicom 2.00.0

OPTIONS: History Buffer, F-key Macros, Search History Buffer, I18n
Compiled on Mar  7 2005, 10:29:09.

Press CTRL-A Z for help on special keys



 XHYPER255B-R1
 Copyright (C) 2002 Hybus Co,. ltd.
 Support: http://www.hybus.net

Autoboot in progress, press any key to stop ..
Autoboot aborted
Type "help" to get a list of commands
XHYPER255B>

 

3. 커널 컴파일을 해보자.
다른 터미넝을 띄운다. 보드에서 준 커널 설정을 한다.
 


[root@linux2 ~]# cd linux/
[root@linux2 linux]# make menuconfig
rm -f include/asm-arm/arch include/asm-arm/proc
(cd include/asm-arm; ln -sf arch- arch; ln -sf proc- proc)
rm -f include/asm
( cd include ; ln -sf asm-arm asm)
make -C scripts/lxdialog all
make[1]: Entering directory `/root/linux/scripts/lxdialog'
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o checklist.o checklist.c
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o menubox.o menubox.c
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o textbox.o textbox.c
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o yesno.o yesno.c
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o inputbox.o inputbox.c
inputbox.c: In function ‘dialog_inputbox’:
inputbox.c:107: warning: pointer targets in passing argument 1 of ‘strcpy’ differ in signedness
inputbox.c:109: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness
inputbox.c:117: warning: pointer targets in passing argument 2 of ‘waddnstr’ differ in signedness
inputbox.c:147: warning: pointer targets in passing argument 1 of ‘strlen’ differ in signedness
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o util.o util.c
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o lxdialog.o lxdialog.c
lxdialog.c: In function ‘j_inputbox’:
lxdialog.c:211: warning: pointer targets in passing argument 2 of ‘fprintf’ differ in signedness
gcc -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -DLOCALE  -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>" -c -o msgbox.o msgbox.c
gcc -o lxdialog checklist.o menubox.o textbox.o yesno.o inputbox.o util.o lxdialog.o msgbox.o -lncurses
make[1]: Leaving directory `/root/linux/scripts/lxdialog'
/bin/sh scripts/Menuconfig arch/arm/config.in
Using defaults found in arch/arm/defconfig
Preparing scripts: functions, parsing.............................................................................done.

Saving your kernel configuration...

*** End of Linux kernel configuration.
*** Check the top-level Makefile for additional configuration.
*** Next, you must run 'make dep'.

[root@linux2 linux]#



가장 중요한 것은 .config 파일이 있어야 커널 컴파일이 가능하다. 이는 menuconfig를 잘 저장할 때 나오는 것이다.
 

[root@linux2 linux]# ls -al
합계 284
dr-xr-xr-x  14 root root  4096  4월 19 10:02 .
drwxr-x---  20 root root  4096  4월 19 09:52 ..
-rw-r--r--   1 root root 22099  4월 19 10:02 .config
-rw-r--r--   1 root root    96  4월 19 10:02 .menuconfig.log

4. 보드가 2.4보드라서 make dep를 한다.
 
make dep
2.6은 make dep를 하지 않아도 된다. 알아서 해결.
2.4는 make dep를 해야 한다.


<기타>
make clean : config 빼고, object만 지운다.
make mrproper   : 설정(config)까지 지운다. 


5. 커널 이미지를 만든다.
make zImage
(커널 이미지 + piggy + relocate 코드를 압축한다. )


6. 커널을 보드로 전달한다.
tftp , bootp를 이용해야 한다.

임베디드 보드에서는 bootloader에서 bootp를 이용해서 서버에 연결하여 ip를 할당받아야 한다.
따라서, 즉, 보드에 넣는 서버는 미리 bootp 데몬이 떠있어야 한다. 
vi /etc/xinetd.d/bootp, vi /etc/xinetd.d/tftp 를 수정

잘보면, 모두 udp 이다.

[root@linux2 linux]# cat /etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer \
#       protocol.  The tftp protocol is often used to boot diskless \
#       workstations, download configuration files to network-aware printers, \
#       and to start the installation process for some operating systems.
service tftp
{
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = /usr/sbin/in.tftpd
        server_args             = -s /tftpboot
        disable                 = no
        per_source              = 11
        cps                     = 100 2
        flags                   = IPv4
}



zImage 이미지 복사
[root@linux2 linux]# ls -al arch/arm/boot/zImage
-rwxr-xr-x  1 root root 928704  4월 19 10:06 arch/arm/boot/zImage
[root@linux2 linux]# cp arch/arm/boot/zImage /tftpboot/
cp: overwrite `/tftpboot/zImage'? y
[root@linux2 linux]# ls -al /tftpboot/zImage
-rwxr-xr-x  1 root root 928704  4월 19 10:21 /tftpboot/zImage

root 파일 시스템 복사
[root@linux2 Image]# cp rootfs.img /tftpboot/
 


[root@linux2 linux]# netstat -au
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
udp        0      0 *:32768                     *:* 
udp        0      0 *:bootps                    *:* 
udp        0      0 *:tftp                      *:* 
udp        0      0 *:978                       *:* 
udp        0      0 *:sunrpc                    *:* 
udp        0      0 *:ipp                       *:* 


자.. minicom에서 실행해보자..


minicom 의 명령어모드 창에서... 서버쪽으로 요청하도록 해야함


XHYPER255B> bootp
Our Ethernet address is 1234 5678 9A00.
        Sending bootp packet...
....................
Bootp packet is not received.



IP를 전달하지 못한것이다.

vi /etc/bootptab

xhyper255:\
ht=1:\
ha=0x123456789A00:\
ip=192.168.1.50:\
sm=255.255.255.0




ha는 맞네.. host ip가 안잡혀서 문제였다.
내 컴퓨터를 192.168.1.x 대로 변경해야 한다.


[root@linux2 linux]# ifconfig eth0 192.168.1.51 netmask 255.255.255.0

[root@linux2 linux]# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0C:29:F2:5E:B0
          inet addr:192.168.1.51  Bcast:192.168.1.255  Mask:255.255.255.0


minicom에서 확인해 본다.

XHYPER255B> bootp
Our Ethernet address is 1234 5678 9A00.
        Sending bootp packet...
.
Bootp Packet received.
        Host   (server) Ethernet : 000C 29F2 5EB0
        Host   (server) IP       : 127.0.0.1
        Client (target) Ethernet : 1234 5678 9A00
        Client (target) IP       : 192.168.1.50


bootp서버가 ip변경사항을 catch하지 못했다.


service xinetd restart 했는데. bootp가 제대로 반영이 되지 않았다.
이런 황당한 일이.... 확인해보니.. bootp가 제대로 죽지 않았다.. (이래서 다들 fix시킬 수 있는 임베디드 보드를 주는구나..bootp 는 최대한 적게 사용하여 개발의 편리성을 주는 이유가 그랬다.. 예전에 삼성이나 LG 임베디드 기기에서는 rom에서 ip를 지정해주고 바로 pc에서 이미지를 구울 수 있게 해주었던 것이 기억이 낫다.)

bootp를 확인해보니.. xinetd 중단시키고, 보니. 데몬이 떠있다... kill로 죽여주고.

[root@linux2 linux]# service xinetd stop
xinetd 를 정지함:                                          [실패]
[root@linux2 linux]# netstat -au
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
udp        0      0 *:32768                     *:* 
udp        0      0 *:bootps                    *:* 
udp        0      0 *:978                       *:* 
udp        0      0 *:5353                      *:* 
udp        0      0 *:sunrpc                    *:* 
udp        0      0 *:ipp                       *:* 
[root@linux2 linux]# ps -ef | grep bootp
root      4862     1  0 10:23 ?        00:00:00 bootpd
root      5108 32262  0 10:31 pts/6    00:00:00 grep bootp
[root@linux2 linux]# kill -9 4862
[root@linux2 linux]#

 


xinetd 데몬을 시작시킨다.



[root@linux2 linux]# service xinetd start
xinetd (을)를 시작합니다:                                  [  확인  ]
[root@linux2 linux]#
[root@linux2 linux]#
[root@linux2 linux]# netstat -au
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
udp        0      0 *:32768                     *:* 
udp        0      0 *:bootps                    *:* 
udp        0      0 *:tftp                      *:* 
udp        0      0 *:978                       *:* 
udp        0      0 *:5353                      *:* 
udp        0      0 *:sunrpc                    *:* 
udp        0      0 *:ipp                       *:* 


minicom에서 bootp를 쳤다. 

XHYPER255B> bootp
Our Ethernet address is 1234 5678 9A00.
        Sending bootp packet...
.
Bootp Packet received.
        Host   (server) Ethernet : 000C 29F2 5EB0
        Host   (server) IP       : 192.168.1.51
        Client (target) Ethernet : 1234 5678 9A00
        Client (target) IP       : 192.168.1.50


ip를 잡은 것을 확인했고, kernel 을 tftp로 보드에 잘 전송한다. 

XHYPER255B> tftp zImage kernel
TFTP Start...
        Host   (server) IP       : 192.168.1.51
        Client (target) IP       : 192.168.1.50
        Loading Filename         : zImage
        Save Address             : 0xA0008000

Loading start...
        0x000E2BC0 (928704) bytes received.
        tftp done.

XHYPER255B>


그 다음 root 파일 시스템을 보드에 잘 전송한다. 파일시스템이 있어야.. 내가 먼가를 할 수 있지..
보드에서 제공해주는 걸 사용한다.
 

XHYPER255B> tftp rootfs.img root
TFTP Start...
        Host   (server) IP       : 192.168.1.51
        Client (target) IP       : 192.168.1.50
        Loading Filename         : rootfs.img
        Save Address             : 0xA0000000

Loading start...
        0x00800000 (8388608) bytes received.
        tftp done.

이미지를 굽는다.
XHYPER255B> flash root



이미지가 잘 구워지면(fusing) 보드의 reset 버튼을 눌러 restart 한다.
login 명은 root로 한다.
 

seblock(): Magic bitmask 0x1985 not found at 0x01dc0020: 0xfbfc idjffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x01dc0024: 0xfdff idFurther such events for this erase block will not be printed
Old JFFS2 bitmask found at 0x01dff410
You cannot use older JFFS2 filesystems with newer kernels
JFFS2: Erase block at 0x01dc0000 is not formatted. It will be erased
VFS: Mounted root (jffs2 filesystem).
Freeing init memory: 368K
Setting up RAMFS, please wait ...
done and exiting
INIT: version 2.78 booting
INIT: Entering runlevel: 3
Starting syslog Starting system logger:

Starting etwork Starting network

Xhyper255 login: root
[root@Xhyper255 /root]$



* 파일 전달하는 것은 serial케이블을 통한 zmodem 또는 이더넷을 통한 NFS를 사용할 수 있다.(NFS를 이용해서 shared 폴더를 구성하고 데이터를 주고 받을 수 있다..)
인터넷은 해야 하니.. NFS는 나중에 하던가 하고.. 파일들이 워낙 간단하니. serial 케이블을 사용한다.
 
1. serial 케이블 이용

ctrl  A 누르고, Z를 눌러 help 명령어가 나오게 한다.

key mode....I |bfc idjffs2| lineWrap on/off....W  local Echo on/off..E | Help screen........Z |dff idFurth|                                            | scroll Back........B |
Old J|                                                                   |
You c|      Select function or press Enter for none.                     |
JFFS2|                                                                   |
VFS: |             Written by Miquel van Smoorenburg 1991-1995           |
Freei|             Some additions by Jukka Lahtinen 1997-2000            |
Setti|             i18n by Arnaldo Carvalho de Melo 1998                 |
done +-------------------------------------------------------------------+
INIT: version 2.78 booting



커널 모듈 파일을 전송해본다...
 
Sendfile->Zmodem를 선택하면, 디렉토리 리스트가 나온다.
여기에서 space 두번을 눌러 선택해서 내가 올리고 싶은 커널 모듈을 찾는다.
선택하면 space 한번을 누르고 엔터를 친다.

커널 모듈 추가한다.


[root@Xhyper255 /root]$insmod hello_mod.o
 Hello Module id Loaded ....


[root@Xhyper255 /root]$dmesg
....
 Hello Module id Loaded ....


[root@Xhyper255 /root]$lsmod
Module                  Size  Used by
hello_mod                432   0  (unused)


모듈만 올라갔지. 실제로는 open/close/read/write/ioctl은 할 수 없다..

mknod를 해야 한다... 

mknod 편은 다음편에...  







Posted by '김용환'
,

임베디드 보드에서 크로스 체인시 가장 중요한 것은 커널 위치가 매우 중요하다. 
KERNEL_DIR = /root/linux  보드가 사용하는 커널 위치이다. 

vi Makefile

..

PLATFORM = /usr/local/arm-linux/bin/arm-linux-

CC = $(PLATFORM)gcc


KERNEL_DIR = /root/linux

CFLAGS = -DMODULE -D__KERNEL__ -I$(KERNEL_DIR)/include -Wall -O2

..



나중에 보드에서 insmod 해서 사용할 때, 문제없이 동작되도록 한다.

'c or linux' 카테고리의 다른 글

커널 모듈 중요 포인트  (0) 2011.04.19
minicom을 이용하여 이미지 굽기(fusing)  (0) 2011.04.19
리눅스 커널 시작 Hello World  (0) 2011.04.18
c header 파일  (0) 2011.04.18
표준 출력을 fwrite, write로 구현하기  (0) 2011.04.18
Posted by '김용환'
,

<리눅스 커널 2. 6 기준>

static 변수 선언하고, 함수들도 static 함수를 선언한다.  그래서, 외부 커널모둘에서 해당 모듈에 영향을 주지 못하게 할 수 있다.


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int hello_init(void) {
    printk("hello init\n");
    return 0;
}

static void hello_exit(void) {
    printk("hello exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");

1) 커널 디렉토리 밑으로 가야 컴파일 된다.

그냥 컴파일하면 에러 발생
[root@linux2 hello_mod]# gcc hello_mod.c
/usr/lib/gcc/i386-redhat-linux/4.0.0/../../../crt1.o(.text+0x18): In function `_start':: undefined reference to `main'
/tmp/cceO6qIX.o(.text+0xf): In function `hello_init':
hello_mod.c: undefined reference to `printk'
/tmp/cceO6qIX.o(.text+0x2c): In function `hello_exit':
hello_mod.c: undefined reference to `printk'
collect2: ld returned 1 exit status


makeFile 파일를 만들자.

obj-m   := hello_mod.o
KDIR    := /lib/modules/$(shell uname -r)/build
PWD     := $(shell pwd)
default:
        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
        rm -rf *.ko
        rm -rf *.mod.*
        rm -rf .*.cmd
        rm -rf *.o



<참고 사항>
MODULE_LICENSE("Dual BSD/GPL");

MODULE_LICENSE 삭제하면.. 에러가 발생한다.
[root@linux2 test]# make
make -C /lib/modules/2.6.11-1.1369_FC4/build SUBDIRS=/mnt/hgfs/shared/Module_2426_new_st/test modules
make[1]: Entering directory `/usr/src/kernels/2.6.11-1.1369_FC4-i686'
  CC [M]  /mnt/hgfs/shared/Module_2426_new_st/test/test.o
/mnt/hgfs/shared/Module_2426_new_st/test/test.c:17:2: error: invalid preprocessing directive #MODULE_LICENSE
make[2]: *** [/mnt/hgfs/shared/Module_2426_new_st/test/test.o] 오류 1
make[1]: *** [_module_/mnt/hgfs/shared/Module_2426_new_st/test] 오류 2
make[1]: Leaving directory `/usr/src/kernels/2.6.11-1.1369_FC4-i686'
make: *** [default] 오류 2

관련 내용은 아래 참조 : http://askville.amazon.com/MODULE_LICENSE-work-Linux-kernel/AnswerViewer.do?requestId=2639289


2) 컴파일하면, o 파일과 ko 파일이 발생하고, insmod써서 올린다.

[root@linux2 hello_mod]# make
make -C /lib/modules/2.6.11-1.1369_FC4/build SUBDIRS=/mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod modules
make[1]: Entering directory `/usr/src/kernels/2.6.11-1.1369_FC4-i686'
  CC [M]  /mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod/hello_mod.o
/mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod/hello_mod.c:20: warning: function declaration isn’t a prototype
/mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod/hello_mod.c:26: warning: function declaration isn’t a prototype
  Building modules, stage 2.
  MODPOST
  CC      /mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod/hello_mod.mod.o
  LD [M]  /mnt/hgfs/shared/Module_2426_new_st/v26_host/hello_mod/hello_mod.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.11-1.1369_FC4-i686'

[root@linux2 hello_mod]# insmod hello_mod.ko
반드시 ko 파일명을 써야 한다.


3) 커널 모듈이 정상적으로 리눅스 커널로 확인하는 법



[root@linux2 hello_mod]# dmesg | tail -n 1
 Hello Module id Loaded ....

[root@linux2 hello_mod]# lsmod | grep hello
hello_mod               1664  0

 

제거하기


[root@linux2 hello_mod]# rmmod hello_mod.ko

[root@linux2 hello_mod]# dmesg | tail -n 1
 Hello Module is Unloaded ....
[root@linux2 hello_mod]# lsmod | grep hello
결과 없음




ko 확장자 없이 rmod hello_mod 해도 결과는 동일하다.

 

4) 커널 심볼 정보에서 리눅스에 올린 커널 모듈  확인하는 방법


[root@linux2 proc]# cat kallsyms | grep hello
00000000 a hello_mod.c  [hello_mod]
caad50a0 ? __mod_license33      [hello_mod]
00000000 a hello_mod.mod.c      [hello_mod]
caad50c0 ? __mod_vermagic5      [hello_mod]
ca97d080 r ____versions [hello_mod]
caad50f8 ? __module_depends     [hello_mod]
caad5120 ? __mod_srcversion30   [hello_mod]
ca97d480 d __this_module        [hello_mod]
ca97d015 t cleanup_module       [hello_mod]
ca97d000 t init_module  [hello_mod]
ca97d000 t hello_init   [hello_mod]
c012172d U printk       [hello_mod]
ca97d015 t hello_exit   [hello_mod]

 의미..

hello_init  의 메모리 주소
ca97d000
hello_exit 의 메모리 주소
ca97d015

타입정보에서 소문자이면, 내부에서만 사용된다는 의미이다.
d : 내부 전역 (static)
t : 내부 함수 (static)

만약 전역변수로 되게 하려면. 어떻게 해야 하지?

int num = 5;
EXPORT_SYMBOL(num);

kallsyms를 보면 확인가능
D : 전역 변수 (static 제외)

* 기타
값 초기화 하면, data 영역으로
값 초기화 안하면, bss 영역으로

Posted by '김용환'
,

c header 파일

c or linux 2011. 4. 18. 16:04


c 나 리눅스 standard libary header 파일
/usr/include/

커널쪽 header 파일 (uname -r 결과 기준)
/usr/src/kernels/2.6.11-1.1369_FC4-i686/include

Posted by '김용환'
,


#include <stdio.h>
#include <string.h>
int main(void) {
   FILE *fp;
    printf("Hello!\n");
    fwrite("Hello!\n", sizeof(char), strlen("Hello!\n"), stdout);
    write(1, "Hello!\n", sizeof(char)*strlen("Hello!\n"));

   fwrite("Hello!\n", sizeof(char), strlen("Hello!\n"), fp);
    fclose(fp);

}

'c or linux' 카테고리의 다른 글

리눅스 커널 시작 Hello World  (0) 2011.04.18
c header 파일  (0) 2011.04.18
cpulimit - cpu 사용량을 정한다.  (0) 2011.03.29
glibc 버젼 확인하기  (0) 2011.02.22
리눅스 시간 동기  (0) 2011.02.14
Posted by '김용환'
,