Search Results for 'Research/SystemProg'

30 POSTS

  1. 2012/01/27 cgrep
  2. 2012/01/26 export LC_ALL=C
  3. 2011/04/22 runtime control of printk times
  4. 2010/03/08 DirectFB Internals - Things You Need to Know to Write Your DirectFBgfxdriver
  5. 2010/03/02 What are the relationships among the main DirectFB types? Screen, Layers, Surface, ...
  6. 2009/11/30 신규 칩셋 선택시 검토할 사항
  7. 2009/06/02 Unaligned memory access
  8. 2009/02/19 Comparison of lightweight web servers
  9. 2008/04/04 objcopy
  10. 2007/10/19 memory allocation
  11. 2007/08/30 CPU에서 사용하는 두가지 캐쉬
  12. 2005/11/22 리눅스 메모리 관리의 이해를 돕는 그림
  13. 2005/11/22 A Map of the Networking Code in Linux Kernel 2.4.20
  14. 2005/07/28 kernel 파라미터 조정하기
  15. 2005/07/27 printk 사용시 주의할 점...
  16. 2005/06/15 MIPS linux cross compiler 제작예제
  17. 2005/02/28 context switching animation(x86) - ucos
  18. 2004/06/13 strongarm의 명령 한라인 수행하는데 걸리는 클럭과 계산 하는 방법을 알고 싶습니다 ..
  19. 2004/06/13 왜 arm-linux-gcc에서는 #pragma pack이 안될까? (출처:www.kelp.or.kr)
  20. 2004/06/07 가상 메모리
  21. 2004/06/06 커널 디버깅 기능 활성화과정
  22. 2004/06/06 압축 해제 이후 커널 패치 과정
  23. 2004/06/06 head-armv.S 추적 및 패치 과정
  24. 2004/06/03 Boot from Flash Memory
  25. 2003/12/10 [Q] relocation of bss and data
  26. 2003/12/01 Glabl변수의 초기화 및 영역
  27. 2002/12/04 커널에서 double형의 연산이 가능한가요?
  28. 2002/12/04 가상 메모리(Demand paging) (3)
  29. 2002/12/02 드라이버가 비동기 이벤트를 사용자 모드 응용 프로그램에 알리는 방법
  30. 2002/12/02 Polling a Device

cgrep

Posted 2012/01/27 10:57
#!/bin/bash

function usage()
{
   echo 'cgrep grep pattern from *.[chSs] or *.cpp or *.hpp or *.mk or [Mm]akefile'
}

if [ $# -eq 0 ]; then
    usage
    exit 1
fi
 
find . -type f -name "*.[chSs]" -o -name "*.cpp" -o -name "*.hpp" -o -name "*.mk" -o -name "[Mm]akefile" | xargs grep --color=auto -n "$1"

                                                                                                                                                          

export LC_ALL=C

Posted 2012/01/26 16:34
grep 등을 이용하여 패턴 검색을 할때, 예를 들어 아래 쉘스크립트와 같은 경우,

rev=`svn info 2>/dev/null`
rev=`echo "${rev}" | grep '^Revision' | awk '{print $NF}'`
설정된 로케일이 영문으로 설정된 경우는 문제없겠지만, 아래와 같이 한글로 설정된 경우에는 위 스크립트는 정상적으로 동작이 안될 것이다.

sunny@sunny-desk:~/project/01_WBS/0.2$ svn info
 경로: .
URL: https://svnhost/svn/ProjectRepo/trunk
저장소 루트: https://svnhost/svn/ProjectRepo
저장소 UUID: 0af9682f-c0b8-1742-9153-f717f418bd9a
리비전: 13
노드 종류: 디렉토리
스케쥴: 일반
마지막 수정 작업자: sunny
마지막 수정 리비전: 13
마지막 수정 일자: 2012-01-17 20:58:14 +0900 (2012-01-17, 화)

따라서, 시스템 로케일이 한글이 경우에도 쉘스크립트가 제대로 동작되게 하려면, 아래와 같이 export LC_ALL=C을 추가하면 된다.

export LC_ALL=C
rev=`svn info 2>/dev/null`
rev=`echo "${rev}" | grep '^Revision' | awk '{print $NF}'`


 sunny@sunny-desk:~/project/01_WBS/0.2$ svn info
Path: .
URL: https://svnhost/svn/ProjectRepo/trunk
Repository Root: https://svnhost/svn/ProjectRepo
Repository UUID: 0af9682f-c0b8-1742-9153-f717f418bd9a
Revision: 13
Node Kind: directory
Schedule: normal
Last Changed Author: sunny
Last Changed Rev: 13
Last Changed Date: 2012-01-17 20:58:14 +0900 (Tue, 17 Jan 2012)







runtime control of printk times

Posted 2011/04/22 16:18

source URL: http://elinux.org/Printk_Times


You can enable and disable printk timestamps at runtime, by writing to /sys/module/printk/parameters/time.

# cat /sys/module/printk/parameters/time
N
# echo 1 >/sys/module/printk/parameters/time
# cat /sys/module/printk/parameters/time
Y
# echo "sample log message" >/dev/kmsg
# dmesg | tail
....
[3814526.197336] sample log message
elc2008_directfb_gfx.pdf


What are the relationships among the main DirectFB types?

There are several one-to-one and one-to-many relationships here:

  • 1 IDirectFB (top-level) <--> N Screens
  • 1 Screen <--> N Layers
  • 1 Layer <--> 1 Primary Surface
  • 1 Layer <--> N Windows
  • 1 Window <--> 1 Window Surface
  • 1 Surface <--> N Subsurfaces

The most common case is one screen with one display layer, but DFB supports multiple instances of each.

Layers and Screens

Each screen can have one or more layers. Usually, a screen will have only one, but system that support overlays may have multiple layers with the hardware letting one layer show through another.

Screens and Windows

A screen cannot directly create a window, but you can ask a screen for the ID of its primary layer, then ask the IDirectFB interface to give you an interface to that layer, then use that interface to create a window.

Surfaces and Windows

Each window has a surface associated with it; drawing to that surface isn't immediately visible on the screen, as the window manager is responsible for compositing the surfaces of the windows to the primary surface based on their update regions and the stacking order, and the window manager is notified of changes by using the Flip() method of the surface.

Surfaces and Layers

A layer also has a surface associated with it; this surface is a direct representation of the layer's screen memory. You can only access this surface when you're in exclusive mode, otherwise you need to create a window and have the window manager draw to the surface.

Glibc 지원 여부 (uclibc만 지원하는 경우도 있음. (broadcom))

frambuffer driver 지원 여부 - 지원하지 않는 경우도 있음.

DirectFB 지원 여부

Unaligned memory access

Posted 2009/06/02 17:19

The problem starts in the memory chip. Memory is capable to read certain number of bytes at a time. If you try to read from unaligned memory address, your request will cause RAM chip to do two read operations. For instance, assuming RAM works with units of 8 bytes, trying to read 8 bytes from relative offset of 5 will cause RAM chips to do two read operations. First will read bytes 0-7. Second will read bytes 8-15. As a result, the relatively slow memory access will become even slower.

diagram1.png

Comparison of lightweight web servers

Posted 2009/02/19 02:17

Comparison of lightweight web servers

From Wikipedia, the free encyclopedia

Jump to: navigation, search

Lightweight web servers are Web servers which have been designed to run with very small resource overhead because of hardware, environment, or simply for the challenge of it.

Many of these systems have been created as a mental exercise to determine if a modern webserver could be written to run on limited resources such as those provided in a graphing calculator, a Commodore 64, or in 64 kB (64 KiB) total of memory. Others have been written as commercial endeavors to create webservers with low overhead for embedded systems (network router configuration pages) or low memory environments.

[edit] Overview

Server  ↓ Creator  ↓ Operating Systems  ↓ Development Language  ↓ Software license  ↓ Size (kB)  ↓ Last Stable Version  ↓ Home  ↓
0W Maxim Zotov Linux and FreeBSD C BSD-like 111
[1]
Abyss Aprelium Windows, Linux, Mac OS X and FreeBSD
Closed source 455
[2]
ebb Ryah Dahl Linux Ruby MIT ?
[3]
thin Marc-André Cournoyer Linux Ruby Ruby [4] ?
[5]
Anti-Web httpd Doug Hoyte and others Linux, Win32 C GPL ?
[6]
AppWeb Mbedthis/ Michael O'Brien Windows, Linux, FreeBSD, Mac OS X, VxWorks C++ GPL / Dual License [7] 350
[8]
Arachnida HTTP(S) server and client Ronald Landheer-Cieslak Windows, Linux, POSIX C++ GPL/BSD Dual License 500
[9]
Redleafd Alfeiks Kaänoken (MadTirra/Tirra) Linux C/Scheme GPL 200
[10]
BadBlue Working Resources Inc. Windows C++ Closed source 703
[11]
BarracudaDrive Real Time Logic Windows, Embedded Linux, Mac PowerPC
Closed source 713
[12]
Barracuda Web Server SDK Real Time Logic Unix, Windows, Mac, and most embedded systems C and Lua Closed source 100 - 500
[13]
Boa ? Unix C, Perl GPL [14] 120 0.94.14rc21 (2005-02-23) [15]
astahttpd Rio Astamal Linux PHP 5.2.x GPL 520
[16]
bozohttpd Matthew R. Green Unix C BSD 32
[17]
Cherokee Álvaro López Ortega Linux, Solaris, *BSD, Windows C GPL 686
[18]
cgttpd Davide Libenzi Linux C
?
[19]
chttpd Greg Olszewski Linux/Win32 C
17
[20]
cheetah Luke Reeves Linux C GPLv2 17
[21]
CoreHTTP ? Linux C GPL [22] 25
[23]
Dandelion Graeme Pietersz Linux, Windows, MacOS, Unix, any on which Tcl runs Tcl GPLv2, GPLv3 45
[24]
Darkhttpd Emil Mikulic UNIX C BSD ?
[25]
Devwex Seanox Software Solutions Any OS with Java 1.2 or higher Java Closed source 30
[26] (German)
dlib C++ http server Davis E. King Linux, Solaris, Windows, Mac OS X, BSD C++ Boost Software License [27] 10
[28]
FlyingAnt CD Web Server Wrensoft Windows, Linux, Mac OS X
Closed source 50
[29]
Fnord
Linux C GPLv2 18
[30]
foXServe Kdev/Davide Cantaluppi Embedded LX 832 fox board
Apache ?
[31]
Gforth httpd Bernd Paysan POSIX-style OS Forth GPL 273 SLOC
[32]
Mathopd Michiel Boland POSIX-style OS C ? 79 1.5 (2007-07-21) [33]
GoAhead WebServer GoAhead VxWorks, Windows CE, Windows, Lynx, Linux, QNX, eCOS, QNX, Netware, OS X, ChorusOS, pSOS, uCOS, IRIX, HP-UX, RTEMS, iRMX/INtime C Dual License [34] 110
[35]
Hiawatha Hugo Leisink Linux, BSD, Mac OS X, Windows C GPL [36] 100
[37]
HTTP File Server Massimo Melina (aka rejetto) Windows Delphi GPL 500
[38]
HTTPi Cameron Kaiser Unix Perl Floodgap Free Software License (FFSL) [39] 58
[40]
ihttpd ? Unix C
40
[41]
KLone KoanLogic Linux, NetBSD, OpenBSD, FreeBSD, QNX, VxWorks, Darwin/Mac OS X, Windows C GPL 200
[42]
Kolibri SENKAS Windows C++ GPL ?
[43]
Kolibri+ SENKAS Windows C++ Closed source ?
[44]
leahhtpd GNU Unix, Linux, Windows C
?
[45]
libmicrohttpd GNU Unix, Linux, Windows C LGPL 25
[46]
libwebserver Luis Figueiredo Unix, Linux, Windows C LGPL [47] 231
[48]
lighttpd Jan Kneschke Unix, Linux, Windows C BSD [49] ? 1.4.20 (Sep 30, 2008) [50]
Lite Netquestion HTTP Web Server ? AIX

28
?
Mongoose Sergey Lyubka Windows, QNX, *BSD, Solaris, Linux, Portable to any OS C MIT 40 2.3 [51]
Monkey HTTP Daemon Eduardo Silva Linux C GPLv2 45
[52]
muhttpd Robbert Haarman UNIX C ? 25
[53]
NaninHttpd ? All Ruby Ruby
14
[54]
NanoHTTPD Jarno Elonen Any OS with Java 1.1 or higher Java Modified BSD 28
[55]
Webserver included with JRE 1.6+ Sun Any OS with Java 1.6 or higher Java Sun Java license 0 (already included with java libraries)
[56]
NanoWeb Vincent Negrier, Mario Salzer, and others Any that supports PHP PHP 4.3
?
[57]
nginx Igor Sysoev Unix-like C BSD 468 0.6.34 (Nov 27, 2008) [58]
NicheStack HTTP Server InterNiche Technologies [59] Any 16 or 32bit embedded C Closed source 9 v3.1 [60]
nostromo - nhttpd Marcus Glocker Unix-like, OpenBSD developed C MIT 55
[61]
Null httpd ? Linux, Windows[1] C
52
[62]
nweb ? Unix C
36
[63]
Obelisk-HTTP Filipe Caldas Any OS with Python Python
50 0.4.4 (Sep 27, 2007) [64]
PS-HTTPD Anders Karlsson
PostScript GPL 8
[65]
publicfile Dan J. Bernstein Any POSIX OS C Public Domain 29
[66]
qshttpd Cosmin Gorgovan Unix C GPL 16
[67]
Rupy ? Any OS with Java 1.4 or higher Java LGPL 45
[68]
SAS ? Linux Assembly
0.941
[69]
Seminole GladeSoft eCos, VxWorks, POSIX, Win32, uCOS C
?
[70]
Shttp Yingyuan Cheng Linux C GPLv2 16
[71]
Simple HTTPD Charlie Lee Unix C
12
[72]
Spud ? Embedded PIC16F876

1
[73]
SWILL David Beazley and Sotiria Lampoudi Windows, Unix C
116
[74]
Techlogica HTTP Server Kyle White Windows

292
[75]
thttpd Acme Labs Unix C
50[2] 2.25b (2003-12-29) [76]
TinyWeb Maxim Masiutin Win32 Delphi
53
[77]
Tntnet Tommi Mäkitalo Unix C++ LGPL 940
[78]
UIP Adam Dunkels Embedded 8bit C
?
[79]
VQEmbWeb Gareth Cronin Any OS with support for Java 5 Java
12
[80]
webAce Fredric White Embedded Fairchild ACE1101MT8[3] ACE1101MT8 microcontroller instructions
1 (1074 bytes)[3]
http://d116.com/ace/
wxWebServer Fedja Stevanovic Windows, Mac OS X, Linux C++
?
[81]
Allegro Embedded WebServer ? Portable to any OS C ? ?
[82]
Mini httpd Jef Poskanzer UNIX C GPL 41
[83]
Micro HTTPD Jef Poskanzer UNIX C GPL 4.98
[84]
JS httpd Jef Poskanzer UNIX Javascript GPL 4.16
[85]
Plain Old Webserver David Kellogg Any OS Mozilla Firefox runs on Javascript GPL 80.1
[86]
Pure Perl CGId Erik Aronesty Any OS perl runs on Perl GPL 11.5
[87]
Wt emweb Linux/BSD/Solaris/..., Windows 2000/XP/Vista, Mac OS X, Others C++ GPL/Commercial Dual License [88] 250
[89]
Xavante The Kepler Project Linux, BSD, Windows, Mac OS X, Others Lua GPL compatible 38
[90]
ZwebServer http://zotagsearch.com/euphorica/#aboutme[dead link] Travis Cunningham[clarification needed] Windows 2000/XP/Vista C#
132
http://zotagsearch.com/zwebserver/[dead link]
Server Creator Operating Systems Development Language License Size (kB) Latest Stable Version Home

[edit] See also

[edit] References

  1. ^ NullLogic. NullLogic - Projects. Retrieved 2009-01-18
  2. ^ "Web Server Comparisons (July 1998)". acme.com. http://www.acme.com/software/thttpd/benchmarks.html. 
  3. ^ a b Fredric White. webACE Server. 2001-08-05. Retrieved 2009-01-18

'Research > SystemProg' 카테고리의 다른 글

신규 칩셋 선택시 검토할 사항  (0) 2009/11/30
Unaligned memory access  (0) 2009/06/02
Comparison of lightweight web servers  (0) 2009/02/19
objcopy  (0) 2008/04/04
memory allocation  (0) 2007/10/19
CPU에서 사용하는 두가지 캐쉬  (0) 2007/08/30

objcopy

Posted 2008/04/04 15:26
출처 : http://blog.naver.com/letov/70012723177


objcopy는 오브젝트 파일을 다른 오브젝트 파일로 복사할 때 사용한는데, 선택적으로 필요한 부분만
을 복사할 수 있기 때문에 파일의 사이즈를 줄이는 데 주로 사용되고, 바이너리 포맷을 바꾸는 데도 이
용된다.
ex) objcopy hello hello.new
hello 파일을 hello.new로 복사, 기존의 hello와 동일하다.
ex) objcopy -O binary hello hello.new
위 명령은 hello 파일에서 인스트럭션과 데이터만을 뽑아서 hello.new로 만든다. 이렇게 만들어진
hello.new는 ELF 헤더도 붙지 않은 순수한 바이너리 그 자체다. 주로 부트 로더를 만들 때 이런 식으
로 사용하는데 이유는 모든 CPU마다 전원이 인가되었을 때 CPU가 인스트럭션을 처음 읽어서 실행할
번지가 정해져 있다. 예를 들면 i386 계열은 0xfffffff0 번지이고 ARM 계열 CPU는 0x0 번지며
MPC860 CPU 같은 경우 0xff00100번지다.
무슨 말이냐하면 i386 계열 CPU는 전원이 켜지는 순간 BIOS의 POST(Power On Self Test) 프로그
램이 위치하는 0xfffffff0 번지의 인스트럭션을 제일 처음 읽어서 수행한다.
i386 PC 외의 CPU 같은 경우 처음 수행하는 프로그램은 부트 로더인데 이러한 부트 로더는 인스트럭
션이 제일 앞에 와있는 바이너리여야 한다. 즉 ELF 헤더가 붙어서는 안 된다는 이야기다. ELF 헤더는
운영체제에서 필요한 정보지 CPU에서 필요한 정보는 아니다.
ex) objcopy -S hello hello.new
모든 심볼들과 재비치 정보들을 제거하여 hello.new 파일을 만든다. 그래서 바이너리 파일의 사이즈가
확실히 줄어든다.
- 참고 문헌 : 유닉스, 리눅스 프로그래밍 필수 유틸리디

'Research > SystemProg' 카테고리의 다른 글

Unaligned memory access  (0) 2009/06/02
Comparison of lightweight web servers  (0) 2009/02/19
objcopy  (0) 2008/04/04
memory allocation  (0) 2007/10/19
CPU에서 사용하는 두가지 캐쉬  (0) 2007/08/30
리눅스 메모리 관리의 이해를 돕는 그림  (0) 2005/11/22

memory allocation

Posted 2007/10/19 16:30
06MemoryAllocation.ppt

'Research > SystemProg' 카테고리의 다른 글

Comparison of lightweight web servers  (0) 2009/02/19
objcopy  (0) 2008/04/04
memory allocation  (0) 2007/10/19
CPU에서 사용하는 두가지 캐쉬  (0) 2007/08/30
리눅스 메모리 관리의 이해를 돕는 그림  (0) 2005/11/22
A Map of the Networking Code in Linux Kernel 2.4.20  (0) 2005/11/22

CPU에서 사용하는 두가지 캐쉬

Posted 2007/08/30 10:45
※ CPU에서 사용하는 두가지 캐쉬



Write Back(Behind) → 80486이후 마이크로 프로세서에서 사용하는 방식인데,



L1 Cache(명령어캐쉬)에 저장된 데이타가 필요할 경우에만 주메모리에 기록됩니다.



기록시에는 CPU 대기(CPU Wait-State)시간을 사용해서 후면작업(백그라운드)을



하듯이 데이타 기록(Write)과정을 처리합니다.




Write Through → 데이타 쓰기작업을 L1캐쉬와 주메모리에서 필요시에는 동시에



병렬로 처리합니다. 유휴시간이 아니라 그때그때 바로바로 데이타 쓰기작업을 합니다.



캐쉬에 쓰기작업중에 캐쉬에 대한 데이타 읽기가 요구될 경우에도 동시 작업으로



처리합니다. Write Back은 동시 요구시에 읽기가 끝난후에 쓰기작업을 재계합니다.



낙후된 기술로, Write Back보다 효율면에서 뒤떨어지는 방식입니다

'Research > SystemProg' 카테고리의 다른 글

objcopy  (0) 2008/04/04
memory allocation  (0) 2007/10/19
CPU에서 사용하는 두가지 캐쉬  (0) 2007/08/30
리눅스 메모리 관리의 이해를 돕는 그림  (0) 2005/11/22
A Map of the Networking Code in Linux Kernel 2.4.20  (0) 2005/11/22
kernel 파라미터 조정하기  (0) 2005/07/28
...
--

kernel 파라미터 조정하기

Posted 2005/07/28 16:47
보통 커널의 파라미터를 조정할때 proc 에서 echo 를 이용하여 redirect
로 직접 쓰는 경우가 많았다. 이렇게 조정을 할 경우에는 또 rc.local 같
은 파일에 따로 기입을 해 줘야 하는 불편함이 있었다.

RedHat 6.2 이후 배포판에는 sysctl 이라는 package가 추가되어 이것들을
관리를 할수 있게 되었다. 일단 조정할수 있는 모든 parameter 들은

$ sysctl -a

명령으로 확인을 할수가 있다. 그리고 특정값을 수정하기 위해서는
/etc/sysctl.conf 에 해당 키(이건 sysctl -a 명령에서 리스트를 확인
할수 있다)와 키값을 지정한 다음

$ sysctl -p

명령으로 바로 적용을 시킬수 있다. 물론 sysctl.conf 에 기입이 되면
부팅시 마다 자동으로 적용이 된다.

만약 잠시만 바꾸어 보고 싶다면

$ sysctl -w net.ipv4.icmp_echo_ignore_all=0

과 같이 직접 값을 넣어 줄수도 있다. 이럴 경우에는 부팅이 되어 있는
순간만 적용이 된다. -p 옵션은 sysctl.conf 가 아닌 다른 파일을 설정
파일로 지정을 할수 있게 한다. 옵션값이 없으면 default 로
/etc/sysctl.conf 를 읽어 들이며 따로 path 를 지정하면 해당 path 에
있는 파일을 읽어 들인다.


printk 사용시 주의할 점...

Posted 2005/07/27 10:41
타입을 주의하여 사용하여야 한다. 가령 예를 들어, 다음에서 보면,

static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
{
     struct mtd_part *part = PART(mtd);

     if ((len + ofs) > mtd->size)
         return -EINVAL;
     printk(__FUNCTION__ ": ofs = %Lx, part->offset = %lx, len = %lx n", ofs, part->offset, (unsigned int)len);
     return part->master->unlock(part->master, ofs + part->offset, len);
}

ofs는 loff_t 타입인데, loff_t 타입은 long long 타입의 typedef 이다.
따라서, ofs 값을 표시할 때, 위와 같이 %L (L은 long long type) 을 사용하지 않고, %l 이나, %x 등을 사용하면,
ofs 값이 제대로 출력되지 않을 뿐 아니라, 뒤에 출력하는 값마저 영향을 받아서 엉뚱한 값이 출력된다.

MIPS linux cross compiler 제작예제

Posted 2005/06/15 11:49
http://kelp.or.kr/korweblog/?story=04/06/04/0386624 KELP - Korea Embedded Linux Project 제목: MIPS linux cross compiler 제작예제

글쓴이: 이영진
글쓴날: 2004년 06월 04일 오후 08:59
URL : http://kelp.or.kr/korweblog/?story=04/06/04/0386624


안녕하세요. (주) 시그마컴 연구 3팀입니다.
ARM에 비해 상대적으로 이용자가 적은 MIPS에 관련된 글을 하나 올리겠습니다.

http://www.gnu.org에서 binutils, gcc, glibc, glibc-linuxthread를 다운 받는다.

작업디렉토리 : $(WORK) 에 다운 받은 파일들이 놓여있다고 가정한다. 굳이 target이란 디렉토리 밑에 작업 환경을 꾸민 이유는 관리하기에 단순무식해서 편하다는 장점때문이다. 작업한 시스템은 Mandrake 1.0 community 인가 하는 버전이고 binutil-2.15, gcc-3.4.0, glibc-2.3.2이며 따로 패치된 것이 아니다.
http://laronde.org/~brad/mips/mips-cross-toolchain/ 이 싸이트의 것을 그대로 따라한다. 또한 http://www.kegel.com/crosstool 에서도 많은 도움을 얻었다.

1 binutils
별로 어려운게 없다. 그냥 설치할 위치를 지정해 주고 target에다가 mipsel-linux 혹은 mips-linux를 적용해 주면 된다. libdir은 뭔지 나도 잘 모르겠다.

$ cd $(WORK)
$ tar xjf binutils-??.bz2
$ mkdir target; cd target; mkdir binutils
$ cd binutils
$ $(WORK)/binutils-??/configure --prefix=/opt/host/mispel-linux
--target=mipsel-linux --libdir='${exec_prefix}'/mipsel-linux/i386-linux/lib
$ make
$ sudo make install


2. static gcc #
완전한 gcc를 만들기 위해서는 glibc가 필요하지만 아직 glibc를 빌드 하기 전이다. 따라서 static버전의 c언어 컴파일러부터 제작한후에 glibc를 빌드하고 다시 gcc를 빌드하는 과정을 거친다. 이 과정에서 static gcc를 빌드 하기 위해서는 커널 헤더 파일과 시스템 헤더 파일이 필요하다. 다른 곳에서 만들어진 크로스 컴파일러의 것을 복사하거나 단순히 호스트의 /usr/include를 임시로 복사해서 사용할 수도 있다. 단 이때에도 커널 헤더파일은 해당 타겟 시스템 것을 복사하는 것이 좋다. 물론 이 방법들은 모두 에러 가능성을 다분히 지니고 있는 단점이 있다. 이 예제에서는 시스템 헤더 파일(/usr/include)을 작업 디렉토리에 복사하고 asm, asm-generic, linux 디렉토리를 커널 것으로 대체했다.
* 저도 이게 어느 수준의 헤더가 필요한지 잘 몰라서요. 보통은 비슷한 버전 대의 기존 도구의 헤더를 슬쩍 빌립니다. ^_^
binutils을 인스톨 한 후에 그 PATH의 바이너리들을 PATH에 걸어둔다. configure시에 enable-language 는 c만 지정하고 disable_shared옵션을 걸고 앞서 설명한 헤더 파일이 존재하는 디렉토리를 with-headers로 지정한다.

$ export PATH=/opt/host/mipsel-linux/bin:$PATH
$ cd $(WORK)
$ tar xjf gcc-??.bz2
$ cd target; mkdir gcc
$ cd gcc
$ sudo $(WORK)/gcc-??/configure --prefix=/opt/host/mipsel-linux
--target=mipsel-linux --enable-languages=c --disable-shared
--with-headers=/home/romntica/CCK/test/include
$ make
$ sudo make install
configure시에 sudo를 하는 것은 지정한 헤더파일($with-headers)과 함께 필요한 파일들을 $prefix/mipsel-linux/sys-include로 복사 하기 때문이다.

3 glibc #
자 이제 말도 많고 탈도 많은 glibc를 만들어보자. 많은 사람들이 이 부분에서 어려움을 호소하거나 포기하는 경우가 있다. 그렇지만 어려울 것 없다. 검색 엔진을 활용하면 된다.
google에서 mips glibc로 검색을 해보았더니 관련 패치에 관한 사이트가 몇 개 나왔다. 내용들을 잘 살펴보고 필요한 것을 적용하기만 하면 된다. 이 예제에서는 다음의 패치를 적용하였다. 물론 여기서 사용된 패치가 꼭 필요하거나 전혀 필요치 않다거나의 여부는 따지지 않는다. 꼭 이것뿐 만이 아니고 개발하려는 장치명으로 검색하시면 gcc나 binutils나 glibc에도 적용할 만한 유용한 패치가 많이 있습니다. 예를 들어 제가 도시바 TX49계열의 칩을 사용했는데 그냥 하면 MULTX인가?? 곱셈연산자를 활용을 못하는 것을 binutils를 패치하고나면 해당 연산자를 사용할 수 있게 해주는 패치가 있었습니다.
우선 linuxthread를 add-on하기 위해 glibc-?? 디렉토리의 서브디렉토리로 압축 해제해준다.
$ cd $(WORK)
$ tar xjf glibc-??.bz2
$ cd glibc-??
$ cd $(WORK)/target; mkdir glibc
$ cd glibc
$ tar xjf ../glibc-linuxthread-??.bz2

그리고 다음의 패치를 적용한다. (죄송합니다. 컴파일 전에 diff를 때렸어야 했는데 clean해도 깨끗이 안되는군요. 파일이 너무 커지다보니 실수로 지워버린 것도 있을 것입니다. 문의하시면 답변해 드리겠습니다.)
diff -urN glibc-2.3.2/Makeconfig glibc-2.3.2-fixed/Makeconfig
--- glibc-2.3.2/Makeconfig 2003-01-06 05:31:36.000000000 +0000
+++ glibc-2.3.2-fixed/Makeconfig 2004-06-04 16:39:10.711288024 +0000
@@ -637,7 +637,7 @@
$(foreach lib,$(libof-$(basename $(@F)))
$(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib)))
$(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
-override CFLAGS = -std=gnu99
+override CFLAGS = -std=gnu9x
$(filter-out %frame-pointer,$(+cflags)) $(sysdep-CFLAGS)
$(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) $(CFLAGS-$(@F))

diff -urN glibc-2.3.2/elf/dl-conflict.c glibc-2.3.2-fixed/elf/dl-conflict.c
--- glibc-2.3.2/elf/dl-conflict.c 2002-10-17 17:05:51.000000000 +0000
+++ glibc-2.3.2-fixed/elf/dl-conflict.c 2004-06-04 13:48:20.897496568 +0000
@@ -33,6 +33,7 @@
_dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict,
ElfW(Rela) *conflictend)
{
+#ifndef _DL_HAVE_NO_ELF_MACHINE_RELA
if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_RELOC, 0))
_dl_printf ("nconflict processing: %sn",
l->l_name[0] ? l->l_name : rtld_progname);
@@ -64,4 +65,5 @@
for (; conflict < conflictend; ++conflict)
elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset);
}
+#endif
}
--- glibc-2.3.2/resolv/Makefile 2003-02-25 23:40:08.000000000 +0000
+++ glibc-2.3.2-fixed/resolv/Makefile 2004-06-04 18:46:07.402374976 +0000
@@ -93,6 +93,8 @@
tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace
$(objpfx)mtrace-tst-leaks: $(objpfx)tst-leaks.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@
+ifeq (no,$(cross-compiling))
ifneq (no,$(PERL))
tests: $(objpfx)mtrace-tst-leaks
endif
+endif
diff -urN glibc-2.3.2/stdio-common/sscanf.c glibc-2.3.2-fixed/stdio-common/sscanf.c
--- glibc-2.3.2/stdio-common/sscanf.c 2002-08-10 18:09:08.000000000 +0000
+++ glibc-2.3.2-fixed/stdio-common/sscanf.c 2004-06-04 14:15:10.784756504 +0000
@@ -27,9 +27,7 @@
/* Read formatted input from S, according to the format string FORMAT. */
/* VARARGS2 */
int
-sscanf (s, format)
- const char *s;
- const char *format;
+sscanf (const char *s, const char *format, ...)
{
va_list arg;
int done;
diff -urN glibc-2.3.2/string/bits/string2.h glibc-2.3.2-fixed/string/bits/string2.h
--- glibc-2.3.2/string/bits/string2.h 2002-05-25 06:09:18.000000000 +0000
+++ glibc-2.3.2-fixed/string/bits/string2.h 2004-06-04 17:50:57.070621896 +0000
@@ -76,7 +76,7 @@
use unaligned memory accesses. */
# define __STRING2_COPY_TYPE(N)
typedef struct { unsigned char __arr[N]; }
- __STRING2_COPY_ARR##N __attribute__ ((packed))
+ __attribute__ ((__packed__)) __STRING2_COPY_ARR##N
__STRING2_COPY_TYPE (2);
__STRING2_COPY_TYPE (3);
__STRING2_COPY_TYPE (4);
diff -urN glibc-2.3.2/sysdeps/mips/Makefile glibc-2.3.2-fixed/sysdeps/mips/Makefile
--- glibc-2.3.2/sysdeps/mips/Makefile 2000-09-06 20:26:50.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/mips/Makefile 2004-06-04 17:53:16.754386736 +0000
@@ -6,3 +6,11 @@
ifeq ($(subdir),setjmp)
sysdep_routines += setjmp_aux
endif
+
+ifeq ($(subdir),csu)
+ifeq (yes,$(build-shared))
+# Compatibility
+sysdep_routines += divdi3
+shared-only-routines += divdi3
+endif
+endif
diff -urN glibc-2.3.2/sysdeps/mips/dl-machine.h glibc-2.3.2-fixed/sysdeps/mips/dl-machine.h
--- glibc-2.3.2/sysdeps/mips/dl-machine.h 2003-02-12 09:42:22.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/mips/dl-machine.h 2004-06-04 13:49:03.153072744 +0000
@@ -55,7 +55,9 @@
to avoid the asserts in dl-lookup.c from blowing. */
#define ELF_MACHINE_JMP_SLOT R_MIPS_REL32
#define elf_machine_type_class(type) ELF_RTYPE_CLASS_PLT
-
+
+/* MIPS doesn't support RELA */
+#define _DL_HAVE_NO_ELF_MACHINE_RELA
/* Translate a processor specific dynamic tag to the index
in l_info array. */
#define DT_MIPS(x) (DT_MIPS_##x - DT_LOPROC + DT_NUM)
diff -urN glibc-2.3.2/sysdeps/mips/mips64/bsd-_setjmp.S glibc-2.3.2-fixed/sysdeps/mips/mips64/bsd-_setjmp.S
--- glibc-2.3.2/sysdeps/mips/mips64/bsd-_setjmp.S 2002-12-31 19:13:27.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/mips/mips64/bsd-_setjmp.S 2004-06-04 13:55:25.649924384 +0000
@@ -22,6 +22,7 @@
in setjmp doesn't clobber the state restored by longjmp. */

#include <sysdep.h>
+#include <sys/asm.h>

#ifdef __PIC__
.option pic2
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/bits/mman.h glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/bits/mman.h
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/bits/mman.h 2001-07-07 19:21:35.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/bits/mman.h 2004-06-04 14:02:26.079009448 +0000
@@ -59,6 +59,8 @@
# define MAP_DENYWRITE 0x2000 /* ETXTBSY */
# define MAP_EXECUTABLE 0x4000 /* mark it as an executable */
# define MAP_LOCKED 0x8000 /* pages are locked */
+# define MAP_POPULATE 0x10000
+# define MAP_NONBLOCK 0x20000
#endif

/* Flags to `msync'. */
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/bits/siginfo.h glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/bits/siginfo.h
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/bits/siginfo.h 2002-12-05 00:22:19.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/bits/siginfo.h 2004-06-04 13:59:42.053945048 +0000
@@ -119,8 +119,10 @@
signals. */
enum
{
- SI_ASYNCNL = -6, /* Sent by asynch name lookup completion. */
+ SI_ASYNCNL = -60, /* Sent by asynch name lookup completion. */
# define SI_ASYNCNL SI_ASYNCNL
+ SI_TKILL = -6,
+# define SI_TKILL SI_TKILL
SI_SIGIO, /* Sent by queued SIGIO. */
# define SI_SIGIO SI_SIGIO
SI_MESGQ, /* Sent by real time mesq state change. */
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/clone.S glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/clone.S
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/clone.S 2001-07-07 19:21:35.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/clone.S 2004-06-04 13:09:34.246201328 +0000
@@ -63,7 +63,7 @@
syscall

bnez a3,error
- beqz v0,__thread_start
+ beqz v0,.Lthread_start

/* Successful return from the parent */
addiu sp,32
@@ -85,6 +85,7 @@
debug info. */

ENTRY(__thread_start)
+.Lthread_start:
/* cp is already loaded. */
.cprestore 16
/* The stackframe has been created on entry of clone(). */
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/kernel_stat.h glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/kernel_stat.h
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/kernel_stat.h 2000-11-20 08:45:43.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/kernel_stat.h 2004-06-04 15:51:16.873177824 +0000
@@ -1,3 +1,5 @@
+#ifndef _KERNEL_STAT_H
+#define _KERNEL_STAT_H 1
/* Definition of `struct stat' used in the kernel.. */
struct kernel_stat
{
@@ -26,3 +28,4 @@
unsigned int st_flags;
unsigned int st_gen;
};
+#endif
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pread.c glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pread.c
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pread.c 2003-01-27 18:55:20.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pread.c 2004-06-04 14:09:59.519076080 +0000
@@ -34,6 +34,24 @@
# endif
# define __NR_pread __NR_pread64
#endif
+#ifdef __NR_O32_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_O32_pread
+# error "__NR_O32_pread and __NR_O32_pread64 both defined???"
+# endif
+# define __NR_O32_pread __NR_O32_pread64
+#endif
+#ifdef __NR_N32_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N32_pread
+# error "__NR_N32_pread and __NR_N32_pread64 both defined???"
+# endif
+# define __NR_N32_pread __NR_N32_pread64
+#endif
+#ifdef __NR_N64_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N64_pread
+# error "__NR_N64_pread and __NR_N64_pread64 both defined???"
+# endif
+# define __NR_N64_pread __NR_N64_pread64
+#endif

#if defined __NR_pread || __ASSUME_PREAD_SYSCALL > 0

diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pread64.c glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pread64.c
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pread64.c 2003-01-27 18:55:20.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pread64.c 2004-06-04 14:10:25.987052336 +0000
@@ -33,6 +33,25 @@
# endif
# define __NR_pread __NR_pread64
#endif
+#ifdef __NR_O32_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_O32_pread
+# error "__NR_O32_pread and __NR_O32_pread64 both defined???"
+# endif
+# define __NR_O32_pread __NR_O32_pread64
+#endif
+#ifdef __NR_N32_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N32_pread
+# error "__NR_N32_pread and __NR_N32_pread64 both defined???"
+# endif
+# define __NR_N32_pread __NR_N32_pread64
+#endif
+#ifdef __NR_N64_pread64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N64_pread
+# error "__NR_N64_pread and __NR_N64_pread64 both defined???"
+# endif
+# define __NR_N64_pread __NR_N64_pread64
+#endif
+

#if defined __NR_pread || __ASSUME_PREAD_SYSCALL > 0

diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pwrite.c glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pwrite.c
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pwrite.c 2003-01-27 18:55:20.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pwrite.c 2004-06-04 14:11:12.383998928 +0000
@@ -34,6 +34,24 @@
# endif
# define __NR_pwrite __NR_pwrite64
#endif
+#ifdef __NR_O32_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_O32_pwrite
+# error "__NR_O32_pwrite and __NR_O32_pwrite64 both defined???"
+# endif
+# define __NR_O32_pwrite __NR_O32_pwrite64
+#endif
+#ifdef __NR_N32_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N32_pwrite
+# error "__NR_N32_pwrite and __NR_N32_pwrite64 both defined???"
+# endif
+# define __NR_N32_pwrite __NR_N32_pwrite64
+#endif
+#ifdef __NR_N64_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N64_pwrite
+# error "__NR_N64_pwrite and __NR_N64_pwrite64 both defined???"
+# endif
+# define __NR_N64_pwrite __NR_N64_pwrite64
+#endif

#if defined __NR_pwrite || __ASSUME_PWRITE_SYSCALL > 0

diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pwrite64.c glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pwrite64.c
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/pwrite64.c 2003-01-27 18:55:20.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/pwrite64.c 2004-06-04 14:11:34.494637600 +0000
@@ -33,7 +33,24 @@
# endif
# define __NR_pwrite __NR_pwrite64
#endif
-
+#ifdef __NR_O32_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_O32_pwrite
+# error "__NR_O32_pwrite and __NR_O32_pwrite64 both defined???"
+# endif
+# define __NR_O32_pwrite __NR_O32_pwrite64
+#endif
+#ifdef __NR_N32_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N32_pwrite
+# error "__NR_N32_pwrite and __NR_N32_pwrite64 both defined???"
+# endif
+# define __NR_N32_pwrite __NR_N32_pwrite64
+#endif
+#ifdef __NR_N64_pwrite64 /* Newer kernels renamed but it's the same. */
+# ifdef __NR_N64_pwrite
+# error "__NR_N64_pwrite and __NR_N64_pwrite64 both defined???"
+# endif
+# define __NR_N64_pwrite __NR_N64_pwrite64
+#endif
#if defined __NR_pwrite || __ASSUME_PWRITE_SYSCALL > 0

extern ssize_t __syscall_pwrite (int fd, const void *__unbounded buf, size_t count,
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/syscalls.list glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/syscalls.list
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/syscalls.list 2003-01-31 03:39:32.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/syscalls.list 2004-06-04 17:54:47.274625568 +0000
@@ -32,50 +32,12 @@
socket - socket i:iii __socket socket
socketpair - socketpair i:iiif __socketpair socketpair

-#
-# These are defined locally because the caller is also defined in this dir.
-#
-s_llseek llseek _llseek i:iiipi __syscall__llseek
-s_sigaction sigaction sigaction i:ipp __syscall_sigaction
-s_ustat ustat ustat i:ip __syscall_ustat
-sys_mknod xmknod mknod i:sii __syscall_mknod
-
# System calls with wrappers.
+s_readahead EXTRA readahead i:iipi __syscall_readahead
rt_sigaction - rt_sigaction i:ippi __syscall_rt_sigaction
rt_sigpending - rt_sigpending i:pi __syscall_rt_sigpending
rt_sigprocmask - rt_sigprocmask i:ippi __syscall_rt_sigprocmask
rt_sigqueueinfo - rt_sigqueueinfo i:iip __syscall_rt_sigqueueinfo
rt_sigsuspend - rt_sigsuspend i:pi __syscall_rt_sigsuspend
rt_sigtimedwait - rt_sigtimedwait i:pppi __syscall_rt_sigtimedwait
-s_execve EXTRA execve i:spp __syscall_execve
-s_exit _exit exit i:i __syscall_exit
-s_fcntl fcntl fcntl i:iiF __syscall_fcntl
-s_fcntl64 fcntl64 fcntl64 i:iiF __syscall_fcntl64
-s_fstat64 fxstat64 fstat64 i:ip __syscall_fstat64
-s_ftruncate64 ftruncate64 ftruncate64 i:iiii __syscall_ftruncate64
-s_getcwd getcwd getcwd i:pi __syscall_getcwd
-s_getdents getdents getdents i:ipi __syscall_getdents
-s_getdents64 getdents getdents64 i:ipi __syscall_getdents64
-s_getpriority getpriority getpriority i:ii __syscall_getpriority
-s_ipc msgget ipc i:iiiip __syscall_ipc
-s_lstat64 lxstat64 lstat64 i:sp __syscall_lstat64
-s_mmap2 mmap64 mmap2 b:aniiii __syscall_mmap2
-s_poll poll poll i:pii __syscall_poll
-s_pread64 pread64 pread i:ibniii __syscall_pread
-s_ptrace ptrace ptrace i:iipp __syscall_ptrace
-s_pwrite64 pwrite64 pwrite i:ibniii __syscall_pwrite
-s_readahead EXTRA readahead i:iiii __syscall_readahead
-s_reboot reboot reboot i:iii __syscall_reboot
-s_setrlimit setrlimit setrlimit i:ip __syscall_setrlimit
-s_sigpending sigpending sigpending i:p __syscall_sigpending
-s_sigprocmask sigprocmask sigprocmask i:ipp __syscall_sigprocmask
-s_stat64 xstat64 stat64 i:sp __syscall_stat64
-s_truncate64 truncate64 truncate64 i:siii __syscall_truncate64

-# Todo: we can pass 6 args in registers, no need for the wrapper
-sys_sysctl sysctl _sysctl i:p __syscall__sysctl
-sys_fstat fxstat fstat i:ip __syscall_fstat
-sys_lstat lxstat lstat i:sp __syscall_lstat
-sys_readv readv readv i:ipi __syscall_readv
-sys_stat xstat stat i:sp __syscall_stat
-sys_writev writev writev i:ipi __syscall_writev
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/mips/xstatconv.c glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/xstatconv.c
--- glibc-2.3.2/sysdeps/unix/sysv/linux/mips/xstatconv.c 2001-07-07 19:21:35.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/mips/xstatconv.c 2004-06-04 15:47:51.887340408 +0000
@@ -18,6 +18,11 @@
02111-1307 USA. */

#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <kernel_stat.h>
+
+#include <string.h>


static inline int
diff -urN glibc-2.3.2/sysdeps/unix/sysv/linux/sys/epoll.h glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/sys/epoll.h
--- glibc-2.3.2/sysdeps/unix/sysv/linux/sys/epoll.h 2002-12-16 23:24:21.000000000 +0000
+++ glibc-2.3.2-fixed/sysdeps/unix/sysv/linux/sys/epoll.h 2004-06-04 17:59:29.871664288 +0000
@@ -19,6 +19,7 @@
#ifndef _SYS_EPOLL_H
#define _SYS_EPOLL_H 1

+#include <stdint.h>
#include <sys/types.h>


@@ -44,6 +45,8 @@
#define EPOLLERR EPOLLERR
EPOLLHUP = 0x010
#define EPOLLHUP EPOLLHUP
+ EPOLLET = (1<<31)
+#define EPOLLET EPOLLET
};


패치가 끝났으면 이제 glibc를 만들어 보자. 물론 한번에 될 거라곤 생각 않는다. 나도 이 예제를 무려 세 번이나 다시 빌드해서 성공했다. gcc와 glibc의 버전에 따른 문제에 기인했던 것 같다. 문제가 발생하면 찾아보고 모르겠으면 다시 또 인터넷을 뒤져보자! 아 주의할 사항은 prefix를 /usr로 줘야 한다는 것이다. glibc가 /usr인 prefix는 특별하게 다룬다고 한다.

$ CFLAGS="-O2 -g -finline-limit=10000 -fno-unit-at-a-time" ../../glibc-??/configure --prefix=/usr --build=i686-linux --host=mipsel-linux --enable-add-ons
$ make
$ make install install_root=/opt/host/mipsel-linux/glibc
이렇게 하면 glibc에 인스톨이 된다.
glibc/lib/* 과 glibc/usr/lib/*을 /opt/host/mipsel-linux/mipsel-linux/lib에 복사한다. 또한 glibc/usr/include/*를 /opt/host/mipsel-linux/mipsel-linux/include로 복사한다. 나머지 glibc의 기타 등등은 옵션으로 각각에 맞게 /opt/host/mipsel-linux/mipsel-linux에다가 복사해 넣으면 된다. 이때 복사를 하면서 lib/*이하에 소프트링크가 깨진 것들이 있는데 걍 놔둬두 무방한것도 있고 필요에 따라 수정해 주면 된다. glibc이하는 삭제해도 좋다.

4 gcc 다시 만들기
이제 완전한 버전의 GCC를 다시 만들기만 하면 된다. 해당 작업디렉토리로 가서 깔끔하게 이전에 static으로 만들었던 것을 싹 지우고 다시 만든다.
$ cd $(WORK)/target/gcc
$ rm -rf *
$ $(WORK)/gcc-??/configure --prefix=/opt/host/mipsel-linux
--target=mipsel-linux --enable-languages=c,c++
$ make
$ sudo make install

자 이제 모든 것이 끝났다.

그러나 본인이 여러분에게 권하는 것은 이미 만들어져 널리 쓰이는 툴을 이용하라는 겁니다.

이런짓은 반드시 꼬옥~ 해야 할때만 해야 하는 것이고 나처럼 널널한 사람만 재미로 해보는 것일 뿐입니다.

DDK가 온다면 DDK것을 그대로 이용하시면 되고 그렇지 않더라도 가장 비슷한 것을 찾아서 이용하면 됩니다. 이런 것 만들줄 몰라도 남이 만든걸 이용해서 더 멋진 것을 만든다면 그걸로도 굉장히 큰 행운이라고 생각합니다.

요청이 있으면 예제로 만든 CCK를 자료실에 올리겠습니다만..

압축해도 100메가 넘을것 같습니다만 ㅡ,ㅡ;;;;
KELP - Korea Embedded Linux Project

context switching animation(x86) - ucos

Posted 2005/02/28 12:17

...
(출처: www.kelp.or.kr)

유영창 (2001년 11월 21일 오전 11:07)
StrongARM은 RISC 형식입니다.

즉 1 클럭에 1 명령이 실행되는 구조 입니다.

Intel에서 제공되고 있는 Developer's Manual 의 4장을 보면
각 명령당 소모하는 클럭수가 나옵니다.

특별한 명령을 제외하면 대부분 1클럭만을 소모합니다.

한가지 조심하여야 할것은

캐쉬가 있을때와
캐쉬가 없을때인데

캐쉬가 있을때는 예측이 조금 힘들고요..

캐쉬가 없을때에는 메모리에서 데이타를 패치하는 것은
메모리의 설정상황에 따라 달라집니다.


궁금이 wrote..
: strongarm의 명령 한라인 수행하는데 걸리는 클럭과 계산 하는 방법을 알고 싶습니다 ..  
[ 이글에 답장 | 본문에 답장 ]  

유영창 (2001년 11월 21일 오전 11:51)
정말 제가 잘 모르는 것에 대해서
끝까지 물어 보시는 군요...

일단 정확하지는 않지만 줏어 들은 이야기와 제 상상을 말씀드리지요

님이 원하시는 것은 아마도 타이밍에 대한 것일 겁니다.

하지만 이 것에 대한 명확한 답은 제가 말씀 드리기 힘들겠네요..
대신 StrongARM에서 내부적으로 처리하는 것에 대한
제가 알고 있는 것을 말씀드리겠읍니다.

일단 하나의 명령을 수행할때의 과정을 살펴 봅시다.

1. 명령을 메모리에서 인스트럭션 레지스터에 로드한다.
2. 해당 명령을 수행한다.
3. 만약 해당 명령이 데이타의 읽기나 쓰기가 필요하다면
메모리에 접근한다.

일단 위의 과정중 2 번이 1명령 수행 시간이 됩니다.
RISC 에서는 1 Clock 만 사용된다는 것입니다.

1 Clock은 PLL 셋팅에 다르죠 외부 크리스탈을 3.686에 설정했고 StrongARM1110이라면
200M 이상이 나옵니다.
이 1 클럭이 한 명령을 수행합니다.

이렇게만 따진다면 200회의 수행이 가능하다는 것입니다.
그런데 실제 1번과 3번 행위가 있죠?
그렇다면 이야기는 달라집니다.

ROM의 억세스 타이밍과 RAM 억세스 타이밍이 매우 다른데
보통 짧게는 4클럭에서 많게는 10클럭까지 먹을수 있읍니다.

그럼 실제 수행 시간은 더욱 느려지겠죠...

그래서 명령 캐쉬를 쓰는 것이고 파이프라인 방식을 사용합니다.
이에 대한 자세한 것은 저도 매뉴얼을 좀더 봐야 하겠네요...

여기까지가 제가 알고 있는 내용입니다.

일단 매뉴얼에는 한번 자세하게 찾아본후 다시 말씀드리지요...

질문에는 무조건 항복합니다.  
글쓴이 : 유영창 (2001년 11월 23일 오후 12:23) 읽은수: 802 [ 임베디드강좌/유영창  ]  
통신 프로그램을 작성하다보면
생기는 오류중에서

struct의 크기 때문에 고생하게 된다.

왜?

struct A
{
char a;
};

이것의 크기는 4로 잡히기 때문이다.

크기를 1로 잡으려면

이렇게 하면 된다.

#pragma pack(1)
struct A
{
char a;
};
#pragma pack()

하지만 arm-linux-gcc에서는 이것이 먹지 않는다.

어떻게 해야 할까?

이렇게 하면 된다.

struct A
{
char a;
} __attribute__ ((packed));


PS : 이지보드에 bootp를 구현하다가.....

가상 메모리

Posted 2004/06/07 00:17
www.ahnz.netMMU

커널 디버깅 기능 활성화과정

Posted 2004/06/06 01:15
커널 디버깅 기능 활성화과정  (출처: http://www.kelp.or.kr 유영창)

커널 디버깅 기능 활성화과정
===========================

1. 개요

   이 문서는 커널의 압축 해제 루틴 이후부터의 커널 패치를
   하는 과정에 대하여 시간순으로 기술한 문서이다.
  
   이 문서에서는 커널의 디버깅 옵션을 활성화 하는
   방법에 대하여 기술한 문서이다.
  
2. 문서

   참조 문서 없음
      
3. 커널 디버깅 옵션

   디버그 포트에 대한  처리이다.
  
   커널 디버깅시에 시리얼로 데이타를 표출하면서 보는 것이 가장 편리하므로
   이 작업에 대한 처리를 우선적으로 해야 할것으로 보인다.
  
   우선 커널 컴파일 옵션에서 다음을 활성화 한다.
  
    Kernel hacking  --->
       [*] Kernel debugging
           [*]   Kernel low-level debugging functions
          
     이렇게 하면 두가지 옵션 변수가 활성화 된다.      
  
     CONFIG_DEBUG_KERNEL  
     CONFIG_DEBUG_LL
    
    이중 CONFIG_DEBUG_LL 이 초기에 커널을 디버깅 하기위한  좋은 툴인 것이다.
    
    이 옵션 변수를 참조하는 것을 살펴보면
    
    arch/arm/kernel/Makefile:obj-$(CONFIG_DEBUG_LL)  += debug-$(PROCESSOR).o
    arch/arm/kernel/head-armv.S:#ifdef CONFIG_DEBUG_LL

    이렇게 존재한다.
    
    우선 첫번째 문장에 의해서 참조되는 것은
    
    arch/arm/kernel/debug-armv.S 이다.
    
    두번째로 참조 되는 것은
    
    arch/arm/kernel/head-armv.S 안에서 CONFIG_DEBUG_LL 에 의해서 활성화 되는 구문이다.
    
    이 옵션만 활성화한 상태에서 커널을 컴파일 하면 다음과 같은 에러가 발생한다.

    
=================================================================================================
===    
        debug-armv.S:389: #error Unknown architecture
        make[1]: *** [debug-armv.o] Error 1
        make[1]: Leaving directory `/var/data/project/ez-m28/kernel_patch/linux-m28-
pre/arch/arm/kernel'
        make: *** [_dir_arch/arm/kernel] Error 2
    
=================================================================================================
===    

    이것은 해당 아키텍쳐에 관련된 디버깅 루틴이 없다는 표시이기도 하다.
    즉 S3C2410의 커널은 이 부분에 대한 처리를 하지 않았다.
    
    우리는 작업의 편리성과 가난함(? - 고가의 에뮬레이터가 없다)으로 인하여
    이 부분을 만들어 가는 것이 편리하다.
    
    물론 다른 아케텍쳐에서 한 루틴을 훔쳐 보고 비슷하게 만들면 별문제가 없다.
    손보아야 할 화일은 다음과 같다.
    
    arch/arm/kernel/debug-armv.S
    
    우리가 추가해야 할 위치는 388 라인쯤에 발견할수 있는
    
    #else
    #error Unknown architecture
    #endif

    구문 바로 전에 만들어야 한다.
    
  
     CONFIG_ARCH_S3C2410    
        
    이 디버깅 루틴은 매크로를 선언하게 되어 있는데
    
    다음과 같은 매크로들은 만들어 주어야 한다.
    
    1) .macro        addruart,rx
        -> rx 로 넘어온 레지스터에 UART 주소를 넘긴다.
        
    2) .macro        senduart,rd,rx  
        -> rd 로 넘어온 데이타를 rx 레지스터에 써 넣는다.
           즉 시리얼 포트에 데이타를 써 넣는다.
    
    3) .macro        waituart,rd,rx
        -> UART에 데이타를 쓸수 있으때 까지 기다린다.
    
    4) .macro        busyuart,rd,rx
        -> UART에 써 넣어진 데이타가 처리 된것을 기다린다.
    
    다음과 같이 만들었다.
    
    
=================================================================================================
===    
        #elif defined(CONFIG_ARCH_S3C2410)
        
                        .macro        addruart,rx
                        mrc        p15, 0, rx, c1, c0
                        tst        rx, #1                        @ MMU enabled?
                        moveq        rx, #0x10000000        @ physical base address
                        movne        rx, #0xD0000000        @ virtual address
                        add        rx, rx, #0x00170000        @ UART0
                        .endm
        
                        .macro        senduart,rd,rx
                        str        rd, [rx, #0x20]        @ UTXH0
                        .endm
        
                        .macro        waituart,rd,rx
        1001:                ldr        rd, [rx, #18]                @
                        tst        rd, #1 << 9                @ UARTFLGUTXFF - 1 when full
                        bne        1001b
                        .endm
        
                        .macro        busyuart,rd,rx
                        .endm
    
=================================================================================================
===    

    참고) 디버깅 할때 체크 포인트 찍는 LED루틴은 다음과 같이 사용했다.            
            
                        mov     r1,     #0x10000000   @C
                        add     r1, r1, #0x00100000   @C
                        add     r1, r1, #0x0000001c   @C
                        mov     r0, #0x7              @C
        dled0:          str     r0,[r1]               @C
                        b       dled0                 @C


    위 LED 보다 아무래도 디버거의 루틴을 이용하는 것이 좋은데
    일단
    
    arch/arm/kernel/head-armv.S 화일에서
    
                    mov        r0, #F_BIT | I_BIT | MODE_SVC        @ make sure svc mode
                msr        cpsr_c, r0                        @ and all irqs disabled
                bl        __lookup_processor_type

                다음에 아래 루틴을 추가해 보았다.
                    
                    moveq        r0, #'X'                        @C
                beq        __error                         @C
            
    시리얼로 이렇게 나온다.
    
        Copy Kernel Image .....
        Copy Ramdisk Image .....
        Starting kernel ...
        Uncompressing Linux............................................. done, booting t
        he kernel.
        
        Error: X    

    큭큭큭 일단 뭔가 나온다.
    
    FIFO 처리가 제대로 될지는 모르겠지만 일단 12 문자까지는 무조건 나올 것이다.
    
    커널 디버깅 기능이 제대로 활성화 된것을 확인 한 것이다.      
    
    커밋한 CVS :  include/asm-arm/arch-s3c2410/s3c2410.h
                       -> UART 선언에 VA_IO_BASE1로 선언되어 있어서 VA_IO_BASE0으로 바꿈
                  arch/arm/kernel/debug-armv.S



2003-07-26 18:23:22

유영창 (http://kelp.or.kr)  
압축 해제 이후 커널 패치 과정(1).txt  

압축 해제 이후 커널 패치 과정
=============================

1. 개요

   이 문서는 커널의 압축 해제 루틴 이후부터의 커널 패치를
   하는 과정에 대하여 시간순으로 기술한 문서이다.
  
2. 문서

   이 문서를 작성하기 위하여 권수호씨가 작성한 문서를 참고 하였다.
      http://kelp.or.kr/korweblog/upload/12/20010725160834/045-LinuxKernel-
chapter38_SA1100_Booting_head_S.doc
      
3. 패치 과정

   head.S 의 함수를 추적하기 위한 방법은
  
   돈이 있다면 가장 좋은 것은 에뮬레이터를 이용하는 것이다.
   하지만 돈이 없다면...
  
   결국 몸으로 때우는 수밖에 없다...
  
   여기서는 몸으로 때우는 방법을 검토해 보자.
  
   보통 루틴 추적 방법은 확인하고자 하는 위치에 도달했는가 하는 것과
   도달 했다면 검사하고자 하는 값을 보아야 하는데..
  
   일단 위치잡는 최악의 방법은 LED를 점멸 시키는 방버이다.
   하지만 이것의 문제는 값을 보기가 힘들다는 점
  
   두번째는 시리얼을 이용하는 방법이다.
  
   일단 부팅 메세지가 나오므로
   우리는 시리얼을 이용하는 방법을 찾아 보자.
  
   이 시리얼 메세지를 보는 방법은
   head.S 를 추적할 때 쓰는 나의 방법이다.
  
   물론 이것은 원칙적으로 arch_decomp_setup() 함수가 호출된 이후에
   동작되지만 EZ-M28 에서는 특별히 하는일이 없으므로 그냥 쓴다.
  
   그리고 어셈블러가 조금 약한 나는 그냥
  
   misc.에 출력 함수를 쓰고
  
   이를 어셈블러에서 호출하는 방식을 쓴다.
  
   여기서 알아야 할것은
  
   arm 에서 한두개의 파라메터를 전달하고자 한다면
  
   r0,r1,r2 이 정도만 사용하면 된다.
  
   우리는 이에 대한 루틴을 만들어 보자..
  
   우선 misc.c 에 다음 함수를 추가 한다.
   이 함수는 나중에 지우는 것이 좋다. (^^)
  
   void CheckMsg2( int a )
   {
        char buff[2];
        
        a = a & 0xF;
        
        if( a >= 10 ) buff[0] = a - 10 + 'A' ;
        else          buff[0] = a + '0' ;
        
        buff[1] = 0;
        
        puts( buff  );
   }
   void CheckMsg( int a )
   {
        
        puts("Check1[");
        
        CheckMsg2( a >> 28 );
        CheckMsg2( a >> 24 );
        CheckMsg2( a >> 20 );
        CheckMsg2( a >> 16 );
        CheckMsg2( a >> 12 );
        CheckMsg2( a >>  8 );
        CheckMsg2( a >>  4 );
        CheckMsg2( a       );
                
        puts("]n");
        
        while(1); // 무한 루프를 돈다.
        
   }

   어셈블러에서 호출할대는
  
   bl CheckMsg
  
   라고 하면 되고
   r0 에 파라메터 a에 해당하는 값을 넣으면 된다.

   체크 포인트를 찍는 방법중에 또 다른 하나는 강제 리셋이다.

   어셈블러에서 다음 코드가 강제로 리셋 시키는 것이다.
    
                ldr     r1, =0x10000010
                mov     r0, #1
                str     r0,[r1]
                
   그리고 가장 일반적인 방법은 붙어 있는 led에 빛나게 하는 것이다.
   아래 코드는 EZ-M28 일 경우이다.
  
                ldr     r1, =0x1010001c
                ldr     r0, =0x7          <== 키고 싶은 LED 상태
dled0:          str     r0,[r1]
                b       dled0

  
   커널의 압축 해제를 수행하는 함수는
  
     arch/arm/boot/compressed/head.S 화일의

   bl        decompress_kernel 를 호출하는 부분이다.
  
   이렇게 호출하는 부분은 두가지가 있는데
  
   EZ-M28에서 호출되는 위치는
  
   243 라인이다.
  

   압축이 해제된 이후에
  
   커널의 압축이 풀린 후 풀린 압축 데이타와 실제 커널의 위치가 다르므로
   이를 맞추는 작업을 수행한다.
  
   현재 수행되는 코드를 압축된 뒤로  옳긴 후 커널을 재배치 하게 된다.
  
   아래의 루틴이 그것이다. ^^  
   ==[247 - 269]=====================================================================  
        /*
         * r0     = decompressed kernel length
         * r1-r3  = unused
         * r4     = kernel execution address
         * r5     = decompressed kernel start
         * r6     = processor ID
         * r7     = architecture ID
         * r8-r14 = unused
         */
        
                        add        r1, r5, r0                @ end of decompressed kernel
                        adr        r2, reloc_start
                        ldr        r3, LC1
                        add        r3, r2, r3
        1:                ldmia        r2!, {r8 - r13}                @ copy relocation code
                        stmia        r1!, {r8 - r13}
                        ldmia        r2!, {r8 - r13}
                        stmia        r1!, {r8 - r13}
                        cmp        r2, r3
                        blo        1b
        
                        bl        cache_clean_flush
                        add        pc, r5, r0                @ call relocation code
   ==================================================================================  

   이후 제어는 reloc_start 가 수행된다.
  
   현재 점검 결과 해당 루틴으로 즉 reloc_start 로 진행되지 않는 것으로 보인다.
  
   하나씩 점검 해봐야 할듯
  
                   add        r1, r5, r0                @ end of decompressed kernel
                mov     r0, r1                                       
                
    다음 문장을 수행한 후에
    
       add        r1, r5, r0                @ end of decompressed kernel            

    r1에 담겨진 주소는  0x0820A894 이다.
    
    즉 커널이미지 압축이 풀린 이미지의 끝 위치가 0820A894 의미이다.
    
    다음 문장을 수행한 후에  
    
       adr        r2, reloc_start
       ldr        r3, LC1
       add        r3, r2, r3
    
    r3에 담겨진 주소는 0x0820A894 이다.
    
    이건 좀 이상하다. ?
    
    왜 이런 현상이 생길까?
    
    좀더 조사해 보니
    
    r2 는 0x08008260 이다.  
    r3 는   000001B4 이다.
            
    더하면 0x08008414 이다.    
    
    어? 내가 뭘 잘못했나?
    
    다시 찍어 보니 0x08008414 가 나왔다.
    
    정리해 보면 r1 0x0820A894 은 압축이 풀린 커널 이미지의 끝 위치
                  
                    
                r2 0x08008260 는 재 배치 코드의 시작 위치 즉 reloc_start
                    
                    
                r3 0x08008414 는 재 배치 코드의 끝 위치 즉   reloc_end 값이 들어 가 있다.
                    
    
    다음 문장은    
    
        1:                ldmia        r2!, {r8 - r13}                @ copy relocation code
                        stmia        r1!, {r8 - r13}
                        ldmia        r2!, {r8 - r13}
                        stmia        r1!, {r8 - r13}
                        cmp        r2, r3
                        blo        1b
    
    재 배치 코드의 영역을 압축이 풀린 커널 이미지의 끝 쪽에 이동시키는 것이다.
    
    재 배치 코드는 압축이 풀린 커널 이미지를 실제로 위치할 곳으로 이동시켜주는
    코드 이다.
    
    이와 같이 뒤쪽에 위치해서 수행되어야  이미지 복사중에도 문제가 없기 때문이다.
    
    일단 이 루틴 까지 진행이 제대로 되는지 검증하기로 하자..
    
    그런데 스택은 어떻게 되어 있을 까 ?
    
    그래서 스택 포인터 값을 찍어 보기로 했다.
    
    압축 풀기 직전에 스택 위치는  0x080ABF94 이다.

   위 문자을 수행하기 이전의 스택 포인터는 080ABF98 이다.
  
   별로 변한것이 없다.
  
   그런 왜 위 문장을 수행한 이후에 처리가 되지 않는 것일까?
  
   위 문장 바로 위에서의 PC값은 얼마일까?
  
    PC => 0x080080FC 이다.
    
    정리
    
    r1 : 0x0820A894 커널 이미지 끝
    r2 : 0x08008260 reloc_start
    r3 : 0x08008414 reloc_end
    sp : 0x080ABF98    
    pc : 0x080080FC
    
    위 루틴이 하는 것은
    
        0x08008260 에서 0x08008414 의 영역을
        0x0820A894 로 옮기는 것이다.
        
     그런데 이것을 수행한 이후에는 시리얼 출력이 제대로
     수행되지 않는다?
    
     이유가 무엇일까?
    
   실제 시스템 패닉이 나는 부분은
  
     1:                ldmia        r2!, {r8 - r13}                @ copy relocation code
                stmia        r1!, {r8 - r13}
                ldmia        r2!, {r8 - r13}
                stmia        r1!, {r8 - r13}

    이다..
    
    이 부분을 다음과 같이 수정하였다.
    
    1:                ldmia        r2!, {r8 - r11}                @ copy relocation code
                stmia        r1!, {r8 - r11}
                ldmia        r2!, {r8 - r11}                @ copy relocation code
                stmia        r1!, {r8 - r11}
                ldmia        r2!, {r8 - r11}                @ copy relocation code
                stmia        r1!, {r8 - r11}

    정상적으로 동작했다.
    
    현재 추정은 SDRAM 과 메모리 컨트롤러의 버스트 모드의 문제로
    보인다.
    
    정확한 이유는 모르겠다. ㅜㅜ
    
    다음은
    
    bl        cache_clean_flush 인데
    
    이것은 캐쉬 데이타를 없애주는 역활을 한다.
    
    이것은 조금 더 분석해야 할듯...
    
    일단 재배치 위치에서 동작하여야 하는데 다음 문장
    
       add        pc, r5, r0                @ call relocation code
    
    으로 인해서
    
    
    옮겨진 reloc_start 의 위치로 점프한다.
    
   ==================================================================================  
        reloc_start:        add        r8, r5, r0
                        debug_reloc_start
                        mov        r1, r4
        
        1:
                        .rept        4
                        ldmia        r5!, {r0, r2, r3, r9 - r13}        @ relocate kernel
                        stmia        r1!, {r0, r2, r3, r9 - r13}
                        .endr
        
                        cmp        r5, r8
                        blo        1b
                        debug_reloc_end
        
        call_kernel:        bl        cache_clean_flush
                        bl        cache_off
                        mov        r0, #0
                        mov        r1, r7                        @ restore architecture number
                        mov        pc, r4                        @ call kernel
   ==================================================================================  

   이 루틴은 풀린 커널 이미지를 실제의 위치로 배 배치한다.
  
   재 배치 주소는 r4 에 가지고 있고 배치도리 커널 이미지의 위치는 r5 에 가지고 있게 된다.
  
   그래서 복사하게 된다.
  
   그리고 r4로 점프한다.
  
   이 루틴까지는 정상적으로 동작한다.
  
   여기서 잠깐 검토해 보아야 할 것이
  
   cache_clean_flush 함수이다.

   이 함수는 다음과 같은 형태를 띄고 있다.
      
   cache_clean_flush:
                mov        r3, #16
                b        call_cache_fn

   call_cache_fn 은 부른다.
  
   이 루틴은 다음과 같은 형태를 띄고 있다.
  
        call_cache_fn:        adr        r12, proc_types
                        mrc        p15, 0, r6, c0, c0        @ get processor ID
        1:                ldr        r1, [r12, #0]                @ get value
                        ldr        r2, [r12, #4]                @ get mask
                        eor        r1, r1, r6                @ (real ^ match)
                        tst        r1, r2                        @       & mask
                        addeq        pc, r12, r3                @ call cache function
                        add        r12, r12, #4*5
                        b        1b

   이 루틴은
  
   mrc        p15, 0, r6, c0, c0        @ get processor ID
  
   을 통하여 r6 레지스터에 프로세서 ID를 가져 온다.
  
   이후 proc_types 에 등록된 프로세스 타입을 검색해서
   일치하는 프로세스 타입을 만나면 r3 에 등록된 오프셋에
   해당하는 루틴을 수행하게 된다.
  
   위 루틴을 통해서 ARM920T 의 armv4_cache_flush을 수행하게 도니다.
  
                   .word        0x41129200                @ ARM920T
                .word        0xff00fff0
                b        __armv4_cache_on
                b        __armv4_cache_off
                b        __armv4_cache_flush

   일단 r6에 어떤값이 생기는지 보자
  
    정확하게 0x41129200  이 읽힌다.
    
   이제 마지막으로 r7 에 담겨져 있는 architecture ID 를
   조사해 보자
  
   체크해 보니 0x0000012F 즉 303 이 나오고 있다.
   당연하다 부트로더에서 303이라는 값으로 설정하고 있기 때문이다.

   S3C2410 은 어떻게 되어 있을까?
        
   아키텍쳐 ID는 다음의 위치에 기록되어 있다.
  
   arch/arm/tools/mach-types 란 파일이다.
  
   s3c2410                        ARCH_S3C2410                S3C2410                
        182
  
   이다.
  
   이것은 CPU에 따른 하드웨어의 특성을 커널에 반영하기 위한
   자료 구조에 사용되는 매크로 화일의 번호값이기도 하다.
  
   원래 이런식으로 하면 조금 곤란하다.
   보드별로 따로 받아야 한다.
  
   하지만 진행을 위해서 이 부분의 수정은 하지 않기로 하였다.
  
   최종적인 EZ-M28을 위해서 따로 만들어야 할 것이다.  
  
   이 값은 현재 arch/arm/boot/compressed/head-s3c2410.S
   에서 선언해 주고 있는데
  
   우리는 이전에 무시하게 했었다.
  
   하지만 이부분만 살리기로 한다.
  
   다음과 같은 부분이다.
  
        #if defined(CONFIG_ARCH_S3C2410)
                mov        r7, #MACH_TYPE_S3C2410
                mov        r8, #0
        #endif
  
   이것은
  
   #if 0  // 무시시작
  
   라는 명령문으로 만든 바로 위에 복사해 넣는다.
  
   나중에는 제거할 것이다.
   즉 부트로더에서 직접 주게 할것이다.
  
   다시 r7 에 담겨져 있는 architecture ID 를 조사해 보면
  
     0x000000B6 이 나온다.
    
  즉 arch/arm/tools/mach-types 에 적혀 있던 대로 182 란 값이
  나온다.
  
  이제 정말 실제 커널로 점프했는지를 조사해야 한다.
  
  그래야 압축이 정확하게 풀린 것이니까...
  
  클클
  
  진짜(?) 커널의 시작 위치는
  
  arch/arm/kernel/head-armv.S 이다.
  
  그리고 가장 처음 시작되는 위치는 다음이다.
  
   ==================================================================================  
        /*
         *  Kernel startup entry point.
         *
         * The rules are:
         *  r0      - should be 0
         *  r1      - unique architecture number
         *  MMU     - off
         *  I-cache - on or off
         *  D-cache - off
         *
         * See linux/arch/arm/tools/mach-types for the complete list of numbers
         * for r1.
         */
                        .section ".text.init",#alloc,#execinstr
                        .type        stext, #function
        ENTRY(stext)
                mov        r12, r0

   ==================================================================================  
    
   아직까지 MMU가 활성화 되어 있지 않으므로 당분간 위에서 사용한
   디버깅 방법을 사용할수 있다.
  
   물론 다른 디버깅 방법도 강구해야 하지만
  
   일단 LED로 이 지점에 도착했나를 체크해 보자
  
   여기서 도착 유무는 led로 해 보기로 했다.
  
   다음과 같은 루틴을
  
   ==================================================================================  
                        mov     r1,   #0x10000000    @C  
                        add     r1, r1, #0x100000    @C
                        add     r1, r1,     #0x1C    @C
                        mov     r0, #0x7             @C
        dled0:          str     r0,[r1]              @C
                        b       dled0                @C
   ==================================================================================  

    mov        r12, r0 다음에 삽입하였다.
    
    테스트 결과 통과 !!! 큭큭... 뭔가 되어 가는 것 같다.
    
    자 이제
    
    디버깅을 위해서 제공된 커널 디버깅 옵션을 활성화 하는 것에 대하여
    연구해 보자.
    
    클클...

    커밋한 CVS :  arch/arm/boot/compressed/head.S
                  arch/arm/boot/compressed/head-s3c2410.S



2003-07-26 18:20:43

'Research > SystemProg' 카테고리의 다른 글

가상 메모리  (0) 2004/06/07
커널 디버깅 기능 활성화과정  (0) 2004/06/06
압축 해제 이후 커널 패치 과정  (0) 2004/06/06
head-armv.S 추적 및 패치 과정  (0) 2004/06/06
Boot from Flash Memory  (0) 2004/06/03
[Q] relocation of bss and data  (0) 2003/12/10

head-armv.S 추적 및 패치 과정

Posted 2004/06/06 01:02
유영창 (http://kelp.or.kr)  
head-armv.S 추적 및 패치 과정  

head-armv.S 추적 및 패치
===========================

1. 개요

   이 문서는 EZ-M28 에 동작시키기 위한 커널 시작점인 head-armv.S 를 추적하고 수정하는
   과정에 대하여 시간 순으로 기술한 문서이다.
  
  
2. 문서

   권수호씨가 쓴 head-armv.S 에 관련된 글 참조
   ( kelp.or.kr 에 가면 있다. )
      
3. head-armv.S 추적 및 패치

   이제 디버그 포트는 활성화 시켰으므로 중간 중간 진행된 내용의 추적은 가능하다.
  
   문제는 이 head-armv.S 의 구조가 매우 복잡하다는 것에 있다.
   거의 데이타 테이블들이 이리 묶이고 저리 묶여 있다.
  
   (개인적으로 권수호씨가 대단하다고 생각한다. )
  
   하나씩 추적해 가면서 문제점을 돌파하기로 하자. (씩씩하게)
  

   다음 루틴은 프로세서 타입을 찾고
   아키텍쳐 타입을 찾고
   가장 최초의 MMU 페이지 테이블을 만드는 루틴이다.
      
   =============================================================================    
                   mov        r0, #F_BIT | I_BIT | MODE_SVC        @ make sure svc mode
                msr        cpsr_c, r0                        @ and all irqs disabled
                bl        __lookup_processor_type
                teq        r10, #0                                @ invalid
processor?
                moveq        r0, #'p'                        @ yes, error 'p'
                beq        __error
                bl        __lookup_architecture_type
                teq        r7, #0                                @ invalid
architecture?
                moveq        r0, #'a'                        @ yes, error 'a'
                beq        __error
                bl        __create_page_tables
                adr        lr, __ret                        @ return address
                add        pc, r10, #12                        @ initialise
processor
                                                        @ (return control
reg)
   =============================================================================    

    bl        __lookup_processor_type
    bl        __lookup_architecture_type
    
    이 루틴을 통과하지 못하고 에러가 발생하면 우리는 시리얼 디버깅 기능을 활성화
    시켰으므로 'p' 문자나 'a' 문자가 발생할 것이다.
    
    실제 수행 결과 이런 문자는 발생하지 않았다.

    테이블까지 정상적으로 만들어 지면

    다음 문장에 의해서
        
                adr        lr, __ret                        @ return address

    다음 문장의 초기화 과정이
    
                add        pc, r10, #12                        @ initialise
processor
                                                        @ (return control
reg)
    
    수행된 이후에               
    
    __ret 로 점프한다.

    여기까지는 정상적으로 온다.
    
   =============================================================================    
    __ret:                ldr        lr, __switch_data
                mcr        p15, 0, r0, c1, c0
                mov        r0, r0
                mov        r0, r0
                mov        r0, r0
                mov        pc, lr
   =============================================================================    
   이 문장은 lr 에 __mmap_switched 의 주소를 적재하므로서
  
   mov        pc, lr 이 수행된 이후에 __mmap_switched로 이동한다.
  
   확인해 보니 __mmap_switched 까지 이동한다.
  
   이 이후 동작 부터가 MMU가 동작되어 수행되는 것이다.
  
   =============================================================================    
        __mmap_switched:
                        
                        adr        r3, __switch_data + 4
                        ldmia        r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat
                                                                @ sp = stack
pointer
        
                        mov        fp, #0                                @ Clear BSS (and
zero fp)
        1:                cmp        r4, r5
                        strcc        fp, [r4],#4
                        bcc        1b
        
                        str        r9, [r6]                        @ Save processor ID
                        str        r1, [r7]                        @ Save machine type
        #ifdef CONFIG_ALIGNMENT_TRAP
                        orr        r0, r0, #2                        @ ...........A.
        #endif
                        bic        r2, r0, #2                        @ Clear 'A' bit
                        stmia        r8, {r0, r2}                        @ Save control
register values
                        b        SYMBOL_NAME(start_kernel)
   =============================================================================    
  
   이 루틴 이후에는 start_kernel로 이동하게 된다.
  
   이 루틴은
  
   init/main.c 에 정의되어 있다.
  
   이 루틴까지 도착하면 일단 기초적인 프로세스 셋업은 끝 난것이다.
  
   일단 이 부분까지는 정상적으로 도착하는 것을 확인했다.
  
   여기서 확인 방법은
  
   init/main.c 의 start_kernel 에서 디버그 에러 메세지 호출 루틴
   __error 함수를 호출하게 변경한 후에 __error 의 데이타가
   표출되는 가를 확인하였다.
  
   그런데 어셈블러 루틴은 C에서 그냥 참조가 되지 않으므로
  
   .globl __error
   __error:

   와 같이   .globl __error 를 앞줄에 추가하였다.
  
   그리고 호출은 다음과 같이 C 루틴에서 호출하면 된다.
  
   __error( 'S' );
  
   실제 표출 메세지는 이렇게 나온다.
  
   =======================================================================================
        Copy Kernel Image .....
        Copy Ramdisk Image .....
        Starting kernel ...
        Uncompressing Linux............................................. done, booting t
        he kernel.
        
        Error: S
   =======================================================================================
  
   이 메세지를 확인함으로써 일단 start_kernel커널까지 진입하는 것은 확인하였다.
  
  
  
   그런데 위에서 각각의 루틴이 하는 것은 무엇일까?
  
   __lookup_processor_type 이 루틴은
  
   실제 MPU의 프로세스 ID를 읽어서 이와 일치하는 자료 구조체의 주소를 얻어 온다.
  
   그렇다면 이 자료 구조체은 어디에 있을까?
  
   이 자료 구조체는 여기저기 헤더화일의 매크로로 여기저기 얽혀 있는데
  
   기본적으로 920T 의 자료구조와 자료구조에 선언될 함수나 데이타는
  
      arch/arm/mm/proc-arm920.S
  
   이다.
  
   이 화일이 링크되는 방법은
  
      arch/arm/mm/Makefile 의
      
      p-$(CONFIG_CPU_ARM920T)        += proc-arm920.o
      
   에 의해서 링크된다.
  
   이 부분은 호출되는가만 체크하고 호출되면 검증 끝으로 보아도
   무방하다.
  
   즉 ARM920 계통이면 공통이기 때문이다.
  
   S3C2410 도 ARM920T 이고 S3C2800 도 ARM920T 이기 때문이다.
  
   __lookup_architecture_type 은 주어진 아키텍쳐 ID를 이용하여
   보드에 맞는 정보의 주소를 얻어오는데
   실제로 얻어오는 주소는
  
   arch/arm/mach-s3c2410/arch.c 화일안에
  
   =======================================================================================
   MACHINE_START(S3C2410, "SAMSUNG ELECTRONICS Co., Ltd")
        MAINTAINER("SW.LEE (hitchcar at sec.samsung.com)")
        BOOT_MEM(PA_SDRAM_BASE,PA_UART_BASE,VA_UART_BASE)
        BOOT_PARAMS(PA_SDRAM_BASE+0x100)
        FIXUP(fixup_s3c2410)
        MAPIO(s3c2410_map_io)
        INITIRQ(s3c2410_init_irq)
   MACHINE_END
   =======================================================================================
  
   라고 정의한 구조체의 주소를 얻어오게 된다.
  
   그런데 이해가 되지 않는 것이

        BOOT_MEM(PA_SDRAM_BASE,PA_UART_BASE,VA_UART_BASE)
        
   이 부분이다.
   원래 이 부분은
  
   BOOT_MEM(물리적 램 주소, 물리적 I/O 주소, 가상 I/O 주소)
  
   가 되어야 한다.
  
   그러면 S3C2410은 UART 가 I/O의 가장 선두인가?
  
   그것참 이상타...
  
   매뉴얼을 보면 아닌데...
  
   그것참...
  
   왜 이렇게 되어 있지?
  
   흠....
   고민 고민 ...
  
   그냥 일단 고쳐 보자...
  
   아래 루틴을
  
      BOOT_MEM(PA_SDRAM_BASE,PA_UART_BASE,VA_UART_BASE)
      BOOT_PARAMS(PA_SDRAM_BASE+0x100)

   다음과 같이 수정하였다.
      
      BOOT_MEM(PA_SDRAM_BASE,0x10000000,0xD0000000)
      
   우리는 이 부분도 수정하여야 한다. 물론 당장은 아니다.
  
   ( 작업자 이름부터 바꾸어 버려야지... 클클 ^^! )
  
   __create_page_tables 함수는 MMU 동작에 필요한 최소한의 수행을 시작한다.
  
   마지막으로
  
                   add        pc, r10, #12                        @ initialise
processor
                                                        @ (return control
reg)

   문장에 의해서 프로세서를 초기화 한다.
   물론 r10 의 값은 프로세서 자료 구조체의 시작 주소가 있다.
  
   호출되는 것은 구조체 주소 + 12 바이트 위치의 루틴이다
  
   결론적으로 arch/arm/mm/proc-arm920.S 에서  __arm920_setup 이 호출된다.
  
   이제 본격적인 start_kernel 을 추적해 보자.
  

   CVS 커밋 화일 : arch/arm/mach-s3c2410/arch.c



2003-07-26 18:27:13

'Research > SystemProg' 카테고리의 다른 글

커널 디버깅 기능 활성화과정  (0) 2004/06/06
압축 해제 이후 커널 패치 과정  (0) 2004/06/06
head-armv.S 추적 및 패치 과정  (0) 2004/06/06
Boot from Flash Memory  (0) 2004/06/03
[Q] relocation of bss and data  (0) 2003/12/10
Glabl변수의 초기화 및 영역  (0) 2003/12/01

Boot from Flash Memory

Posted 2004/06/03 00:53
http://www.denx.de/twiki/publish/DULG/LinuxInFlash.html

7.5.  Boot from Flash Memory



The previous section described how to load the Linux kernel image
over ethernet using TFTP. This is especially well suited for your
development and test environment, when the kernel image is still
undergoing frequent changes, for instance because you are modifying
kernel code or configuration.


Later in your development cycle you will work on application code or
device drivers, which can be loaded dynamically as modules. If the
Linux kernel remains the same then you can save the time needed for
the TFTP download and put the kernel image into the flash memory of
your INCA-IP board.


The U-Boot command flinfo can be used to display
information about the available on-board flash on your system:



INCA-IP # fli

Bank # 1: AMD 29LV641D (64 Mbit, uniform sectors)
  Size: 8 MB in 128 Sectors
  Sector Start Addresses:
    B0000000 (RO) B0010000 (RO) B0020000      B0030000 (RO) B0040000    
    B0050000      B0060000      B0070000      B0080000      B0090000    
    B00A0000      B00B0000      B00C0000      B00D0000      B00E0000    
    B00F0000      B0100000      B0110000      B0120000      B0130000    
    B0140000      B0150000      B0160000      B0170000      B0180000    
    B0190000      B01A0000      B01B0000      B01C0000      B01D0000    
    B01E0000      B01F0000      B0200000      B0210000      B0220000    
    B0230000      B0240000      B0250000      B0260000      B0270000    
    B0280000      B0290000      B02A0000      B02B0000      B02C0000    
    B02D0000      B02E0000      B02F0000      B0300000      B0310000    
    B0320000      B0330000      B0340000      B0350000      B0360000    
    B0370000      B0380000      B0390000      B03A0000      B03B0000    
    B03C0000      B03D0000      B03E0000      B03F0000      B0400000    
    B0410000      B0420000      B0430000      B0440000      B0450000    
    B0460000      B0470000      B0480000      B0490000      B04A0000    
    B04B0000      B04C0000      B04D0000      B04E0000      B04F0000    
    B0500000      B0510000      B0520000      B0530000      B0540000    
    B0550000      B0560000      B0570000      B0580000      B0590000    
    B05A0000      B05B0000      B05C0000      B05D0000      B05E0000    
    B05F0000      B0600000      B0610000      B0620000      B0630000    
    B0640000      B0650000      B0660000      B0670000      B0680000    
    B0690000      B06A0000      B06B0000      B06C0000      B06D0000    
    B06E0000      B06F0000      B0700000      B0710000      B0720000    
    B0730000      B0740000      B0750000      B0760000      B0770000    
    B0780000      B0790000      B07A0000      B07B0000      B07C0000    
    B07D0000      B07E0000      B07F0000    

Bank # 2: AMD 29LV641D (64 Mbit, uniform sectors)
  Size: 8 MB in 128 Sectors
  Sector Start Addresses:
    B0800000      B0810000      B0820000      B0830000      B0840000    
    B0850000      B0860000      B0870000      B0880000      B0890000    
    B08A0000      B08B0000      B08C0000      B08D0000      B08E0000    
    B08F0000      B0900000      B0910000      B0920000      B0930000    
    B0940000      B0950000      B0960000      B0970000      B0980000    
    B0990000      B09A0000      B09B0000      B09C0000      B09D0000    
    B09E0000      B09F0000      B0A00000      B0A10000      B0A20000    
    B0A30000      B0A40000      B0A50000      B0A60000      B0A70000    
    B0A80000      B0A90000      B0AA0000      B0AB0000      B0AC0000    
    B0AD0000      B0AE0000      B0AF0000      B0B00000      B0B10000    
    B0B20000      B0B30000      B0B40000      B0B50000      B0B60000    
    B0B70000      B0B80000      B0B90000      B0BA0000      B0BB0000    
    B0BC0000      B0BD0000      B0BE0000      B0BF0000      B0C00000    
    B0C10000      B0C20000      B0C30000      B0C40000      B0C50000    
    B0C60000      B0C70000      B0C80000      B0C90000      B0CA0000    
    B0CB0000      B0CC0000      B0CD0000      B0CE0000      B0CF0000    
    B0D00000      B0D10000      B0D20000      B0D30000      B0D40000    
    B0D50000      B0D60000      B0D70000      B0D80000      B0D90000    
    B0DA0000      B0DB0000      B0DC0000      B0DD0000      B0DE0000    
    B0DF0000      B0E00000      B0E10000      B0E20000      B0E30000    
    B0E40000      B0E50000      B0E60000      B0E70000      B0E80000    
    B0E90000      B0EA0000      B0EB0000      B0EC0000      B0ED0000    
    B0EE0000      B0EF0000      B0F00000      B0F10000      B0F20000    
    B0F30000      B0F40000      B0F50000      B0F60000      B0F70000    
    B0F80000      B0F90000      B0FA0000      B0FB0000      B0FC0000    
    B0FD0000      B0FE0000      B0FF0000    
INCA-IP #



From this output you can see the total amount of flash memory, and
how it is divided in blocks (Erase Units or
Sectors). The RO markers
show blocks of flash memory that are write protected (by software) -
this is the area where U-Boot is stored. The remaining flash memory
is available for other use.


For instance, we can store the Linux kernel image in flash starting
at the start address of the next free flash sector. Before we can do
this we must make sure that the flash memory in that region is empty
- a Linux kernel image is typically around 600...700 kB, so to be on
the safe side we dedicate the whole area from 0xB0040000 to
0xB00FFFFF for the kernel image. Keep in mind that with
flash memory only whole erase units can be cleared.


After having deleted the target flash area, you can download
the Linux image and write it to flash.  Below is a transcript of
the complete operation with a final iminfo command to check
the newly placed Linux kernel image in the flash ram.



INCA-IP # era B0040000 B00FFFFF
Erase Flash from 0xb0040000 to 0xb00fffff
...... done
Erased 12 sectors
INCA-IP # tftp 100000 /tftpboot/INCA/uImage
TFTP from server 192.168.3.1; our IP address is 192.168.3.65
Filename '/tftpboot/INCA/uImage'.
Load address: 0x100000
Loading: #################################################################
         #################################################################
         ############
done
Bytes transferred = 726443 (b15ab hex)
INCA-IP # cp.b 100000 $(kernel_addr) $(filesize)
Copy to Flash... done
INCA-IP # iminfo $(kernel_addr)

## Checking Image at b0040000 ...
   Image Name:   MIPS Linux-2.4.20
   Created:      2003-07-25  20:13:55 UTC
   Image Type:   MIPS Linux Kernel Image (gzip compressed)
   Data Size:    726379 Bytes = 709.4 kB
   Load Address: 80002000
   Entry Point:  80196398
   Verifying Checksum ... OK
INCA-IP #



Note how the filesize variable (which gets set by
the TFTP transfer) is used to automatically adjust for the actual
image size.


Now we can boot directly from flash. All we need to do is passing the
address of the image in flash with the bootm
command; we also make the definition of the
bootargs variable permanent now:



INCA-IP # setenv bootcmd bootm B0040000
INCA-IP # setenv bootargs root=/dev/nfs rw nfsroot=$(serverip):$(rootpath) ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask):$(hostname)::off


Use printenv to verify that everything is OK before you save the
environment settings:



INCA-IP # printenv
bootdelay=5
baudrate=115200
stdin=serial
stdout=serial
stderr=serial
bootcmd=bootm B0040000
bootargs=root=/dev/nfs rw nfsroot=192.168.3.1:/opt/eldk/mips_4KC
ip=192.168.3.65:192.168.3.1:192.168.3.1:255.255.255.0:inca::off
....

INCA-IP # saveenv


To test booting from flash you can now reset the board (either by
power-cycling it, or using the U-Boot command
reset), or you can manually call the
boot command which will run the commands in the
bootcmd variable:



INCA-IP # run bootcmd

## Booting image at b0040000 ...
   Image Name:   MIPS Linux-2.4.20
   Created:      2003-07-25  20:13:55 UTC
   Image Type:   MIPS Linux Kernel Image (gzip compressed)
   Data Size:    726379 Bytes = 709.4 kB
   Load Address: 80002000
   Entry Point:  80196398
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
## Loading Ramdisk Image at b0100000 ...
   Image Name:   Simple Embedded Linux Framework
   Created:      2003-04-08   0:22:03 UTC
   Image Type:   MIPS Linux RAMDisk Image (gzip compressed)
   Data Size:    1370528 Bytes =  1.3 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ...

[Q] relocation of bss and data

Posted 2003/12/10 18:12
구글 검색:
구글 뉴스그룹 홈으로 이동하기
뉴스그룹 
뉴스그룹 고급 검색    환경설정     
 
View with frames관련별  날짜별로
전체 목록 보기 "[Q] relocation of bss and data"
  
목록안의 메시지 1
글쓴이:Kim, Jeong-Hwan (frog@lgic.co.kr)
제목:[Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-03 18:42:04 PST
This is a general question about relocation of data and bss section.

When code is linked with linker script allocating all sections including
.bss and .data located in flash area
and all the sections are copied by itself into RAM, how are the data and bss
section relocated?
In the case of text, I know, PIC can run text in different memory area from
that assigned by linker.
However, what happens to .bss and .data ?
For example, gloable variable "a" is defined and assigned its address
0xFFF00200 (flash area) by linker
and map file tells its address 0xFFF00200.
When the area in which global variable "a" is located is copied into RAM and
the location of "a" is changed to 0x00000200 (RAM area),
does the code using "a" such as "a = a+1;"operate normally?
If the address of "a" is still 0xFFF00200 after code is copied, "a = a+1"
will not operate normally becausea is located in flash and will not be
updated.
How can the address of "a" be changed to 0x00000200 ?

Kim
목록안의 메시지 2
글쓴이:Andrew S (andrewsa@com.mmot.com)
제목:Re: [Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-03 19:32:05 PST
"Kim, Jeong-Hwan" wrote:
> 
> This is a general question about relocation of data and bss section.
> 
> When code is linked with linker script allocating all sections including
> .bss and .data located in flash area
> and all the sections are copied by itself into RAM, how are the data and bss
> section relocated?
> In the case of text, I know, PIC can run text in different memory area from
> that assigned by linker.
> However, what happens to .bss and .data ?
> For example, gloable variable "a" is defined and assigned its address
> 0xFFF00200 (flash area) by linker
> and map file tells its address 0xFFF00200.
> When the area in which global variable "a" is located is copied into RAM and
> the location of "a" is changed to 0x00000200 (RAM area),
> does the code using "a" such as "a = a+1;"operate normally?
> If the address of "a" is still 0xFFF00200 after code is copied, "a = a+1"
> will not operate normally becausea is located in flash and will not be
> updated.
> How can the address of "a" be changed to 0x00000200 ?
> 
> Kim

Only initialized data needs to be copied (.data).

I believe that references to .data and .bss variables are
made relative to some register (base address). Change the
contents of the register, and you've relocated your data.

-- 
CU
Andrew S.   andrewsa@com.mmot.com   {anti-spam: invert '.m'}
목록안의 메시지 3
글쓴이:Tom Evans (tom@nospam.invalid)
제목:Re: [Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-04 02:31:17 PST
Andrew S wrote:
> 
> "Kim, Jeong-Hwan" wrote:
> >
> > This is a general question about relocation of data and bss section.
>
> Only initialized data needs to be copied (.data).
> 
> I believe that references to .data and .bss variables are
> made relative to some register (base address). Change the
> contents of the register, and you've relocated your data.

This depends on your compiler and linker, but with Metaware you have
the options of SMALL Data and BSS segments which use R2 and R13.

By default these are not used. You need to specially select that
your data segments are linked as sbss and sdata and SDA_BASE
and SDA2_BASE to make this work.

Read your linker manual. It should tell you how to do all this.

The crudest way to do this is to link your data "in the right place"
and then run an AWK script over your HEX file and change all the
lines with the address in the data area to "just after the
code segment" and then copy the data back where it belongs when
your code starts.

Tom Evans
InitialSurnameAt
tennyson.com.au
목록안의 메시지 4
글쓴이:vanbaren_gerald (vanbaren@falcon.si.com)
제목:Re: [Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-04 11:32:05 PST
Andrew S <andrewsa@com.mmot.com> writes:

>"Kim, Jeong-Hwan" wrote:
>> 
>> This is a general question about relocation of data and bss section.
>> 
>> When code is linked with linker script allocating all sections including
>> .bss and .data located in flash area
>> and all the sections are copied by itself into RAM, how are the data and bss
>> section relocated?
>> In the case of text, I know, PIC can run text in different memory area from
>> that assigned by linker.
>> However, what happens to .bss and .data ?
>> For example, gloable variable "a" is defined and assigned its address
>> 0xFFF00200 (flash area) by linker
>> and map file tells its address 0xFFF00200.
>> When the area in which global variable "a" is located is copied into RAM and
>> the location of "a" is changed to 0x00000200 (RAM area),
>> does the code using "a" such as "a = a+1;"operate normally?
>> If the address of "a" is still 0xFFF00200 after code is copied, "a = a+1"
>> will not operate normally becausea is located in flash and will not be
>> updated.
>> How can the address of "a" be changed to 0x00000200 ?
>> 
>> Kim 
>Only initialized data needs to be copied (.data). 
>I believe that references to .data and .bss variables are
>made relative to some register (base address). Change the
>contents of the register, and you've relocated your data. 
>-- 
>CU
>Andrew S.   andrewsa@com.mmot.com   {anti-spam: invert '.m'}


As Andrew pointed out, .bss is simply zeroed so, as long as your system
zeros RAM on startup, you are OK there.

The PPC has a concept of register relative addressing with the .sdata
and .sdata2 sections, but most programs spill out of those areas and you
will still have a relocation problem.  Also, some compilers don't take
advantage of those conventions.

What is typically done is to link .data at the desired (RAM) address
and then use the object tools (if you are using gnu tools, objcopy,
etc.) to move the .data section to ROM (flash).  In your startup
code, _way early_ and before using any initialized .data values
(perhaps in crt0.s), copy your flash .data image into RAM.  This requires
you to know where the .data section starts and how long it is.  I'll let
you work out these details (check out the labels etext and edata --
I believe they are useful).

Disclaimer: if you are not using the gnu toolset, everything is likely
to be different but similar.  With the gnu toolset, I've inserted just
enough errors to make sure you understand the concepts rather than using
the instructions as boilerplate :-).

gvb

--
+---------------------------------------------------------------------------+
| Jerry Van Baren / vanbaren_gerald@si.com / Grand Rapids Mi / 616-241-7973 |
|   My employer is a company.  Companies are artifacts of a legal system.   |
|________________Artifacts are incapable of having opinions.________________|
목록안의 메시지 5
글쓴이:Andrew Klossner (andrew@cesa.opbu.xerox.com)
제목:Re: [Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-04 08:40:08 PST
> When code is linked with linker script allocating all sections
> including .bss and .data located in flash area and all the sections
> are copied by itself into RAM, how are the data and bss section
> relocated?

Other contributors have addressed the case in which code must work in
either place, using PIC and small data segment registers.

If your .data and .bss are not used until after they are copied to
RAM, then you instruct the loader to resolve all references to them
using their RAM addresses.  The GNU loader I use lets me specify this
in the command file.  For example, to place the .data section in ROM
but resolve references as though it begins in RAM at address 0x1000, I
use:

 .data BLOCK(0x1000) : AT 0x1000 {
  *(.data)
 }

  -=- Andrew Klossner (andrew@cesa.opbu.xerox.com)
목록안의 메시지 6
글쓴이:Martin Usher (martinusher@earthlink.net)
제목:[Q] relocation of bss and data
 
View this article only
뉴스그룹:comp.sys.powerpc.tech
날짜:2001-04-30 19:31:07 PST
"Kim, Jeong-Hwan" <frog@lgic.co.kr> wrote in message
news:UYuy6.305$2b5.9359@news2.bora.net...
> This is a general question about relocation of data and bss section.
>
> When code is linked with linker script allocating all sections including
> .bss and .data located in flash area
> and all the sections are copied by itself into RAM, how are the data and bss
> section relocated?

There's a simple trick to this. If you look at the linker control file
syntax you'll find a way of specifying sections that are to be placed at one
address even though they are to be linked at another. In GNU's ld program
its something like.....

.data SECTION (link address): AT (where you want to put it address)

Since the linker also knows how to work variables and has built-in functions
such as ADDR and SIZEOF its possible to place the sections without having to
compute absolute addresses.

The following is a typical GNU control file for a simple ROM montior that's
starts in ROM but then copies itself to RAM after doing the basic
initializing of the processor. (You may recognize the file names as those
from the 8260 sample startup files.) The bulk of the image starts at offset
0x3000 into the ROM, the RAM image starts at 0x700000 and copied with the
image are data sections. The bss, being unitialized, is not loaded. The
startup code will do a long word copy from end_entry to stext for (edata -
stext) / 4 long words. It will then zero out the bss section by zeroing
everything from edata to ebss. (Those labels can be seen by the code -- you
just reference them like any other external symbol.)

Its worth trying to look this stuff up in the manual.

SECTIONS
    {
    s1 0xFF800000 :
        {
        config.o(.text)
        }

    s2 0xFF800100 :
        {
        vect_tbl.o(.text)
        }

    s3 0xFF803000 :
        {

문서 전부 보기... (29줄 이상)

  


©2003 Google

'Research > SystemProg' 카테고리의 다른 글

head-armv.S 추적 및 패치 과정  (0) 2004/06/06
Boot from Flash Memory  (0) 2004/06/03
[Q] relocation of bss and data  (0) 2003/12/10
Glabl변수의 초기화 및 영역  (0) 2003/12/01
커널에서 double형의 연산이 가능한가요?  (0) 2002/12/04
가상 메모리(Demand paging)  (3) 2002/12/04

Glabl변수의 초기화 및 영역

Posted 2003/12/01 00:56
Glabl변수의 초기화 및 영역 - Welcome

출처:www.ezdoum.com

version1: 
int myarray[1000]={1,2,3,4}; 
void main(int argc,char *argv[]) 
{ 
  myarray[0]=3; 
} 
 
version2: 
int myarray[1000]; 
void main(int argc,char * argv[]) 
{ 
  myarray[0]=3; 
} 
 
 실행 화일의 크기 비교 
 version 1: 17657 byte 
 version 2: 13629 byte 
 
왜 이렇게 차이가 나는 걸까요? 
두 프로그램 다 integer형의 배열이 1000개 만큼 잡히는 데요. 
고수님들의 답변 기대합니다. 
 
좋은 호기심입니다... 
  
 우선.. 이 현상을 이해 할려면,, elf 바이너리의 특성을 알아야 합니다.  
 
 여기 가시면 elf 바이너리 스팩이 있습니다. 
 http://www.ezdoum.com/stories.php?story=02/04/08/1870532 
  
 간략히 말하면  
 int myarray[1000]={1,2,3,4}와 
 int myarray[1000] 는 바이너리에서 자리 잡는 곳이 틀립니다. 
  
 int myarray[1000]={1,2,3,4}는 
 14 .data         00000fc0  08049400  08049400  00000400  2**5 
                  CONTENTS, ALLOC, LOAD, DATA 
 란 섹션에 자리를 잡게 되지요.. 즉.. 실행파일안에.. 
 Contents of section .data: 
 8049400 00000000 d0a30408 00000000 00000000  ................ 
 8049410 00000000 00000000 00000000 00000000  ................ 
 8049420 01000000 02000000 03000000 04000000  ................ 
 8049430 00000000 00000000 00000000 00000000  ................ 
 8049440 00000000 00000000 00000000 00000000  ................ 
 8049450 00000000 00000000 00000000 00000000  ................ 
 8049460 00000000 00000000 00000000 00000000  ................ 
 8049470 00000000 00000000 00000000 00000000  ................ 
 8049480 00000000 00000000 00000000 00000000  ................ 
 8049490 00000000 00000000 00000000 00000000  ................ 
 이런식으로 초기화된 값들이 들어있습니다. 
  
 하지만  int myarray[1000] 이녀석 같은 경우엔 
 초기화 되지 않았기 때문에 bbs 영역에 들어가게 되지요 
 20 .bss          00000018  0804a490  0804a490  00001490  2**2 
                  ALLOC 
  
 bss 영역은 실행 파일에 포함되지 않고 단지 섹션헤더에 
 자신의 사이즈 정보를 가지고 있어서,,, 바이너리가 
 로딩될때 공간만 확보를 하게 되지요.. 
  
  
 이것은 test1의 영역정보 요약입니다.  
 (int myarray[1000]={1,2,3,4}) 
  
 13 .rodata       00000008  080483f8  080483f8  000003f8  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
 14 .data         00000fc0  08049400  08049400  00000400  2**5 
                  CONTENTS, ALLOC, LOAD, DATA 
 -> 보시면  data영역이  뒤에볼 test2보다 크게 잡혀있는게 보입니다. 
 15 .eh_frame     00000004  0804a3c0  0804a3c0  000013c0  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 
 19 .dynamic      000000a0  0804a3f0  0804a3f0  000013f0  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 20 .bss          00000018  0804a490  0804a490  00001490  2**2 
                  ALLOC 
 -> 00001490이게 파일에서 옵셋포인터 인데, 다음 섹션인 stab의 
 옵셋이 00001490 으로 같은것을 볼수 있습니다. 바이너리가 
 로딩되었을때 사이즈만 가지고 있고 실제 파일에서는 아무것도 
 없는거죠..  
 21 .stab         00000750  00000000  00000000  00001490  2**2 
                  CONTENTS, READONLY, DEBUGGING 
 
 
 13 .rodata       00000008  080483f8  080483f8  000003f8  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
 14 .data         0000000c  08049400  08049400  00000400  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 ->  test1과는 달리 초기화된 데이터가 아니라  
   int myarray[1000]; 선언을 했기 때문에 여기 사이즈가 작습니다. 
 15 .eh_frame     00000004  0804940c  0804940c  0000040c  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 
 19 .dynamic      000000a0  0804943c  0804943c  0000043c  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 20 .bss          00000fc0  080494e0  080494e0  000004e0  2**5 
                  ALLOC                   
 21 .stab         00000750  00000000  00000000  000004e0  2**2 
                  CONTENTS, READONLY, DEBUGGING 
 
 
 
                
test1:     file format elf32-i386 
 
Sections: 
Idx Name          Size      VMA       LMA       File off  Algn 
  0 .interp       00000013  080480f4  080480f4  000000f4  2**0 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  1 .note.ABI-tag 00000020  08048108  08048108  00000108  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  2 .hash         0000002c  08048128  08048128  00000128  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  3 .dynsym       00000060  08048154  08048154  00000154  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  4 .dynstr       00000073  080481b4  080481b4  000001b4  2**0 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  5 .gnu.version  0000000c  08048228  08048228  00000228  2**1 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  6 .gnu.version_r 00000020  08048234  08048234  00000234  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  7 .rel.got      00000008  08048254  08048254  00000254  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  8 .rel.plt      00000018  0804825c  0804825c  0000025c  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  9 .init         0000002f  08048274  08048274  00000274  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 10 .plt          00000040  080482a4  080482a4  000002a4  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 11 .text         000000ec  080482f0  080482f0  000002f0  2**4 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 12 .fini         0000001a  080483dc  080483dc  000003dc  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 13 .rodata       00000008  080483f8  080483f8  000003f8  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
 14 .data         00000fc0  08049400  08049400  00000400  2**5 
                  CONTENTS, ALLOC, LOAD, DATA 
 15 .eh_frame     00000004  0804a3c0  0804a3c0  000013c0  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 16 .ctors        00000008  0804a3c4  0804a3c4  000013c4  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 17 .dtors        00000008  0804a3cc  0804a3cc  000013cc  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 18 .got          0000001c  0804a3d4  0804a3d4  000013d4  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 19 .dynamic      000000a0  0804a3f0  0804a3f0  000013f0  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 20 .bss          00000018  0804a490  0804a490  00001490  2**2 
                  ALLOC 
 21 .stab         00000750  00000000  00000000  00001490  2**2 
                  CONTENTS, READONLY, DEBUGGING 
 22 .stabstr      0000134f  00000000  00000000  00001be0  2**0 
                  CONTENTS, READONLY, DEBUGGING 
 23 .comment      0000016e  00000000  00000000  00002f2f  2**0 
                  CONTENTS, READONLY 
 24 .note         00000078  0804a4a8  0804a4a8  0000309d  2**0 
                  CONTENTS, READONLY                   
                   
test2:     file format elf32-i386 
 
Sections: 
Idx Name          Size      VMA       LMA       File off  Algn 
  0 .interp       00000013  080480f4  080480f4  000000f4  2**0 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  1 .note.ABI-tag 00000020  08048108  08048108  00000108  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  2 .hash         0000002c  08048128  08048128  00000128  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  3 .dynsym       00000060  08048154  08048154  00000154  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  4 .dynstr       00000073  080481b4  080481b4  000001b4  2**0 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  5 .gnu.version  0000000c  08048228  08048228  00000228  2**1 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  6 .gnu.version_r 00000020  08048234  08048234  00000234  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  7 .rel.got      00000008  08048254  08048254  00000254  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  8 .rel.plt      00000018  0804825c  0804825c  0000025c  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
  9 .init         0000002f  08048274  08048274  00000274  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 10 .plt          00000040  080482a4  080482a4  000002a4  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 11 .text         000000ec  080482f0  080482f0  000002f0  2**4 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 12 .fini         0000001a  080483dc  080483dc  000003dc  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, CODE 
 13 .rodata       00000008  080483f8  080483f8  000003f8  2**2 
                  CONTENTS, ALLOC, LOAD, READONLY, DATA 
 14 .data         0000000c  08049400  08049400  00000400  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 15 .eh_frame     00000004  0804940c  0804940c  0000040c  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 16 .ctors        00000008  08049410  08049410  00000410  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 17 .dtors        00000008  08049418  08049418  00000418  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 18 .got          0000001c  08049420  08049420  00000420  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 19 .dynamic      000000a0  0804943c  0804943c  0000043c  2**2 
                  CONTENTS, ALLOC, LOAD, DATA 
 20 .bss          00000fc0  080494e0  080494e0  000004e0  2**5 
                  ALLOC 
 21 .stab         00000750  00000000  00000000  000004e0  2**2 
                  CONTENTS, READONLY, DEBUGGING 
 22 .stabstr      0000134f  00000000  00000000  00000c30  2**0 
                  CONTENTS, READONLY, DEBUGGING 
 23 .comment      0000016e  00000000  00000000  00001f7f  2**0 
                  CONTENTS, READONLY 
 24 .note         00000078  0804a4a0  0804a4a0  000020ed  2**0 
                  CONTENTS, READONLY 
 
ps. 더 자세히 공부하고 싶은 분은 아래의 책을 참고하세요 ^^ 
Linkers and Loaders  
John R. Levine  
http://www.wowbook.com/generic/book/info/book_detail.asp?isbn=ISBN1-55860-496-0 
 

출처 : http://linuxkernel.net 게시판


--------------------------------------------------------------------------------

2002/09/19 (16:35) from 211.38.3.65' of 211.38.3.65'  Article Number : 5920  
  정지호  Access : 18 , Lines : 31  
커널에서 double형의 연산이 가능한가요?  
혹시 시도해 보신분 안계세요?
커널 소스에서 double형을 사용한곳을 찾아 보니깐..
드라이버 쪽에서 몇개가 나오고 나머지는 없더군요...
아래 코드의 수행 결과가 이상합니다.

=============================================
double dd = 100.0;
double dd2 = 33.3;
int ii;

if (dd <= 0.0)
printk("dd is zeron");
else
printk("dd is not zeron");

ii = dd/dd2;

printk("res=%dn", ii);
===============================================
수행결가
===============================================
dd is zero  
res=0      


결과를 보면 double형 연산이 안됩니다.

혹시 아시는분 좀 알려 주세요...

감사합니다.




--------------------------------------------------------------------------------

2002/09/19 (16:40) from 211.38.3.65' of 211.38.3.65'  Article Number : 5921  
  정지호  Access : 26 , Lines : 7  
[내용추가]  커널에서 double형의 연산이 가능한가요?  
Makefile에 아래의 내용을 넣어야 컴파일이 되더군요..

LIBGCC := $(shell $(CROSS_COMPILE)gcc --print-libgcc-file-name)

$(LIBGCC)를 적당한 위치에 추가하면 됩니다.




--------------------------------------------------------------------------------

2002/09/20 (02:44) from 63.220.67.67' of 63.220.67.67'  Article Number : 5923  
  이호 (flyduck@linuxkernel.net)  Access : 38 , Lines : 53  
Re: 커널에서 double형의 연산이 가능한가요?  

원칙적으로 커널에서 floating point 연산을 할 수 없습니다. 이것은
규칙입니다. 요새는 모든 CPU에 실수연산을 담당하는 FPU가 있고,
floating point 연산은 이 FPU를 이용합니다. 그리고 이런 연산이
일어날 때마다 FPU register를 조작하게 됩니다. 문제는 커널에서
mode switching이 일어날 때 이 레지스터를 저장하지 않습니다.

따라서 user process에서 실수 연산을 하는 도중에 시스템 콜이나
인터럽트 등으로 커널 모드에 진입을 하고, 커널에서 FPU 레지스터를
바꾼후 그냥 사용자 모드로 되돌아왔다면 사용자 프로그램은 엉뚱한
결과를 낳을 수 있습니다. 눈으로 확인하기는 쉽지 않겠지만요.
그래서 실수 연산과 관련해서는...

- init_module() 처럼 전혀 위험이 없는 곳에 사용하거나 (insmod
프로그램이 실수 연산을 사용하지 않으므로)
- 실수연산후 FPU 레지스터의 값을 복구하거나
- software emulation (FPU를 사용하지 않고 소프트웨어적인 실수계산)

을 해야 합니다. MMX 명령어도 마찬가지죠.



--------------------------------------------------------------------------------

2002/09/23 (17:48) from 211.38.3.65' of 211.38.3.65'  Article Number : 5931  
  정지호  Access : 30 , Lines : 93  
해결...했습니다.  
답변감사합니다.

질문의 코드는 커널 컴파일 할때 -msoft-float 옵션을 켜고
컴파일 할때의 결과 입니다.
그리고 CPU가 FPU가 없는 임베디드 CPU(IBM405GP) 였습니다.
(정보가 정확하지 않았죠 ^^)

원인을 추적하던중 gcc 컴파일러의 컴파일러 소스에 버그인지 아닌지 모르겠는
문제의 코드가 있어 수정을 했습니다.

문제의 코드는 libgcc.a를 만드는 소스(soft-float emulation 코드)
floatlib.c파일의 double형의 equal(not equal)연산을 하는 코드

int
__eqdf2 (double a1, double a2)
{
   //return *(long long *) &a1 == *(long long *) &a2;
   return (__cmpdf2 ((float) a1, (float) a2) != 0);
}

였습니다.

막힌 부분이 원래 코드 입니다.

수정하고 나니...
원래의 코드가 다른 CPU에서는 동작하는지 궁금한데..
여유가 없어서 테스트를 못해본 상태 입니다.
(이상타....혹시 i386계열에서는 문제가 없는거 아닌지..
.. 아~~~ 인텔은 위의 코드를 사용안한다.. 왜~~ FPU가 있으니깐... ^^)
여튼 이렇게 처리하니 문제가 없더군요...

수고하세요..

가상 메모리(Demand paging)

Posted 2002/12/04 13:10
http://vorlon.cwru.edu/~kxm73/출처 : http://vorlon.cwru.edu/~kxm73/

13. 버쳐메모리(Virtual Memory:가상 메모리)

지난 두 장에 이어서 이번에는 메모리에 대한 논의의 후반부인 버쳐메모리를 다루어볼까 합니다. 그동안 소개되었던 수많은 메모리 관리 기법들의 공통분모는 단 한가지로 압축될수 있죠. 바로 그것은 멀티프로그래밍이 가능하도록 최대한 많은 프로세스들이 동시에 메모리에 공존하도록 만드는 것입니다. 이중 버쳐메모리는 일련의 프로세스들이 물리적인 메모리에 할당되지 않아도 실행이 가능하도록 만들어주는 테크닉이며, 가장 큰 장점으로써 물리적 메모리보다 프로그램이 요구하는 메모리가 클지라도 실행이 가능해진다는 점이겠죠. 여기까지는 여러분들이 상식선에서 익히 아시는 부분이라 생각됩니다. 그러나 곧 펼쳐질 버쳐메모리의 해부도를 아는 이들은 그리 많지 않습니다.

버쳐메모리의 의의는 -이거 멋진 말입니다. 맘속에 담아놓고 뽐낼때 씁시다- 메인메모리를 극도로 거대한 동일 어레이(uniform array) 저장매체로 추상화 시킨다는 사실로써 유저의관점에 있어서 물리적 메모리와 논리적 메모리를 완벽하게 분리시켜 버렸다는데에 있죠. 허나, 모든건 장단점이 공존하기 마련이듯, 벼쳐메모리의 오에스 차원에서 구현하기가 먼저 까다롭고 또한 잘못 사용되었을때 성능의 감소는 정말 끔찍하기조차 하죠.

지지난 장에서는 한정된 메모리상에 쏟아지는 프로세스들을 할당하기 위한 기법들로 오버레이(overlay) 또는 다이내믹 로딩(dynamic loading)등이 언급되었었죠. 이들과 버쳐 메모리와는 근본적인 차이점이 존재하게 되는데 후자들이 막말로 자수성가 해야하는 밑바닥 인생들이라면, 버쳐메모리는 오에스라는 엄청난 빽의 지원으로 시작부터 부귀영화를 누리는 귀족이라고 할까요,,,

"On systems which support virtual memory, overlays have virtually disappeared."
아아,,, 기술서가 아닌 문학서를 읽고있다는 착각조차 드는 멋들어진 표현이었습니다.

버쳐메모리를 논하기 위해서는 제일먼저 디멘드 페이징(demand paging)이라는 말부터 살펴볼 필요가 있겠어요. 디멘드 페이징은 버쳐메모리를 구현하기 위한 가장 일반적인 테크닉이죠. 먼저 디멘드 페이징은 전장에서 언급했던 페이징 기법에 전전 장에서 언급했던 스와핑 기법을 적당히 섞은 기법입니다. 여기서 우리는 "혹시 그렇다면 페이징 기법의 쌍벽인 세그멘테이션 기법과 스와핑을 짱뽕시켜도 뭔가 그럴듯하지 않을까!"라고 상상하시는 분이 간혹 계실수 있는데, 정말 예리하시군요,,,맞습니다. 그것또한 버쳐메모리를 구현하기위한 또하나의 테크닉으로써 존재하고 있으며, 그것을 디멘드 세그멘테이션이라고 일컫습니다. 쏟아지는 무관심속에서 장렬하게 쓰러져간 오에스인 OS2가 바로 이렇게 진보적인 메모리 기법을 채용하고 있었죠.

여하튼, 세그멘테이션은 페이징과 달리 그 단위 크기가 불규칙하기에 그 원리가 여러모로 복잡한 관계로 여기서는 디멘드 페이징에 대한 설명만을 하겠습니다. 디멘드 페이징 기법의 원리는 간단합니다. 먼저 우리가 어떤 프로세스를 실행하고자 한다면 간단하게 해당 페이지를 메모리에 스와프 인 시킵니다. 하지만, 여기서 우리는 전체 프로세스에 대응되는 페이지들을 스와프 인 시키는것이 아니라 게으른 스와퍼(lazy swapper)라 불리우는 녀석이 스와핑을 시키는데 해당 페이지가 요구되어지지(demanded) 않을때까지는 절대로 메모리에 스와프 인 시키지 않는 독한 놈입니다. 자, 여기서 우리는 상당히 절묘한 기술용어를 또하나 접하게 되는데 바로 페이지 폴트(page-fault)라는 것이죠. 이경우는 우리의 프로세스군이 엄니의 밥먹으라는 소리에 식탁에 도착했지만 막상 떠먹으려니 주둥이를 방에 두고 왔다는 사실을 깨닫는 순간인것과도 같죠. 전장에서 말씀드렸듯이 페이징 기법은 프로세스의 크기와 상관없이 한개의 프로세스 조차 여러개의 페이지들로 조각조각 나누어버리는 기법인지라, 디멘드 페이징의 경우 프로세스 일부는 오에스로 페이지 폴트 트랩이 보내지기 전까지는 절대로 메모리에 할당되지를 않습니다.

페이지 폴트가 발생한 상황에 대한 대처는 비교적 심플합니다. 제일먼저 페이지 폴트가 발생하면 프로세스로 부터 해당 메모리로의 레퍼런쓰가 옳았는지부터 확인을 하게 되고, 만일 잘못된 레퍼런쓰였다면 프로세스를 종료시켜주게 되죠. 바로 폭탄맞는 경우입니다. 이경우는 프로세스 자체의 오류이기 때문에 오에스도 어쩔수가 없겠죠. 하지만, 만일 제대로된 레퍼런스였고, 해당 페이지가 메모리에 할당이 되지 않은 상태였다면은 빈 프레임(페이지와 프레임은 각각 논리적 메모리와 물리적 메모리의 단위를 일컫죠)을 재빨리찾아내어 해당 페이지를 프레임에 할당하게 되고, 비로서 아까 중간에 멈추었던 인스트럭션을 재실행! 하게 되는것이죠. 위와같은 식으로 메모리에 단 한개의 페이지를 할당하지 않고서도 결국 프로세스를 실행할수 있게 만드는 무서운 기법이 가능해질수도 있을진데, 바로 순수 디멘드 페이징(pure demand paging) 기법입니다.

위에서 비교적 심플한 방법으로 대처한다고는 막상 말했지만, 이것을 현실적으로 구현한다는 측면에서는 아주 골치아픈 첨병이 숨어있어요. 페이지 폴트의 발생시 프로세스는을 재실행 한다고 했는데, 재실행 한다는 뜻은, 바로 이전까지의 자신의 위치, 레지스터 정보등의 상태를 저장해야 한다는 사실을 암시하게 되지요. 또한 여러게의 프로세스들이 연속적으로 페이지 폴트를 쎄려버리면 씨피유,,,정말 뚜껑 열리게 되겠죠. 허나 다행히도 메모리에서는 신비한 현상이 한가지 일어나는데 바로 레퍼런스의 지역성(locality of reference)로써 후반부에서 다시 다루도록 하겠습니다. 결론적으로 그 지역성 덕분에 매번 한순간 다발적으로 페이지 폴트가 일어나는 일은 극히 드물게 됨으로 나름대로 효율성을 기할수가 있게 되었죠.

자, 디멘드 페이징 특유의 상황이 또한가지 연출되는데 바로 페이지 바꿔치기(page replacement)입니다. 이경우는 페이지 폴트가 발생해서 해당 페이지를 막상 할당하려고 보니 빈 프레임이 하나도 없드라,,,고로 현재 할당되어있는 녀석들중 하나와 바꿔치기 해서라도 올려주는 것이죠. 이때 과연 그렇다면 어떤 녀석을 다시 디스크로 끌어내리는 희생양으로 삼을지가 또한 여러개의 알고리즘들로 존재하고 있고, 이들 알고리즘들과는 별도로 페이지 바꿔치기를 함에있어서 참으로 드러진 기법이 등장하게 되는데 바로 더티 비트(dirty bit)의 활용입니다. 자, 한번 생각해 보셔요. 페이지 바꿔치기가 일어나려면 2번의 I/O가 필요하겠죠? 먼저 현재 프레임에 할당된 페이지중 한개의 희생양을 디스크로 끌어내릴때 한번, 그리고 디스크에서 요구된 페이지를 프레임으로 올릴때 한번,,,이렇게 총 두번입니다. 이러한 I/O는 순전히 오버헤드로 작용하여 시스템의 성능을 감소시키게 되겠죠. 하지만, 더티 비트라는 비트를 한개의 프레임마다 달아놓고 만일 해당 프레임의 내용이 바뀌었을경우 1로, 그렇지 않을경우 0으로 세팅한다고 약속을 하게되면,,,한번의 I/O로도 바꿔치기가 가능해집니다. 왜냐하면 더티 비트가 0인 녀석의 경우 디스크로 다시 내려올 이유가 전히어~ 없어지기 때문입니다. 뭣하러 내려오남,,,백업본이 고스란이 이미 디스크에 있는디,,,

페이지 바꿔치기를 위하여 희생양 프레임을 고르는데 사용할수 있는 대표적인 알고리즘들을 이제는 살펴봅시다.

1. FIFO 알고리즘 : 곰곰히 생각하면 FIFO라는 말은 이제 우리에게 익숙해졌을 정도로 도처에 등장하는 감초알고리즘같습니다. 말그대로 이 알고리즘은 프레임에 올라온지 가장 오래된 페이지를 내려버리죠. 이 알고리즘을 구현하기 위해서는 반드시 각 페이지가 올라온 시간을 나름데로 트래킹하고 있어야 할듯 하지만, 그 방법보다는 FIFO큐(Queue)를 구성해서 순서만을 트래킹하는 방법을 사용하게 됩니다. FIFO알고리즘의 성능은 언제나 좋지만은 않지요. 더구나 아주 요상한 현상이 본 알고리즘에서는 발생할수 있는데, 바로 벨로디의 요상함(Belody's anomaly)라는 현상으로써 프레임의 수를 늘렸음에도 오히려 페이지 폴트수가 증가할수도 있는 현상을 나타내주기도 해요. 즉, 램을 올렸는데 이게 어떻게된건지 오히려 가끔씩 디스크가 더욱 버벅거리게 되는격이죠. 본 현상은, 프레임수가 늘어나면 페이지 폴트가 줄어들것이라는 상식적인 실험을 하는 와중에 언제나 그렇지가 않다는 사실을 연구하다 졸지에 발견한겁니다. 상식적인 가정을 의심하는 가운데 빛나는 논문이 여러분을 기다리죠,,,-_-+

2. 최적(Optimal) 알고리즘 : 이것은 앞으로 장시간 동안 사용되지 않을 페이지를 프레임에서 내려버린다는 알고리즘입니다. 말그대로 최적이죠. 하지만 가장큰 단점은 구현이 불가능하다는 것입니다. 미래에 어떤 페이지가 어떻게 안쓰일지를 무슨수로 결정하겄습니까,,,결론적으로 특정 알고리즘의 성능을 측정함에 있어서 이론적 비교의 대상으로 주로 사용됩니다.

3. LRU(Least Recently Used) 알고리즘 : 꽁머리대신 닭대가리라고, 최적알고리즘은 미래의 현상에 대한 판단이 필요하다면, 요 알고리즘은 과거의 행적에 대한 판단을 기준으로 페이지 바꿔치기를 하게 되요. 즉, 가장 오랫동안 침묵을 지키던 페이지를 내려버리죠. 구현을 위해서는 카운터 또는 스택을 이용해서 얼마나 오랫동안 개겼는지를 트래킹하게 됩니다. 최적 알고리즘과 LRU알고리즘에는 벨로디의 요상함 현상이 일어나지 않죠. 허나, 최적은 구현이 불가능하고, LRU는 특유의 오버헤드가 많은데다가 하드웨어의 특별한 지원까지 필요로 하게되는 단점을 가지고 있습니다.

4. LRU Approximation 알고리즘 : LRU가 그래도 좋긴 좋은가 봅니다. 이것의 구현이 까다로우니 흉내라도 내겠다는 알고리즘이죠. 흉내를 내는 여러자기의 알고리즘들이 있습니다만, 그중에 하나 주목할 만한 것이 있는데, 바로 Enhanced Second-Chance 알고리즘입니다. Second-Chance 알고리즘은 기본적으로 FIFO알고리즘의 골격에 큐의 꼬리와 머리를 연결하여 원형 순환을 시킨뒤 각각의 큐옆에 레퍼런스 비트(reference bit)를 달아주는 형태를 하고 있어요. 레퍼런스 비트가 0일경우는 바꿔치기를 하고, 만일 1일경우는 0으로 리셋되는 대신에 다음 프레임으로 넘어가게 되는것이죠. 만일 0으로 리셋된 프레임이 히트되었을경우는 0을 다시 1로 전환시켜주겠죠? 본 알고리즘의 핵심은 말그대로 두번째 기회를 주게 된다는 것이며, 이렇게 한번 넘어가게 된다면 포인터가 전체 큐를 한번 싸그리 돌기전까지는 안전하게 프레임에 남아있게되죠. 본 알고리즘이 최악의 경우 어떤 현상을 나타낼듯한가요? 바로 2번 뺑이치는 FIFO그 이상 이하도 아니겠죠.

그렇다면 Enhanced Second-Chance이란? Ehhanced는 위에 간략하게 설명한 알고리즘에 또하나의 비트를 추가해주게 됩니다. 바로 더티비트! 이죠. 더티비트와 레퍼런스 비트의 조합에는 다음과 같은 경우의 수가 나오게 됩니다.

(레퍼런스비트, 더티비트)
(0,0):최근에 사용되지도 않았을뿐더러 변하지도 않났다네,,,:이거, 당장 방빼야하는 페이지입니다.
(0,1):최근에 사용되지는 않았지만, 내용이 조금 변하긴 했지,,,:썩 빼기 좋은 경우는 아닙니다만(2번의 I/O가 필요하죠) 최악의 경우 이녀석도 방빼게 됩니다.
(1,0):최근에 사용되었지만, 내용은 그대로라네,,,:아마도 곧 다시 사용되겄죠,,,빼기가 참 그렇군요,,,
(1,1):최근에 사용되었을뿐더러 내용까지 변했다네,,,:곧 다시 사용될듯하며, 내리기 전에는 반드시 디스크에 기록을 해야할겁니다.

참고로 우리의 호프 매틴토시의 버쳐메모리 매니져가 위의 알고리즘을 사용하고 있습니다.

그밖엔 카운팅 알고리즘, 페이지 버퍼링 알고리즘등이 책에 소개가 되지만, 핵심은 위에서 소개가 다 된듯하군요. 이것으로 페이지 바꿔치기에 대한 고찰이 끝난것이 아닙니다. 페이지 바꿔치기를 함에있어서 또하나의 기준으로 글로벌(global) 이냐, 아니면 로컬(local)이냐하는 논의가 있죠. 전장에서 페이징을 하기 위해서는 한개의 프로세스조차 조각낸다는 말을 한적이 있죠? 즉 한개의 프로세스가 10조각으로 나위었을때 5조각을 올린다음 페이지 폴트가 발생했다고 가정해봅시다. 만일 이때 5조각중 한조각을 내린뒤 필요한 한조각을 올리게 될경우(이럴경우 해당 프로세스의 조각은 5개로 불변이죠)가 바로 로컬 바꿔치기 알고리즘이고, 다른 프로세스의 페이지를 내린뒤 한개를 올려서 총 6개의 조각을 만들어주는것이 글로벌 바꿔치기 알고리즘이죠. 결과적으로 글로벌 페이지 바꿔치기는 시스템 전체적인 프로세스 처리량을 향상시켜주기는 하지만, 프로세스가 자기 자신에 대한 페이지 폴트율을 도무지 제어하기가 어려워 진다는 단점이 있습니다만 현재 대부분의 버쳐 메모리가 글로벌 바꿔치기 알고리즘을 사용합니다.

가끔씩, 버쳐메모리를 사용할때,,,자신의 하드가 갑자기 미쳐서 쉴새없이 드르르르륵~~~거리며 사람을 화들짝 놀라게 만드는 경우를 혹시 경험해 보셨나요? 그 현상에 대한 정확한 설명을 여기서 드립니다. 바로 트래슁(thrashing)이라 하는 현상이거든요.

오에스는 언제나 자신의 시스템에 대한 효율을 기하기 위하여 씨피유사용량(CPU Utilization)을 점검하곤 하지요. 만일 씨피유사용량이 낮아졌다는 판단이 들경우에는 멀티프로그래밍의 수준을 높여줌으로써 언제나 적정한 사용량을 유지하도록 분위기를 조성해줍니다. 그런데, 버쳐메모리가 인스톨된 시스템에서 어느 프로세스가 실행됨에 있어서 새로운! 페이즈(phase:여기서는 늘 하던 일이 아닌 뭔가 새로운 일을 하려는 경우로 이해하시길)로 전환되게 될경우 프레임에 해당 페이지가 할당되어 있지 않다면 당연히 페이지 폴트가 발생하기 시작하겠죠. 이때 페이지 발생하는 폴트의 결과로 다른 프로세스의 프레임을 점유하게 되면, 다른 프로세스 또한 페이지 폴트율이 증가하게 되고 이런식으로 서로의 페이지 폴트율이 증가하기 시작합니다. 전체적인 페이지 폴트율이 증가하면서 페이징 디바이스의 큐또한 기하급수적으로 쌓여가고 반면에 레디큐는 텅텅,,,비어가죠. 레디큐가 비어간다는 것은 현재 실행중인 프로세스가 줄어든다는 곳이고 이는 과연 무엇을 뜻하게될까요,,,바로 씨피유사용량이 낮아졌다는 뜻입니다. 고로 씨피유는 이러한 상황에서 눈치없이 멀티프로그래밍레벨을 올려버릴테고,,,그 결과는 ? 정말 참담합니다,,,더더욱 낮아지는 레디큐와 자꾸만 올라가는 멀티프로그래밍 레벨,,,고로 결국은 작은 눈한덩이가 눈사태를 일으키듯이 모든 프로세스는 서로 페이징하느라 아무일도 못하게 되죠. 이러한 현상이 바로 트래슁이랍니다. 트래슁을 미연에 방지하는 궁극의 테크닉은 바로 로컬 페이지 바꿔치기 알고리즘이지만, 각 프로세스에게 과연 얼마만큼의 프레임을 지정해줄것인가에 대한 문제또한 만만한것이 아니죠. 물론 시스템의 프로세스 처리량의 감소도 감수해야 합니다.

트래슁을 방지하기 위하여 프로세스당 적정한 프레임수를 결정할수 있는 방법에는 워킹셋전략(working-set strategy)이라는 것이 있지요. 본 기법의 핵심은 프로세스 실행에 있어서 로컬리티 모델(locality model)에 대한 정의인데, 여기서는 이 로컬리티 모델만을 간략하게 다루겠습니다. 로컬리티 모델이란 은 메모리상에서의 정보의 변화를 표시해주는 지도에서 확인이 되는 현상으로 x축을 시간, y축을 메모리 어드레스로 설정하고 플로팅을 했을때 2차원 평면상에 주기적인 패턴이 나타나게 되는 것입니다. 만일 이 평면이 무작위적인 정보가 왔다갔다한다면 전체적으로 흑과 백으로 회색을 디더링한것과 같은 결과가 나오겠지만, 부분 부분 만이 패턴을 그리며 연결된 무늬가 형성된다는 점에서 분명히 메모리 주소값들의 사용은 어떤 패턴을 가지고 있다는 사실을 암시해주죠. 이 사실이 뭐가 그리 중요하냐구요? 바로 이것이 캐쉬메모리가 존재하도록 만든 배경이론입니다. 매번 다른 인스트럭션과 다른 데이터들이 메모리와 씨피유 사이를 관통한다면 캐쉬메모리는 그 존재의미가 전혀 없어져 버리죠.

이상으로 버쳐메모리에 대한 이론적인 배경을 살펴보았습니다. 메모리에 대한 논의를 완전히 끝내기 전에 한가지 지난번 다루지 못한 부분이 있기에 잠시 언급을 할까 해요. 바로 리엔트랑코드(reentrant code)입니다. 리엔트랑코드는 앞장의 페이징과 세그멘테이션 기법을 논의하면서 특정 페이지와 세그멘트를 공유할때 등장하는 말이죠. 세그멘테이션 에서 에디터의 예를 들면서 에디터 세그먼트와 데이터 세그먼트로 나눌경우 두사람이 각자의 데이터 세그먼트를 메모리에 할당하되, 에디터 세그먼트는 메모리에서 공유가 가능해진다고 했었죠. 이때 에디터 세그먼트가 공유되기 위해서는 바로 리엔트랑코드로 만들어져야 합니다. 리엔트랑 코드는 간단하게 말한다면 자신을 변화시키지 않는(non-self-modifying) 코드입니다. 즉 실행되는 동안은 자신을 절대로 변화시키지 않죠. 이것은 아주 교묘하게도 예전에 말씀드렸던 데이터의 싱크(Sync:Syncronization)문제와도 연관이 되어있는 있는문제로, 최근에 오에스가 고차원적으로 발전하며 자주 등장하는 말입니다. 리엔트랑코드,,,그냥 우리와 아무 상관없는 이야기로 들리겠지만, 여러분 애플의 카본(Carbon)의 정체가 무엇인줄 아십니까? 바로 애플의 툴박스 루틴들중 리엔트랑코드만을 골라내거나 또는 리엔트랑코드로 재작성된 코드들의 묶음입니다.

이것으로 메모리에 대한 기나긴 논의를 마치게 되겠군요. 전혀 아쉽지가 않은 이유를 통 모르겄네,,,-_-
이제는 제가 기획한 오에스 개론의 끝이 보이는군요. 이제남은 것은 파일, 쓰레드, 그리고 통신의 기초라 할수 있는 OSI 7Layer Protocol을 한장내외로 아주 간략하게 설명한뒤 강의를 마칠까 합니다. 그럼 또 봐유,,,

-duffer 경준


KB Article ID: K001509



--------------------------------------------------------------------------------


이 내용이 적용되는 제품:

- Microsoft Win32 Device Driver Kit (DDK) for Windows NT, versions 3.1, 3.5, 3.51, 4.0
- Microsoft Win32 Device Driver Kit (DDK) Windows 2000

[요 약]

Windows NT 와 Windows 2000 에서 커널 모드 드라이버는 사용자 모드 응용 프로그램으로 콜백(Callback) 할 수 없습니다. 이것은 의도적으로 설계된 것입니다. 비동기적인 이벤트에 대해서 응용 프로그램에게 알리기 위한 드라이버를 위하여, 응용 프로그램은 이벤트가 발생할 때 마다 드라이버가 해당 요구(Request) 를 완료할 수 있도록 모든 시간에 대해서 드라이버에 걸려 있는 입출력 요구(I/O Request) 를 유지할 필요가 있습니다. 본 문서는 응용 프로그램과 드라이버가 비동기적인 알림을 수행하기 위해서 사용할 수 있는 전형적인 방법에 대해서 다루고 있습니다.

[추가 정보]

응용 프로그램

응용 프로그램은 전용 입력 스레드를 가질 수 있습니다. 해당 스레드는 입출력 요구(I/O Request) 를 보내고 응답을 대기하는 루프(Loop)를 돌게 됩니다. 드라이버가 열려 있고 핸들인 hDevice 를 가지고 있다면 해당 루프(Loop)는 다음과 같을 수 있습니다.

while (!ApplicationExiting) {

returnval = DeviceIoControl (hDevice, dwIoControlCode,
lpvInBuffer, cbInBuffer, lpvOutBuffer,
cbOutBuffer, lpcbBytesReturned, lpoOverlapped);
if (!returnval && (GetLastError() == ERROR_IO_PENDING)) {
WaitForSingleObject (hEvent, INFINITE) // hEvent is located in
overlapped structure as well
... // Code to do action
ResetEvent (hEvent)
}
{ ... // Code to handle other situations }
}

BOOL 형인 ApplicationExiting() 는 이벤트에 대한 검사를 중지하도록 하는 루프(Loop)에 대한 조건을 나타내고 있습니다. 응용 프로그램의 메인 스레드는 종료할 시간이 되었을 때 이 BOOL 을 TRUE 로 설정할 수 있습니다. I/O 제어 코드 dwIoControlCode()는 드라이버에 의해서 정의됩니다.

위의 DeviceIoControl 호출은 요구(Request)가 지연(Pending)되고 있는 동안 다른 응용 프로그램 스레드가 이 요구(Request)를 다른 드라이버로 보내는 것을 지속할 수 있도록 하기 위해서 비동기적으로 만들어져야 합니다. DeviceIoControl 호출의 오버랩 된 구조 내에서 초기화되고 배치된 이벤트는 요구(Request)의 완료로 인해서 이 스레드를 동기화 하기 위하여 사용될 수 있습니다. 그러한 이벤트가 만족되면 이러한 스레드는 다른 응용 프로그램의 스레드에게 해당 이벤트가 시그널(Signal) 되었음을 알릴 수 있습니다. 오버랩 된 구조가 지정되지 않았다면 이 요구(Request)가 해당 드라이버내에서 처리되는 동안 다른 모든 스레드는 블록(Block)화 될 것입니다. 다른 스레드는 동기적인(Synchronous) DeviceIoControl 이 완료될 때 까지 릴리즈 되지 않을 것입니다.

해당 드라이버가 비동기적인 이벤트 알림 내에서 전송을 위한 Read 요구(Request)를 사용한다면 사용자 모드(User-Mode) 스레드는 DeviceIoControl() 을 대신하여 ReadFile() 또는 ReadFileEx() 을 사용할 수 있습니다.

드라이버

해당 드라이버는 이벤트가 일어나기 전까지는 입출력 요구(I/O Request) 를 완료하지 못하게 됩니다. 해당 드라이버가 입출력 요구(I/O Request)를 받았을 때 이벤트가 발생했고 이벤트가 응용 프로그램으로 전송되기 위해서 대기하고 있다면 그 드라이버는 Dispatch 루틴(Routine) 내에서 해당 요구(Request)를 완료할 수 있습니다. 대기하고 있는 이벤트가 없다고 보고되면 그 드라이버는 다음의 단계들을 수행합니다:

1. IoMarkIrpPending()을 사용하여 Irp pending 을 표시합니다.

2. IoSetCancelRoutine()을 사용하여 Irp 에 대한 취소 루틴(Routine)을 설정합니다.

3. Irp 를 저장소(예를 들어서 Queue)에 넣습니다.

4. Dispatch 루틴(Routine)으로부터 STATUS_PENDING 을 반환합니다.

나중에 이벤트가 발생하였을 때 해당 드라이버는 그것의 Deferred Procedure Call (DPC) 루틴(Routine)으로부터의 지연 요구(Request)를 완료할 수 있습니다. Irp 가 완료되기 이전에 해당 드라이버는 IoSetCancelRoutine 을 이용하여 취소 루틴(Routine) 주소를 NULL로 설정해야 합니다.


Polling a Device

Posted 2002/12/02 00:22
A device driver should avoid polling its device unless absolutely necessary and should never use a whole timeslice polling. Polling a device is an expensive operation that makes any operating system compute-bound within the polling driver. A device driver that does much polling interferes with I/O operations on other devices and can make the system slow and unresponsive to users.

Recently developed devices, which are as technologically advanced as the processors on which Windows NT®/Windows® 2000 is designed to run, seldom require a driver to polls its device to ensure that the device is ready to start an I/O operation or that an operation is complete.

Nevertheless, some devices still in use were designed to work with old processors, which had narrow data buses, slow clock rates, and single-user, single-tasking operating systems that did synchronous I/O. Such devices might require polling or some other means of waiting for the device to update its registers, particularly for Windows NT/Windows 2000, which is designed to do asynchronous I/O on new processors with wide data buses and fast clock rates.

Although it might seem logical to solve a slow-device problem by coding a simple loop that increments a counter, thereby "wasting" a minimum interval while the device updates registers, such a driver is unlikely to be portable across Windows NT/Windows 2000 platforms. The loop counter maximum would require customization for each Windows NT/Windows 2000 platform. Furthermore, if the driver is compiled with a good optimizing compiler, the compiler might remove the driver's counter variable and the loop(s) where it is incremented.

Follow this implementation guideline if the driver must stall while the device hardware updates state:

A driver can call KeStallExecutionProcessor before it reads the device register(s). The driver should minimize the interval it stalls and should, in general, specify a stall interval no longer than 50 microseconds.

The granularity of a KeStallExecutionProcessor interval is 1 microsecond.

If the device frequently requires more than 50 microseconds to update state, consider setting up a device-dedicated thread in the driver.

Built on Wednesday, June 28, 2000